Repository: sksalahuddin2828/C_Programming Branch: main Commit: 7c28905ddbca Files: 132 Total size: 3.5 MB Directory structure: gitextract_msw6v1wo/ ├── Asdl.c ├── Asm_Trampoline.S ├── Assemble.c ├── Ast.c ├── Ast_Opt.c ├── Ast_Unparse.c ├── BltinModule.c ├── Bootstrap_Hash.c ├── ByteCodes.c ├── CeVal.c ├── Ceval_Gil.c ├── Ceval_Macros.h ├── Clinic/ │ ├── Python-tokenize.c.h │ ├── _warnings.c.h │ ├── bltinmodule.c.h │ ├── context.c.h │ ├── import.c.h │ ├── instrumentation.c.h │ ├── marshal.c.h │ ├── sysmodule.c.h │ └── traceback.c.h ├── CodeCS.c ├── Compile.c ├── Condvar.h ├── Context.c ├── Dtoa.c ├── Dup2.c ├── Dynamic_Annotations.c ├── Dynload_Hpux.c ├── Dynload_Shlib.c ├── Dynload_Stub.c ├── Dynload_Win.c ├── Emscripten_Signal.c ├── Errors.c ├── Fileutils.c ├── Flowgraph.c ├── Formatter_Unicode.c ├── Frame.c ├── Frozen.c ├── FrozenMain.c ├── Future.c ├── Game/ │ ├── CMakeLists.txt │ ├── graphics.asm │ ├── linked_list.asm │ ├── main.asm │ ├── memory.asm │ └── utils.asm ├── Game I/ │ ├── CMakeLists.txt │ ├── c_key_event.h │ ├── c_list.c │ ├── c_list.h │ ├── c_rectangle.c │ ├── c_rectangle.h │ ├── c_result.h │ ├── c_vector2.c │ ├── c_vector2.h │ ├── c_window.c │ ├── c_window.h │ └── main.c ├── Game II/ │ ├── CMakeLists.txt │ ├── colour.cpp │ ├── colour.h │ ├── entity.cpp │ ├── entity.h │ ├── key_event.h │ ├── main.cpp │ ├── rectangle.cpp │ ├── rectangle.h │ ├── vector2.cpp │ ├── vector2.h │ ├── window.cpp │ └── window.h ├── GeTargs.c ├── Generated_Cases.c.h ├── GetArgs.c ├── GetCompiler.c ├── GetCopyRight.c ├── GetCopyright.c ├── GetOpt.c ├── GetPlatForm.c ├── GetVersion.c ├── Get_Compiler.c ├── Get_Opt.c ├── Get_Plat_Form.c ├── Getversion.c ├── Hamt.c ├── HashTable.c ├── ImPort.c ├── ImPortdl.c ├── ImPortdl.h ├── InTrinSics.c ├── InitConfig.c ├── InstruMenTation.c ├── InstruMentation.c ├── Legacy_Tracing.c ├── MakeOpCodeTargets.py ├── MarShal.c ├── ModSupport.c ├── MySnPrintf.c ├── MyStrtoul.c ├── OpCode_MetaData.h ├── OpCode_Targets.h ├── OptiMizer.c ├── PathConfig.c ├── Perf_Trampoline.c ├── PreConfig.c ├── PyArena.c ├── PyCtype.c ├── PyFpc.c ├── PyHash.c ├── PyLifeCycle.c ├── PyMath.c ├── PyState.c ├── PyStrcmp.c ├── PyStrhex.c ├── PyStrtod.c ├── PyTime.c ├── Python-AST.c ├── Python-Tokenize.c ├── PythonRun.c ├── Specialize.c ├── Stdlib_Module_Names.h ├── StrucMember.c ├── Suggestions.c ├── SyMTable.c ├── SySModule.c ├── Thread.c ├── Thread_NT.h ├── Thread_Pthread.h ├── Thread_Pthread_Dtubs.h ├── TraceBack.c └── TraceMalloc.c ================================================ FILE CONTENTS ================================================ ================================================ FILE: Asdl.c ================================================ #include "Python.h" #include "pycore_asdl.h" GENERATE_ASDL_SEQ_CONSTRUCTOR(generic, void*); GENERATE_ASDL_SEQ_CONSTRUCTOR(identifier, PyObject*); GENERATE_ASDL_SEQ_CONSTRUCTOR(int, int); ================================================ FILE: Asm_Trampoline.S ================================================ .text .globl _Py_trampoline_func_start # The following assembly is equivalent to: # PyObject * # trampoline(PyThreadState *ts, _PyInterpreterFrame *f, # int throwflag, py_evaluator evaluator) # { # return evaluator(ts, f, throwflag); # } _Py_trampoline_func_start: #ifdef __x86_64__ sub $8, %rsp call *%rcx add $8, %rsp ret #endif // __x86_64__ #if defined(__aarch64__) && defined(__AARCH64EL__) && !defined(__ILP32__) // ARM64 little endian, 64bit ABI // generate with aarch64-linux-gnu-gcc 12.1 stp x29, x30, [sp, -16]! mov x29, sp blr x3 ldp x29, x30, [sp], 16 ret #endif .globl _Py_trampoline_func_end _Py_trampoline_func_end: .section .note.GNU-stack,"",@progbits ================================================ FILE: Assemble.c ================================================ #include #include "Python.h" #include "pycore_code.h" // write_location_entry_start() #include "pycore_compile.h" #include "pycore_opcode.h" // _PyOpcode_Caches[] and opcode category macros #define DEFAULT_CODE_SIZE 128 #define DEFAULT_LNOTAB_SIZE 16 #define DEFAULT_CNOTAB_SIZE 32 #undef SUCCESS #undef ERROR #define SUCCESS 0 #define ERROR -1 #define RETURN_IF_ERROR(X) \ if ((X) == -1) { \ return ERROR; \ } typedef _PyCompilerSrcLocation location; typedef _PyCompile_Instruction instruction; typedef _PyCompile_InstructionSequence instr_sequence; static inline bool same_location(location a, location b) { return a.lineno == b.lineno && a.end_lineno == b.end_lineno && a.col_offset == b.col_offset && a.end_col_offset == b.end_col_offset; } struct assembler { PyObject *a_bytecode; /* bytes containing bytecode */ int a_offset; /* offset into bytecode */ PyObject *a_except_table; /* bytes containing exception table */ int a_except_table_off; /* offset into exception table */ /* Location Info */ int a_lineno; /* lineno of last emitted instruction */ PyObject* a_linetable; /* bytes containing location info */ int a_location_off; /* offset of last written location info frame */ }; static int assemble_init(struct assembler *a, int firstlineno) { memset(a, 0, sizeof(struct assembler)); a->a_lineno = firstlineno; a->a_linetable = NULL; a->a_location_off = 0; a->a_except_table = NULL; a->a_bytecode = PyBytes_FromStringAndSize(NULL, DEFAULT_CODE_SIZE); if (a->a_bytecode == NULL) { goto error; } a->a_linetable = PyBytes_FromStringAndSize(NULL, DEFAULT_CNOTAB_SIZE); if (a->a_linetable == NULL) { goto error; } a->a_except_table = PyBytes_FromStringAndSize(NULL, DEFAULT_LNOTAB_SIZE); if (a->a_except_table == NULL) { goto error; } return SUCCESS; error: Py_XDECREF(a->a_bytecode); Py_XDECREF(a->a_linetable); Py_XDECREF(a->a_except_table); return ERROR; } static void assemble_free(struct assembler *a) { Py_XDECREF(a->a_bytecode); Py_XDECREF(a->a_linetable); Py_XDECREF(a->a_except_table); } static inline void write_except_byte(struct assembler *a, int byte) { unsigned char *p = (unsigned char *) PyBytes_AS_STRING(a->a_except_table); p[a->a_except_table_off++] = byte; } #define CONTINUATION_BIT 64 static void assemble_emit_exception_table_item(struct assembler *a, int value, int msb) { assert ((msb | 128) == 128); assert(value >= 0 && value < (1 << 30)); if (value >= 1 << 24) { write_except_byte(a, (value >> 24) | CONTINUATION_BIT | msb); msb = 0; } if (value >= 1 << 18) { write_except_byte(a, ((value >> 18)&0x3f) | CONTINUATION_BIT | msb); msb = 0; } if (value >= 1 << 12) { write_except_byte(a, ((value >> 12)&0x3f) | CONTINUATION_BIT | msb); msb = 0; } if (value >= 1 << 6) { write_except_byte(a, ((value >> 6)&0x3f) | CONTINUATION_BIT | msb); msb = 0; } write_except_byte(a, (value&0x3f) | msb); } /* See Objects/exception_handling_notes.txt for details of layout */ #define MAX_SIZE_OF_ENTRY 20 static int assemble_emit_exception_table_entry(struct assembler *a, int start, int end, _PyCompile_ExceptHandlerInfo *handler) { Py_ssize_t len = PyBytes_GET_SIZE(a->a_except_table); if (a->a_except_table_off + MAX_SIZE_OF_ENTRY >= len) { RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, len * 2)); } int size = end-start; assert(end > start); int target = handler->h_offset; int depth = handler->h_startdepth - 1; if (handler->h_preserve_lasti > 0) { depth -= 1; } assert(depth >= 0); int depth_lasti = (depth<<1) | handler->h_preserve_lasti; assemble_emit_exception_table_item(a, start, (1<<7)); assemble_emit_exception_table_item(a, size, 0); assemble_emit_exception_table_item(a, target, 0); assemble_emit_exception_table_item(a, depth_lasti, 0); return SUCCESS; } static int assemble_exception_table(struct assembler *a, instr_sequence *instrs) { int ioffset = 0; _PyCompile_ExceptHandlerInfo handler; handler.h_offset = -1; handler.h_startdepth = -1; handler.h_preserve_lasti = -1; int start = -1; for (int i = 0; i < instrs->s_used; i++) { instruction *instr = &instrs->s_instrs[i]; if (instr->i_except_handler_info.h_offset != handler.h_offset) { if (handler.h_offset >= 0) { RETURN_IF_ERROR( assemble_emit_exception_table_entry(a, start, ioffset, &handler)); } start = ioffset; handler = instr->i_except_handler_info; } ioffset += _PyCompile_InstrSize(instr->i_opcode, instr->i_oparg); } if (handler.h_offset >= 0) { RETURN_IF_ERROR(assemble_emit_exception_table_entry(a, start, ioffset, &handler)); } return SUCCESS; } /* Code location emitting code. See locations.md for a description of the format. */ #define MSB 0x80 static void write_location_byte(struct assembler* a, int val) { PyBytes_AS_STRING(a->a_linetable)[a->a_location_off] = val&255; a->a_location_off++; } static uint8_t * location_pointer(struct assembler* a) { return (uint8_t *)PyBytes_AS_STRING(a->a_linetable) + a->a_location_off; } static void write_location_first_byte(struct assembler* a, int code, int length) { a->a_location_off += write_location_entry_start( location_pointer(a), code, length); } static void write_location_varint(struct assembler* a, unsigned int val) { uint8_t *ptr = location_pointer(a); a->a_location_off += write_varint(ptr, val); } static void write_location_signed_varint(struct assembler* a, int val) { uint8_t *ptr = location_pointer(a); a->a_location_off += write_signed_varint(ptr, val); } static void write_location_info_short_form(struct assembler* a, int length, int column, int end_column) { assert(length > 0 && length <= 8); int column_low_bits = column & 7; int column_group = column >> 3; assert(column < 80); assert(end_column >= column); assert(end_column - column < 16); write_location_first_byte(a, PY_CODE_LOCATION_INFO_SHORT0 + column_group, length); write_location_byte(a, (column_low_bits << 4) | (end_column - column)); } static void write_location_info_oneline_form(struct assembler* a, int length, int line_delta, int column, int end_column) { assert(length > 0 && length <= 8); assert(line_delta >= 0 && line_delta < 3); assert(column < 128); assert(end_column < 128); write_location_first_byte(a, PY_CODE_LOCATION_INFO_ONE_LINE0 + line_delta, length); write_location_byte(a, column); write_location_byte(a, end_column); } static void write_location_info_long_form(struct assembler* a, location loc, int length) { assert(length > 0 && length <= 8); write_location_first_byte(a, PY_CODE_LOCATION_INFO_LONG, length); write_location_signed_varint(a, loc.lineno - a->a_lineno); assert(loc.end_lineno >= loc.lineno); write_location_varint(a, loc.end_lineno - loc.lineno); write_location_varint(a, loc.col_offset + 1); write_location_varint(a, loc.end_col_offset + 1); } static void write_location_info_none(struct assembler* a, int length) { write_location_first_byte(a, PY_CODE_LOCATION_INFO_NONE, length); } static void write_location_info_no_column(struct assembler* a, int length, int line_delta) { write_location_first_byte(a, PY_CODE_LOCATION_INFO_NO_COLUMNS, length); write_location_signed_varint(a, line_delta); } #define THEORETICAL_MAX_ENTRY_SIZE 25 /* 1 + 6 + 6 + 6 + 6 */ static int write_location_info_entry(struct assembler* a, location loc, int isize) { Py_ssize_t len = PyBytes_GET_SIZE(a->a_linetable); if (a->a_location_off + THEORETICAL_MAX_ENTRY_SIZE >= len) { assert(len > THEORETICAL_MAX_ENTRY_SIZE); RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, len*2)); } if (loc.lineno < 0) { write_location_info_none(a, isize); return SUCCESS; } int line_delta = loc.lineno - a->a_lineno; int column = loc.col_offset; int end_column = loc.end_col_offset; assert(column >= -1); assert(end_column >= -1); if (column < 0 || end_column < 0) { if (loc.end_lineno == loc.lineno || loc.end_lineno == -1) { write_location_info_no_column(a, isize, line_delta); a->a_lineno = loc.lineno; return SUCCESS; } } else if (loc.end_lineno == loc.lineno) { if (line_delta == 0 && column < 80 && end_column - column < 16 && end_column >= column) { write_location_info_short_form(a, isize, column, end_column); return SUCCESS; } if (line_delta >= 0 && line_delta < 3 && column < 128 && end_column < 128) { write_location_info_oneline_form(a, isize, line_delta, column, end_column); a->a_lineno = loc.lineno; return SUCCESS; } } write_location_info_long_form(a, loc, isize); a->a_lineno = loc.lineno; return SUCCESS; } static int assemble_emit_location(struct assembler* a, location loc, int isize) { if (isize == 0) { return SUCCESS; } while (isize > 8) { RETURN_IF_ERROR(write_location_info_entry(a, loc, 8)); isize -= 8; } return write_location_info_entry(a, loc, isize); } static int assemble_location_info(struct assembler *a, instr_sequence *instrs, int firstlineno) { a->a_lineno = firstlineno; location loc = NO_LOCATION; int size = 0; for (int i = 0; i < instrs->s_used; i++) { instruction *instr = &instrs->s_instrs[i]; if (!same_location(loc, instr->i_loc)) { RETURN_IF_ERROR(assemble_emit_location(a, loc, size)); loc = instr->i_loc; size = 0; } size += _PyCompile_InstrSize(instr->i_opcode, instr->i_oparg); } RETURN_IF_ERROR(assemble_emit_location(a, loc, size)); return SUCCESS; } static void write_instr(_Py_CODEUNIT *codestr, instruction *instr, int ilen) { int opcode = instr->i_opcode; assert(!IS_PSEUDO_OPCODE(opcode)); int oparg = instr->i_oparg; assert(HAS_ARG(opcode) || oparg == 0); int caches = _PyOpcode_Caches[opcode]; switch (ilen - caches) { case 4: codestr->op.code = EXTENDED_ARG; codestr->op.arg = (oparg >> 24) & 0xFF; codestr++; /* fall through */ case 3: codestr->op.code = EXTENDED_ARG; codestr->op.arg = (oparg >> 16) & 0xFF; codestr++; /* fall through */ case 2: codestr->op.code = EXTENDED_ARG; codestr->op.arg = (oparg >> 8) & 0xFF; codestr++; /* fall through */ case 1: codestr->op.code = opcode; codestr->op.arg = oparg & 0xFF; codestr++; break; default: Py_UNREACHABLE(); } while (caches--) { codestr->op.code = CACHE; codestr->op.arg = 0; codestr++; } } /* assemble_emit_instr() Extend the bytecode with a new instruction. Update lnotab if necessary. */ static int assemble_emit_instr(struct assembler *a, instruction *instr) { Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode); _Py_CODEUNIT *code; int size = _PyCompile_InstrSize(instr->i_opcode, instr->i_oparg); if (a->a_offset + size >= len / (int)sizeof(_Py_CODEUNIT)) { if (len > PY_SSIZE_T_MAX / 2) { return ERROR; } RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, len * 2)); } code = (_Py_CODEUNIT *)PyBytes_AS_STRING(a->a_bytecode) + a->a_offset; a->a_offset += size; write_instr(code, instr, size); return SUCCESS; } static int assemble_emit(struct assembler *a, instr_sequence *instrs, int first_lineno, PyObject *const_cache) { RETURN_IF_ERROR(assemble_init(a, first_lineno)); for (int i = 0; i < instrs->s_used; i++) { instruction *instr = &instrs->s_instrs[i]; RETURN_IF_ERROR(assemble_emit_instr(a, instr)); } RETURN_IF_ERROR(assemble_location_info(a, instrs, a->a_lineno)); RETURN_IF_ERROR(assemble_exception_table(a, instrs)); RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, a->a_except_table_off)); RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_except_table)); RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, a->a_location_off)); RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_linetable)); RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, a->a_offset * sizeof(_Py_CODEUNIT))); RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_bytecode)); return SUCCESS; } static PyObject * dict_keys_inorder(PyObject *dict, Py_ssize_t offset) { PyObject *tuple, *k, *v; Py_ssize_t i, pos = 0, size = PyDict_GET_SIZE(dict); tuple = PyTuple_New(size); if (tuple == NULL) return NULL; while (PyDict_Next(dict, &pos, &k, &v)) { i = PyLong_AS_LONG(v); assert((i - offset) < size); assert((i - offset) >= 0); PyTuple_SET_ITEM(tuple, i - offset, Py_NewRef(k)); } return tuple; } // This is in codeobject.c. extern void _Py_set_localsplus_info(int, PyObject *, unsigned char, PyObject *, PyObject *); static void compute_localsplus_info(_PyCompile_CodeUnitMetadata *umd, int nlocalsplus, PyObject *names, PyObject *kinds) { PyObject *k, *v; Py_ssize_t pos = 0; while (PyDict_Next(umd->u_varnames, &pos, &k, &v)) { int offset = (int)PyLong_AS_LONG(v); assert(offset >= 0); assert(offset < nlocalsplus); // For now we do not distinguish arg kinds. _PyLocals_Kind kind = CO_FAST_LOCAL; if (PyDict_Contains(umd->u_fasthidden, k)) { kind |= CO_FAST_HIDDEN; } if (PyDict_GetItem(umd->u_cellvars, k) != NULL) { kind |= CO_FAST_CELL; } _Py_set_localsplus_info(offset, k, kind, names, kinds); } int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); // This counter mirrors the fix done in fix_cell_offsets(). int numdropped = 0; pos = 0; while (PyDict_Next(umd->u_cellvars, &pos, &k, &v)) { if (PyDict_GetItem(umd->u_varnames, k) != NULL) { // Skip cells that are already covered by locals. numdropped += 1; continue; } int offset = (int)PyLong_AS_LONG(v); assert(offset >= 0); offset += nlocals - numdropped; assert(offset < nlocalsplus); _Py_set_localsplus_info(offset, k, CO_FAST_CELL, names, kinds); } pos = 0; while (PyDict_Next(umd->u_freevars, &pos, &k, &v)) { int offset = (int)PyLong_AS_LONG(v); assert(offset >= 0); offset += nlocals - numdropped; assert(offset < nlocalsplus); _Py_set_localsplus_info(offset, k, CO_FAST_FREE, names, kinds); } } static PyCodeObject * makecode(_PyCompile_CodeUnitMetadata *umd, struct assembler *a, PyObject *const_cache, PyObject *constslist, int maxdepth, int nlocalsplus, int code_flags, PyObject *filename) { PyCodeObject *co = NULL; PyObject *names = NULL; PyObject *consts = NULL; PyObject *localsplusnames = NULL; PyObject *localspluskinds = NULL; names = dict_keys_inorder(umd->u_names, 0); if (!names) { goto error; } if (_PyCompile_ConstCacheMergeOne(const_cache, &names) < 0) { goto error; } consts = PyList_AsTuple(constslist); /* PyCode_New requires a tuple */ if (consts == NULL) { goto error; } if (_PyCompile_ConstCacheMergeOne(const_cache, &consts) < 0) { goto error; } assert(umd->u_posonlyargcount < INT_MAX); assert(umd->u_argcount < INT_MAX); assert(umd->u_kwonlyargcount < INT_MAX); int posonlyargcount = (int)umd->u_posonlyargcount; int posorkwargcount = (int)umd->u_argcount; assert(INT_MAX - posonlyargcount - posorkwargcount > 0); int kwonlyargcount = (int)umd->u_kwonlyargcount; localsplusnames = PyTuple_New(nlocalsplus); if (localsplusnames == NULL) { goto error; } localspluskinds = PyBytes_FromStringAndSize(NULL, nlocalsplus); if (localspluskinds == NULL) { goto error; } compute_localsplus_info(umd, nlocalsplus, localsplusnames, localspluskinds); struct _PyCodeConstructor con = { .filename = filename, .name = umd->u_name, .qualname = umd->u_qualname ? umd->u_qualname : umd->u_name, .flags = code_flags, .code = a->a_bytecode, .firstlineno = umd->u_firstlineno, .linetable = a->a_linetable, .consts = consts, .names = names, .localsplusnames = localsplusnames, .localspluskinds = localspluskinds, .argcount = posonlyargcount + posorkwargcount, .posonlyargcount = posonlyargcount, .kwonlyargcount = kwonlyargcount, .stacksize = maxdepth, .exceptiontable = a->a_except_table, }; if (_PyCode_Validate(&con) < 0) { goto error; } if (_PyCompile_ConstCacheMergeOne(const_cache, &localsplusnames) < 0) { goto error; } con.localsplusnames = localsplusnames; co = _PyCode_New(&con); if (co == NULL) { goto error; } error: Py_XDECREF(names); Py_XDECREF(consts); Py_XDECREF(localsplusnames); Py_XDECREF(localspluskinds); return co; } PyCodeObject * _PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *umd, PyObject *const_cache, PyObject *consts, int maxdepth, instr_sequence *instrs, int nlocalsplus, int code_flags, PyObject *filename) { PyCodeObject *co = NULL; struct assembler a; int res = assemble_emit(&a, instrs, umd->u_firstlineno, const_cache); if (res == SUCCESS) { co = makecode(umd, &a, const_cache, consts, maxdepth, nlocalsplus, code_flags, filename); } assemble_free(&a); return co; } ================================================ FILE: Ast.c ================================================ /* * This file exposes PyAST_Validate interface to check the integrity * of the given abstract syntax tree (potentially constructed manually). */ #include "Python.h" #include "pycore_ast.h" // asdl_stmt_seq #include "pycore_pystate.h" // _PyThreadState_GET() #include #include struct validator { int recursion_depth; /* current recursion depth */ int recursion_limit; /* recursion limit */ }; static int validate_stmts(struct validator *, asdl_stmt_seq *); static int validate_exprs(struct validator *, asdl_expr_seq *, expr_context_ty, int); static int validate_patterns(struct validator *, asdl_pattern_seq *, int); static int validate_type_params(struct validator *, asdl_type_param_seq *); static int _validate_nonempty_seq(asdl_seq *, const char *, const char *); static int validate_stmt(struct validator *, stmt_ty); static int validate_expr(struct validator *, expr_ty, expr_context_ty); static int validate_pattern(struct validator *, pattern_ty, int); static int validate_typeparam(struct validator *, type_param_ty); #define VALIDATE_POSITIONS(node) \ if (node->lineno > node->end_lineno) { \ PyErr_Format(PyExc_ValueError, \ "AST node line range (%d, %d) is not valid", \ node->lineno, node->end_lineno); \ return 0; \ } \ if ((node->lineno < 0 && node->end_lineno != node->lineno) || \ (node->col_offset < 0 && node->col_offset != node->end_col_offset)) { \ PyErr_Format(PyExc_ValueError, \ "AST node column range (%d, %d) for line range (%d, %d) is not valid", \ node->col_offset, node->end_col_offset, node->lineno, node->end_lineno); \ return 0; \ } \ if (node->lineno == node->end_lineno && node->col_offset > node->end_col_offset) { \ PyErr_Format(PyExc_ValueError, \ "line %d, column %d-%d is not a valid range", \ node->lineno, node->col_offset, node->end_col_offset); \ return 0; \ } static int validate_name(PyObject *name) { assert(!PyErr_Occurred()); assert(PyUnicode_Check(name)); static const char * const forbidden[] = { "None", "True", "False", NULL }; for (int i = 0; forbidden[i] != NULL; i++) { if (_PyUnicode_EqualToASCIIString(name, forbidden[i])) { PyErr_Format(PyExc_ValueError, "identifier field can't represent '%s' constant", forbidden[i]); return 0; } } return 1; } static int validate_comprehension(struct validator *state, asdl_comprehension_seq *gens) { assert(!PyErr_Occurred()); if (!asdl_seq_LEN(gens)) { PyErr_SetString(PyExc_ValueError, "comprehension with no generators"); return 0; } for (Py_ssize_t i = 0; i < asdl_seq_LEN(gens); i++) { comprehension_ty comp = asdl_seq_GET(gens, i); if (!validate_expr(state, comp->target, Store) || !validate_expr(state, comp->iter, Load) || !validate_exprs(state, comp->ifs, Load, 0)) return 0; } return 1; } static int validate_keywords(struct validator *state, asdl_keyword_seq *keywords) { assert(!PyErr_Occurred()); for (Py_ssize_t i = 0; i < asdl_seq_LEN(keywords); i++) if (!validate_expr(state, (asdl_seq_GET(keywords, i))->value, Load)) return 0; return 1; } static int validate_args(struct validator *state, asdl_arg_seq *args) { assert(!PyErr_Occurred()); for (Py_ssize_t i = 0; i < asdl_seq_LEN(args); i++) { arg_ty arg = asdl_seq_GET(args, i); VALIDATE_POSITIONS(arg); if (arg->annotation && !validate_expr(state, arg->annotation, Load)) return 0; } return 1; } static const char * expr_context_name(expr_context_ty ctx) { switch (ctx) { case Load: return "Load"; case Store: return "Store"; case Del: return "Del"; // No default case so compiler emits warning for unhandled cases } Py_UNREACHABLE(); } static int validate_arguments(struct validator *state, arguments_ty args) { assert(!PyErr_Occurred()); if (!validate_args(state, args->posonlyargs) || !validate_args(state, args->args)) { return 0; } if (args->vararg && args->vararg->annotation && !validate_expr(state, args->vararg->annotation, Load)) { return 0; } if (!validate_args(state, args->kwonlyargs)) return 0; if (args->kwarg && args->kwarg->annotation && !validate_expr(state, args->kwarg->annotation, Load)) { return 0; } if (asdl_seq_LEN(args->defaults) > asdl_seq_LEN(args->posonlyargs) + asdl_seq_LEN(args->args)) { PyErr_SetString(PyExc_ValueError, "more positional defaults than args on arguments"); return 0; } if (asdl_seq_LEN(args->kw_defaults) != asdl_seq_LEN(args->kwonlyargs)) { PyErr_SetString(PyExc_ValueError, "length of kwonlyargs is not the same as " "kw_defaults on arguments"); return 0; } return validate_exprs(state, args->defaults, Load, 0) && validate_exprs(state, args->kw_defaults, Load, 1); } static int validate_constant(struct validator *state, PyObject *value) { assert(!PyErr_Occurred()); if (value == Py_None || value == Py_Ellipsis) return 1; if (PyLong_CheckExact(value) || PyFloat_CheckExact(value) || PyComplex_CheckExact(value) || PyBool_Check(value) || PyUnicode_CheckExact(value) || PyBytes_CheckExact(value)) return 1; if (PyTuple_CheckExact(value) || PyFrozenSet_CheckExact(value)) { if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); return 0; } PyObject *it = PyObject_GetIter(value); if (it == NULL) return 0; while (1) { PyObject *item = PyIter_Next(it); if (item == NULL) { if (PyErr_Occurred()) { Py_DECREF(it); return 0; } break; } if (!validate_constant(state, item)) { Py_DECREF(it); Py_DECREF(item); return 0; } Py_DECREF(item); } Py_DECREF(it); --state->recursion_depth; return 1; } if (!PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "got an invalid type in Constant: %s", _PyType_Name(Py_TYPE(value))); } return 0; } static int validate_expr(struct validator *state, expr_ty exp, expr_context_ty ctx) { assert(!PyErr_Occurred()); VALIDATE_POSITIONS(exp); int ret = -1; if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); return 0; } int check_ctx = 1; expr_context_ty actual_ctx; /* First check expression context. */ switch (exp->kind) { case Attribute_kind: actual_ctx = exp->v.Attribute.ctx; break; case Subscript_kind: actual_ctx = exp->v.Subscript.ctx; break; case Starred_kind: actual_ctx = exp->v.Starred.ctx; break; case Name_kind: if (!validate_name(exp->v.Name.id)) { return 0; } actual_ctx = exp->v.Name.ctx; break; case List_kind: actual_ctx = exp->v.List.ctx; break; case Tuple_kind: actual_ctx = exp->v.Tuple.ctx; break; default: if (ctx != Load) { PyErr_Format(PyExc_ValueError, "expression which can't be " "assigned to in %s context", expr_context_name(ctx)); return 0; } check_ctx = 0; /* set actual_ctx to prevent gcc warning */ actual_ctx = 0; } if (check_ctx && actual_ctx != ctx) { PyErr_Format(PyExc_ValueError, "expression must have %s context but has %s instead", expr_context_name(ctx), expr_context_name(actual_ctx)); return 0; } /* Now validate expression. */ switch (exp->kind) { case BoolOp_kind: if (asdl_seq_LEN(exp->v.BoolOp.values) < 2) { PyErr_SetString(PyExc_ValueError, "BoolOp with less than 2 values"); return 0; } ret = validate_exprs(state, exp->v.BoolOp.values, Load, 0); break; case BinOp_kind: ret = validate_expr(state, exp->v.BinOp.left, Load) && validate_expr(state, exp->v.BinOp.right, Load); break; case UnaryOp_kind: ret = validate_expr(state, exp->v.UnaryOp.operand, Load); break; case Lambda_kind: ret = validate_arguments(state, exp->v.Lambda.args) && validate_expr(state, exp->v.Lambda.body, Load); break; case IfExp_kind: ret = validate_expr(state, exp->v.IfExp.test, Load) && validate_expr(state, exp->v.IfExp.body, Load) && validate_expr(state, exp->v.IfExp.orelse, Load); break; case Dict_kind: if (asdl_seq_LEN(exp->v.Dict.keys) != asdl_seq_LEN(exp->v.Dict.values)) { PyErr_SetString(PyExc_ValueError, "Dict doesn't have the same number of keys as values"); return 0; } /* null_ok=1 for keys expressions to allow dict unpacking to work in dict literals, i.e. ``{**{a:b}}`` */ ret = validate_exprs(state, exp->v.Dict.keys, Load, /*null_ok=*/ 1) && validate_exprs(state, exp->v.Dict.values, Load, /*null_ok=*/ 0); break; case Set_kind: ret = validate_exprs(state, exp->v.Set.elts, Load, 0); break; #define COMP(NAME) \ case NAME ## _kind: \ ret = validate_comprehension(state, exp->v.NAME.generators) && \ validate_expr(state, exp->v.NAME.elt, Load); \ break; COMP(ListComp) COMP(SetComp) COMP(GeneratorExp) #undef COMP case DictComp_kind: ret = validate_comprehension(state, exp->v.DictComp.generators) && validate_expr(state, exp->v.DictComp.key, Load) && validate_expr(state, exp->v.DictComp.value, Load); break; case Yield_kind: ret = !exp->v.Yield.value || validate_expr(state, exp->v.Yield.value, Load); break; case YieldFrom_kind: ret = validate_expr(state, exp->v.YieldFrom.value, Load); break; case Await_kind: ret = validate_expr(state, exp->v.Await.value, Load); break; case Compare_kind: if (!asdl_seq_LEN(exp->v.Compare.comparators)) { PyErr_SetString(PyExc_ValueError, "Compare with no comparators"); return 0; } if (asdl_seq_LEN(exp->v.Compare.comparators) != asdl_seq_LEN(exp->v.Compare.ops)) { PyErr_SetString(PyExc_ValueError, "Compare has a different number " "of comparators and operands"); return 0; } ret = validate_exprs(state, exp->v.Compare.comparators, Load, 0) && validate_expr(state, exp->v.Compare.left, Load); break; case Call_kind: ret = validate_expr(state, exp->v.Call.func, Load) && validate_exprs(state, exp->v.Call.args, Load, 0) && validate_keywords(state, exp->v.Call.keywords); break; case Constant_kind: if (!validate_constant(state, exp->v.Constant.value)) { return 0; } ret = 1; break; case JoinedStr_kind: ret = validate_exprs(state, exp->v.JoinedStr.values, Load, 0); break; case FormattedValue_kind: if (validate_expr(state, exp->v.FormattedValue.value, Load) == 0) return 0; if (exp->v.FormattedValue.format_spec) { ret = validate_expr(state, exp->v.FormattedValue.format_spec, Load); break; } ret = 1; break; case Attribute_kind: ret = validate_expr(state, exp->v.Attribute.value, Load); break; case Subscript_kind: ret = validate_expr(state, exp->v.Subscript.slice, Load) && validate_expr(state, exp->v.Subscript.value, Load); break; case Starred_kind: ret = validate_expr(state, exp->v.Starred.value, ctx); break; case Slice_kind: ret = (!exp->v.Slice.lower || validate_expr(state, exp->v.Slice.lower, Load)) && (!exp->v.Slice.upper || validate_expr(state, exp->v.Slice.upper, Load)) && (!exp->v.Slice.step || validate_expr(state, exp->v.Slice.step, Load)); break; case List_kind: ret = validate_exprs(state, exp->v.List.elts, ctx, 0); break; case Tuple_kind: ret = validate_exprs(state, exp->v.Tuple.elts, ctx, 0); break; case NamedExpr_kind: ret = validate_expr(state, exp->v.NamedExpr.value, Load); break; /* This last case doesn't have any checking. */ case Name_kind: ret = 1; break; // No default case so compiler emits warning for unhandled cases } if (ret < 0) { PyErr_SetString(PyExc_SystemError, "unexpected expression"); ret = 0; } state->recursion_depth--; return ret; } // Note: the ensure_literal_* functions are only used to validate a restricted // set of non-recursive literals that have already been checked with // validate_expr, so they don't accept the validator state static int ensure_literal_number(expr_ty exp, bool allow_real, bool allow_imaginary) { assert(exp->kind == Constant_kind); PyObject *value = exp->v.Constant.value; return (allow_real && PyFloat_CheckExact(value)) || (allow_real && PyLong_CheckExact(value)) || (allow_imaginary && PyComplex_CheckExact(value)); } static int ensure_literal_negative(expr_ty exp, bool allow_real, bool allow_imaginary) { assert(exp->kind == UnaryOp_kind); // Must be negation ... if (exp->v.UnaryOp.op != USub) { return 0; } // ... of a constant ... expr_ty operand = exp->v.UnaryOp.operand; if (operand->kind != Constant_kind) { return 0; } // ... number return ensure_literal_number(operand, allow_real, allow_imaginary); } static int ensure_literal_complex(expr_ty exp) { assert(exp->kind == BinOp_kind); expr_ty left = exp->v.BinOp.left; expr_ty right = exp->v.BinOp.right; // Ensure op is addition or subtraction if (exp->v.BinOp.op != Add && exp->v.BinOp.op != Sub) { return 0; } // Check LHS is a real number (potentially signed) switch (left->kind) { case Constant_kind: if (!ensure_literal_number(left, /*real=*/true, /*imaginary=*/false)) { return 0; } break; case UnaryOp_kind: if (!ensure_literal_negative(left, /*real=*/true, /*imaginary=*/false)) { return 0; } break; default: return 0; } // Check RHS is an imaginary number (no separate sign allowed) switch (right->kind) { case Constant_kind: if (!ensure_literal_number(right, /*real=*/false, /*imaginary=*/true)) { return 0; } break; default: return 0; } return 1; } static int validate_pattern_match_value(struct validator *state, expr_ty exp) { assert(!PyErr_Occurred()); if (!validate_expr(state, exp, Load)) { return 0; } switch (exp->kind) { case Constant_kind: /* Ellipsis and immutable sequences are not allowed. For True, False and None, MatchSingleton() should be used */ if (!validate_expr(state, exp, Load)) { return 0; } PyObject *literal = exp->v.Constant.value; if (PyLong_CheckExact(literal) || PyFloat_CheckExact(literal) || PyBytes_CheckExact(literal) || PyComplex_CheckExact(literal) || PyUnicode_CheckExact(literal)) { return 1; } PyErr_SetString(PyExc_ValueError, "unexpected constant inside of a literal pattern"); return 0; case Attribute_kind: // Constants and attribute lookups are always permitted return 1; case UnaryOp_kind: // Negated numbers are permitted (whether real or imaginary) // Compiler will complain if AST folding doesn't create a constant if (ensure_literal_negative(exp, /*real=*/true, /*imaginary=*/true)) { return 1; } break; case BinOp_kind: // Complex literals are permitted // Compiler will complain if AST folding doesn't create a constant if (ensure_literal_complex(exp)) { return 1; } break; case JoinedStr_kind: // Handled in the later stages return 1; default: break; } PyErr_SetString(PyExc_ValueError, "patterns may only match literals and attribute lookups"); return 0; } static int validate_capture(PyObject *name) { assert(!PyErr_Occurred()); if (_PyUnicode_EqualToASCIIString(name, "_")) { PyErr_Format(PyExc_ValueError, "can't capture name '_' in patterns"); return 0; } return validate_name(name); } static int validate_pattern(struct validator *state, pattern_ty p, int star_ok) { assert(!PyErr_Occurred()); VALIDATE_POSITIONS(p); int ret = -1; if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); return 0; } switch (p->kind) { case MatchValue_kind: ret = validate_pattern_match_value(state, p->v.MatchValue.value); break; case MatchSingleton_kind: ret = p->v.MatchSingleton.value == Py_None || PyBool_Check(p->v.MatchSingleton.value); if (!ret) { PyErr_SetString(PyExc_ValueError, "MatchSingleton can only contain True, False and None"); } break; case MatchSequence_kind: ret = validate_patterns(state, p->v.MatchSequence.patterns, /*star_ok=*/1); break; case MatchMapping_kind: if (asdl_seq_LEN(p->v.MatchMapping.keys) != asdl_seq_LEN(p->v.MatchMapping.patterns)) { PyErr_SetString(PyExc_ValueError, "MatchMapping doesn't have the same number of keys as patterns"); ret = 0; break; } if (p->v.MatchMapping.rest && !validate_capture(p->v.MatchMapping.rest)) { ret = 0; break; } asdl_expr_seq *keys = p->v.MatchMapping.keys; for (Py_ssize_t i = 0; i < asdl_seq_LEN(keys); i++) { expr_ty key = asdl_seq_GET(keys, i); if (key->kind == Constant_kind) { PyObject *literal = key->v.Constant.value; if (literal == Py_None || PyBool_Check(literal)) { /* validate_pattern_match_value will ensure the key doesn't contain True, False and None but it is syntactically valid, so we will pass those on in a special case. */ continue; } } if (!validate_pattern_match_value(state, key)) { ret = 0; break; } } if (ret == 0) { break; } ret = validate_patterns(state, p->v.MatchMapping.patterns, /*star_ok=*/0); break; case MatchClass_kind: if (asdl_seq_LEN(p->v.MatchClass.kwd_attrs) != asdl_seq_LEN(p->v.MatchClass.kwd_patterns)) { PyErr_SetString(PyExc_ValueError, "MatchClass doesn't have the same number of keyword attributes as patterns"); ret = 0; break; } if (!validate_expr(state, p->v.MatchClass.cls, Load)) { ret = 0; break; } expr_ty cls = p->v.MatchClass.cls; while (1) { if (cls->kind == Name_kind) { break; } else if (cls->kind == Attribute_kind) { cls = cls->v.Attribute.value; continue; } else { PyErr_SetString(PyExc_ValueError, "MatchClass cls field can only contain Name or Attribute nodes."); ret = 0; break; } } if (ret == 0) { break; } for (Py_ssize_t i = 0; i < asdl_seq_LEN(p->v.MatchClass.kwd_attrs); i++) { PyObject *identifier = asdl_seq_GET(p->v.MatchClass.kwd_attrs, i); if (!validate_name(identifier)) { ret = 0; break; } } if (ret == 0) { break; } if (!validate_patterns(state, p->v.MatchClass.patterns, /*star_ok=*/0)) { ret = 0; break; } ret = validate_patterns(state, p->v.MatchClass.kwd_patterns, /*star_ok=*/0); break; case MatchStar_kind: if (!star_ok) { PyErr_SetString(PyExc_ValueError, "can't use MatchStar here"); ret = 0; break; } ret = p->v.MatchStar.name == NULL || validate_capture(p->v.MatchStar.name); break; case MatchAs_kind: if (p->v.MatchAs.name && !validate_capture(p->v.MatchAs.name)) { ret = 0; break; } if (p->v.MatchAs.pattern == NULL) { ret = 1; } else if (p->v.MatchAs.name == NULL) { PyErr_SetString(PyExc_ValueError, "MatchAs must specify a target name if a pattern is given"); ret = 0; } else { ret = validate_pattern(state, p->v.MatchAs.pattern, /*star_ok=*/0); } break; case MatchOr_kind: if (asdl_seq_LEN(p->v.MatchOr.patterns) < 2) { PyErr_SetString(PyExc_ValueError, "MatchOr requires at least 2 patterns"); ret = 0; break; } ret = validate_patterns(state, p->v.MatchOr.patterns, /*star_ok=*/0); break; // No default case, so the compiler will emit a warning if new pattern // kinds are added without being handled here } if (ret < 0) { PyErr_SetString(PyExc_SystemError, "unexpected pattern"); ret = 0; } state->recursion_depth--; return ret; } static int _validate_nonempty_seq(asdl_seq *seq, const char *what, const char *owner) { if (asdl_seq_LEN(seq)) return 1; PyErr_Format(PyExc_ValueError, "empty %s on %s", what, owner); return 0; } #define validate_nonempty_seq(seq, what, owner) _validate_nonempty_seq((asdl_seq*)seq, what, owner) static int validate_assignlist(struct validator *state, asdl_expr_seq *targets, expr_context_ty ctx) { assert(!PyErr_Occurred()); return validate_nonempty_seq(targets, "targets", ctx == Del ? "Delete" : "Assign") && validate_exprs(state, targets, ctx, 0); } static int validate_body(struct validator *state, asdl_stmt_seq *body, const char *owner) { assert(!PyErr_Occurred()); return validate_nonempty_seq(body, "body", owner) && validate_stmts(state, body); } static int validate_stmt(struct validator *state, stmt_ty stmt) { assert(!PyErr_Occurred()); VALIDATE_POSITIONS(stmt); int ret = -1; if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); return 0; } switch (stmt->kind) { case FunctionDef_kind: ret = validate_body(state, stmt->v.FunctionDef.body, "FunctionDef") && validate_type_params(state, stmt->v.FunctionDef.type_params) && validate_arguments(state, stmt->v.FunctionDef.args) && validate_exprs(state, stmt->v.FunctionDef.decorator_list, Load, 0) && (!stmt->v.FunctionDef.returns || validate_expr(state, stmt->v.FunctionDef.returns, Load)); break; case ClassDef_kind: ret = validate_body(state, stmt->v.ClassDef.body, "ClassDef") && validate_type_params(state, stmt->v.ClassDef.type_params) && validate_exprs(state, stmt->v.ClassDef.bases, Load, 0) && validate_keywords(state, stmt->v.ClassDef.keywords) && validate_exprs(state, stmt->v.ClassDef.decorator_list, Load, 0); break; case Return_kind: ret = !stmt->v.Return.value || validate_expr(state, stmt->v.Return.value, Load); break; case Delete_kind: ret = validate_assignlist(state, stmt->v.Delete.targets, Del); break; case Assign_kind: ret = validate_assignlist(state, stmt->v.Assign.targets, Store) && validate_expr(state, stmt->v.Assign.value, Load); break; case AugAssign_kind: ret = validate_expr(state, stmt->v.AugAssign.target, Store) && validate_expr(state, stmt->v.AugAssign.value, Load); break; case AnnAssign_kind: if (stmt->v.AnnAssign.target->kind != Name_kind && stmt->v.AnnAssign.simple) { PyErr_SetString(PyExc_TypeError, "AnnAssign with simple non-Name target"); return 0; } ret = validate_expr(state, stmt->v.AnnAssign.target, Store) && (!stmt->v.AnnAssign.value || validate_expr(state, stmt->v.AnnAssign.value, Load)) && validate_expr(state, stmt->v.AnnAssign.annotation, Load); break; case TypeAlias_kind: ret = validate_expr(state, stmt->v.TypeAlias.name, Store) && validate_type_params(state, stmt->v.TypeAlias.type_params) && validate_expr(state, stmt->v.TypeAlias.value, Load); break; case For_kind: ret = validate_expr(state, stmt->v.For.target, Store) && validate_expr(state, stmt->v.For.iter, Load) && validate_body(state, stmt->v.For.body, "For") && validate_stmts(state, stmt->v.For.orelse); break; case AsyncFor_kind: ret = validate_expr(state, stmt->v.AsyncFor.target, Store) && validate_expr(state, stmt->v.AsyncFor.iter, Load) && validate_body(state, stmt->v.AsyncFor.body, "AsyncFor") && validate_stmts(state, stmt->v.AsyncFor.orelse); break; case While_kind: ret = validate_expr(state, stmt->v.While.test, Load) && validate_body(state, stmt->v.While.body, "While") && validate_stmts(state, stmt->v.While.orelse); break; case If_kind: ret = validate_expr(state, stmt->v.If.test, Load) && validate_body(state, stmt->v.If.body, "If") && validate_stmts(state, stmt->v.If.orelse); break; case With_kind: if (!validate_nonempty_seq(stmt->v.With.items, "items", "With")) return 0; for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.With.items); i++) { withitem_ty item = asdl_seq_GET(stmt->v.With.items, i); if (!validate_expr(state, item->context_expr, Load) || (item->optional_vars && !validate_expr(state, item->optional_vars, Store))) return 0; } ret = validate_body(state, stmt->v.With.body, "With"); break; case AsyncWith_kind: if (!validate_nonempty_seq(stmt->v.AsyncWith.items, "items", "AsyncWith")) return 0; for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.AsyncWith.items); i++) { withitem_ty item = asdl_seq_GET(stmt->v.AsyncWith.items, i); if (!validate_expr(state, item->context_expr, Load) || (item->optional_vars && !validate_expr(state, item->optional_vars, Store))) return 0; } ret = validate_body(state, stmt->v.AsyncWith.body, "AsyncWith"); break; case Match_kind: if (!validate_expr(state, stmt->v.Match.subject, Load) || !validate_nonempty_seq(stmt->v.Match.cases, "cases", "Match")) { return 0; } for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.Match.cases); i++) { match_case_ty m = asdl_seq_GET(stmt->v.Match.cases, i); if (!validate_pattern(state, m->pattern, /*star_ok=*/0) || (m->guard && !validate_expr(state, m->guard, Load)) || !validate_body(state, m->body, "match_case")) { return 0; } } ret = 1; break; case Raise_kind: if (stmt->v.Raise.exc) { ret = validate_expr(state, stmt->v.Raise.exc, Load) && (!stmt->v.Raise.cause || validate_expr(state, stmt->v.Raise.cause, Load)); break; } if (stmt->v.Raise.cause) { PyErr_SetString(PyExc_ValueError, "Raise with cause but no exception"); return 0; } ret = 1; break; case Try_kind: if (!validate_body(state, stmt->v.Try.body, "Try")) return 0; if (!asdl_seq_LEN(stmt->v.Try.handlers) && !asdl_seq_LEN(stmt->v.Try.finalbody)) { PyErr_SetString(PyExc_ValueError, "Try has neither except handlers nor finalbody"); return 0; } if (!asdl_seq_LEN(stmt->v.Try.handlers) && asdl_seq_LEN(stmt->v.Try.orelse)) { PyErr_SetString(PyExc_ValueError, "Try has orelse but no except handlers"); return 0; } for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.Try.handlers); i++) { excepthandler_ty handler = asdl_seq_GET(stmt->v.Try.handlers, i); VALIDATE_POSITIONS(handler); if ((handler->v.ExceptHandler.type && !validate_expr(state, handler->v.ExceptHandler.type, Load)) || !validate_body(state, handler->v.ExceptHandler.body, "ExceptHandler")) return 0; } ret = (!asdl_seq_LEN(stmt->v.Try.finalbody) || validate_stmts(state, stmt->v.Try.finalbody)) && (!asdl_seq_LEN(stmt->v.Try.orelse) || validate_stmts(state, stmt->v.Try.orelse)); break; case TryStar_kind: if (!validate_body(state, stmt->v.TryStar.body, "TryStar")) return 0; if (!asdl_seq_LEN(stmt->v.TryStar.handlers) && !asdl_seq_LEN(stmt->v.TryStar.finalbody)) { PyErr_SetString(PyExc_ValueError, "TryStar has neither except handlers nor finalbody"); return 0; } if (!asdl_seq_LEN(stmt->v.TryStar.handlers) && asdl_seq_LEN(stmt->v.TryStar.orelse)) { PyErr_SetString(PyExc_ValueError, "TryStar has orelse but no except handlers"); return 0; } for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.TryStar.handlers); i++) { excepthandler_ty handler = asdl_seq_GET(stmt->v.TryStar.handlers, i); if ((handler->v.ExceptHandler.type && !validate_expr(state, handler->v.ExceptHandler.type, Load)) || !validate_body(state, handler->v.ExceptHandler.body, "ExceptHandler")) return 0; } ret = (!asdl_seq_LEN(stmt->v.TryStar.finalbody) || validate_stmts(state, stmt->v.TryStar.finalbody)) && (!asdl_seq_LEN(stmt->v.TryStar.orelse) || validate_stmts(state, stmt->v.TryStar.orelse)); break; case Assert_kind: ret = validate_expr(state, stmt->v.Assert.test, Load) && (!stmt->v.Assert.msg || validate_expr(state, stmt->v.Assert.msg, Load)); break; case Import_kind: ret = validate_nonempty_seq(stmt->v.Import.names, "names", "Import"); break; case ImportFrom_kind: if (stmt->v.ImportFrom.level < 0) { PyErr_SetString(PyExc_ValueError, "Negative ImportFrom level"); return 0; } ret = validate_nonempty_seq(stmt->v.ImportFrom.names, "names", "ImportFrom"); break; case Global_kind: ret = validate_nonempty_seq(stmt->v.Global.names, "names", "Global"); break; case Nonlocal_kind: ret = validate_nonempty_seq(stmt->v.Nonlocal.names, "names", "Nonlocal"); break; case Expr_kind: ret = validate_expr(state, stmt->v.Expr.value, Load); break; case AsyncFunctionDef_kind: ret = validate_body(state, stmt->v.AsyncFunctionDef.body, "AsyncFunctionDef") && validate_type_params(state, stmt->v.AsyncFunctionDef.type_params) && validate_arguments(state, stmt->v.AsyncFunctionDef.args) && validate_exprs(state, stmt->v.AsyncFunctionDef.decorator_list, Load, 0) && (!stmt->v.AsyncFunctionDef.returns || validate_expr(state, stmt->v.AsyncFunctionDef.returns, Load)); break; case Pass_kind: case Break_kind: case Continue_kind: ret = 1; break; // No default case so compiler emits warning for unhandled cases } if (ret < 0) { PyErr_SetString(PyExc_SystemError, "unexpected statement"); ret = 0; } state->recursion_depth--; return ret; } static int validate_stmts(struct validator *state, asdl_stmt_seq *seq) { assert(!PyErr_Occurred()); for (Py_ssize_t i = 0; i < asdl_seq_LEN(seq); i++) { stmt_ty stmt = asdl_seq_GET(seq, i); if (stmt) { if (!validate_stmt(state, stmt)) return 0; } else { PyErr_SetString(PyExc_ValueError, "None disallowed in statement list"); return 0; } } return 1; } static int validate_exprs(struct validator *state, asdl_expr_seq *exprs, expr_context_ty ctx, int null_ok) { assert(!PyErr_Occurred()); for (Py_ssize_t i = 0; i < asdl_seq_LEN(exprs); i++) { expr_ty expr = asdl_seq_GET(exprs, i); if (expr) { if (!validate_expr(state, expr, ctx)) return 0; } else if (!null_ok) { PyErr_SetString(PyExc_ValueError, "None disallowed in expression list"); return 0; } } return 1; } static int validate_patterns(struct validator *state, asdl_pattern_seq *patterns, int star_ok) { assert(!PyErr_Occurred()); for (Py_ssize_t i = 0; i < asdl_seq_LEN(patterns); i++) { pattern_ty pattern = asdl_seq_GET(patterns, i); if (!validate_pattern(state, pattern, star_ok)) { return 0; } } return 1; } static int validate_typeparam(struct validator *state, type_param_ty tp) { VALIDATE_POSITIONS(tp); int ret = -1; switch (tp->kind) { case TypeVar_kind: ret = validate_name(tp->v.TypeVar.name) && (!tp->v.TypeVar.bound || validate_expr(state, tp->v.TypeVar.bound, Load)); break; case ParamSpec_kind: ret = validate_name(tp->v.ParamSpec.name); break; case TypeVarTuple_kind: ret = validate_name(tp->v.TypeVarTuple.name); break; } return ret; } static int validate_type_params(struct validator *state, asdl_type_param_seq *tps) { Py_ssize_t i; for (i = 0; i < asdl_seq_LEN(tps); i++) { type_param_ty tp = asdl_seq_GET(tps, i); if (tp) { if (!validate_typeparam(state, tp)) return 0; } } return 1; } /* See comments in symtable.c. */ #define COMPILER_STACK_FRAME_SCALE 3 int _PyAST_Validate(mod_ty mod) { assert(!PyErr_Occurred()); int res = -1; struct validator state; PyThreadState *tstate; int starting_recursion_depth; /* Setup recursion depth check counters */ tstate = _PyThreadState_GET(); if (!tstate) { return 0; } /* Be careful here to prevent overflow. */ int recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining; starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE; state.recursion_depth = starting_recursion_depth; state.recursion_limit = C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE; switch (mod->kind) { case Module_kind: res = validate_stmts(&state, mod->v.Module.body); break; case Interactive_kind: res = validate_stmts(&state, mod->v.Interactive.body); break; case Expression_kind: res = validate_expr(&state, mod->v.Expression.body, Load); break; case FunctionType_kind: res = validate_exprs(&state, mod->v.FunctionType.argtypes, Load, /*null_ok=*/0) && validate_expr(&state, mod->v.FunctionType.returns, Load); break; // No default case so compiler emits warning for unhandled cases } if (res < 0) { PyErr_SetString(PyExc_SystemError, "impossible module node"); return 0; } /* Check that the recursion depth counting balanced correctly */ if (res && state.recursion_depth != starting_recursion_depth) { PyErr_Format(PyExc_SystemError, "AST validator recursion depth mismatch (before=%d, after=%d)", starting_recursion_depth, state.recursion_depth); return 0; } return res; } PyObject * _PyAST_GetDocString(asdl_stmt_seq *body) { if (!asdl_seq_LEN(body)) { return NULL; } stmt_ty st = asdl_seq_GET(body, 0); if (st->kind != Expr_kind) { return NULL; } expr_ty e = st->v.Expr.value; if (e->kind == Constant_kind && PyUnicode_CheckExact(e->v.Constant.value)) { return e->v.Constant.value; } return NULL; } ================================================ FILE: Ast_Opt.c ================================================ /* AST Optimizer */ #include "Python.h" #include "pycore_ast.h" // _PyAST_GetDocString() #include "pycore_long.h" // _PyLong #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_format.h" // F_LJUST typedef struct { int optimize; int ff_features; int recursion_depth; /* current recursion depth */ int recursion_limit; /* recursion limit */ } _PyASTOptimizeState; static int make_const(expr_ty node, PyObject *val, PyArena *arena) { // Even if no new value was calculated, make_const may still // need to clear an error (e.g. for division by zero) if (val == NULL) { if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) { return 0; } PyErr_Clear(); return 1; } if (_PyArena_AddPyObject(arena, val) < 0) { Py_DECREF(val); return 0; } node->kind = Constant_kind; node->v.Constant.kind = NULL; node->v.Constant.value = val; return 1; } #define COPY_NODE(TO, FROM) (memcpy((TO), (FROM), sizeof(struct _expr))) static int has_starred(asdl_expr_seq *elts) { Py_ssize_t n = asdl_seq_LEN(elts); for (Py_ssize_t i = 0; i < n; i++) { expr_ty e = (expr_ty)asdl_seq_GET(elts, i); if (e->kind == Starred_kind) { return 1; } } return 0; } static PyObject* unary_not(PyObject *v) { int r = PyObject_IsTrue(v); if (r < 0) return NULL; return PyBool_FromLong(!r); } static int fold_unaryop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) { expr_ty arg = node->v.UnaryOp.operand; if (arg->kind != Constant_kind) { /* Fold not into comparison */ if (node->v.UnaryOp.op == Not && arg->kind == Compare_kind && asdl_seq_LEN(arg->v.Compare.ops) == 1) { /* Eq and NotEq are often implemented in terms of one another, so folding not (self == other) into self != other breaks implementation of !=. Detecting such cases doesn't seem worthwhile. Python uses for 'is subset'/'is superset' operations on sets. They don't satisfy not folding laws. */ cmpop_ty op = asdl_seq_GET(arg->v.Compare.ops, 0); switch (op) { case Is: op = IsNot; break; case IsNot: op = Is; break; case In: op = NotIn; break; case NotIn: op = In; break; // The remaining comparison operators can't be safely inverted case Eq: case NotEq: case Lt: case LtE: case Gt: case GtE: op = 0; // The AST enums leave "0" free as an "unused" marker break; // No default case, so the compiler will emit a warning if new // comparison operators are added without being handled here } if (op) { asdl_seq_SET(arg->v.Compare.ops, 0, op); COPY_NODE(node, arg); return 1; } } return 1; } typedef PyObject *(*unary_op)(PyObject*); static const unary_op ops[] = { [Invert] = PyNumber_Invert, [Not] = unary_not, [UAdd] = PyNumber_Positive, [USub] = PyNumber_Negative, }; PyObject *newval = ops[node->v.UnaryOp.op](arg->v.Constant.value); return make_const(node, newval, arena); } /* Check whether a collection doesn't containing too much items (including subcollections). This protects from creating a constant that needs too much time for calculating a hash. "limit" is the maximal number of items. Returns the negative number if the total number of items exceeds the limit. Otherwise returns the limit minus the total number of items. */ static Py_ssize_t check_complexity(PyObject *obj, Py_ssize_t limit) { if (PyTuple_Check(obj)) { Py_ssize_t i; limit -= PyTuple_GET_SIZE(obj); for (i = 0; limit >= 0 && i < PyTuple_GET_SIZE(obj); i++) { limit = check_complexity(PyTuple_GET_ITEM(obj, i), limit); } return limit; } else if (PyFrozenSet_Check(obj)) { Py_ssize_t i = 0; PyObject *item; Py_hash_t hash; limit -= PySet_GET_SIZE(obj); while (limit >= 0 && _PySet_NextEntry(obj, &i, &item, &hash)) { limit = check_complexity(item, limit); } } return limit; } #define MAX_INT_SIZE 128 /* bits */ #define MAX_COLLECTION_SIZE 256 /* items */ #define MAX_STR_SIZE 4096 /* characters */ #define MAX_TOTAL_ITEMS 1024 /* including nested collections */ static PyObject * safe_multiply(PyObject *v, PyObject *w) { if (PyLong_Check(v) && PyLong_Check(w) && !_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w) ) { size_t vbits = _PyLong_NumBits(v); size_t wbits = _PyLong_NumBits(w); if (vbits == (size_t)-1 || wbits == (size_t)-1) { return NULL; } if (vbits + wbits > MAX_INT_SIZE) { return NULL; } } else if (PyLong_Check(v) && (PyTuple_Check(w) || PyFrozenSet_Check(w))) { Py_ssize_t size = PyTuple_Check(w) ? PyTuple_GET_SIZE(w) : PySet_GET_SIZE(w); if (size) { long n = PyLong_AsLong(v); if (n < 0 || n > MAX_COLLECTION_SIZE / size) { return NULL; } if (n && check_complexity(w, MAX_TOTAL_ITEMS / n) < 0) { return NULL; } } } else if (PyLong_Check(v) && (PyUnicode_Check(w) || PyBytes_Check(w))) { Py_ssize_t size = PyUnicode_Check(w) ? PyUnicode_GET_LENGTH(w) : PyBytes_GET_SIZE(w); if (size) { long n = PyLong_AsLong(v); if (n < 0 || n > MAX_STR_SIZE / size) { return NULL; } } } else if (PyLong_Check(w) && (PyTuple_Check(v) || PyFrozenSet_Check(v) || PyUnicode_Check(v) || PyBytes_Check(v))) { return safe_multiply(w, v); } return PyNumber_Multiply(v, w); } static PyObject * safe_power(PyObject *v, PyObject *w) { if (PyLong_Check(v) && PyLong_Check(w) && !_PyLong_IsZero((PyLongObject *)v) && _PyLong_IsPositive((PyLongObject *)w) ) { size_t vbits = _PyLong_NumBits(v); size_t wbits = PyLong_AsSize_t(w); if (vbits == (size_t)-1 || wbits == (size_t)-1) { return NULL; } if (vbits > MAX_INT_SIZE / wbits) { return NULL; } } return PyNumber_Power(v, w, Py_None); } static PyObject * safe_lshift(PyObject *v, PyObject *w) { if (PyLong_Check(v) && PyLong_Check(w) && !_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w) ) { size_t vbits = _PyLong_NumBits(v); size_t wbits = PyLong_AsSize_t(w); if (vbits == (size_t)-1 || wbits == (size_t)-1) { return NULL; } if (wbits > MAX_INT_SIZE || vbits > MAX_INT_SIZE - wbits) { return NULL; } } return PyNumber_Lshift(v, w); } static PyObject * safe_mod(PyObject *v, PyObject *w) { if (PyUnicode_Check(v) || PyBytes_Check(v)) { return NULL; } return PyNumber_Remainder(v, w); } static expr_ty parse_literal(PyObject *fmt, Py_ssize_t *ppos, PyArena *arena) { const void *data = PyUnicode_DATA(fmt); int kind = PyUnicode_KIND(fmt); Py_ssize_t size = PyUnicode_GET_LENGTH(fmt); Py_ssize_t start, pos; int has_percents = 0; start = pos = *ppos; while (pos < size) { if (PyUnicode_READ(kind, data, pos) != '%') { pos++; } else if (pos+1 < size && PyUnicode_READ(kind, data, pos+1) == '%') { has_percents = 1; pos += 2; } else { break; } } *ppos = pos; if (pos == start) { return NULL; } PyObject *str = PyUnicode_Substring(fmt, start, pos); /* str = str.replace('%%', '%') */ if (str && has_percents) { _Py_DECLARE_STR(percent, "%"); _Py_DECLARE_STR(dbl_percent, "%%"); Py_SETREF(str, PyUnicode_Replace(str, &_Py_STR(dbl_percent), &_Py_STR(percent), -1)); } if (!str) { return NULL; } if (_PyArena_AddPyObject(arena, str) < 0) { Py_DECREF(str); return NULL; } return _PyAST_Constant(str, NULL, -1, -1, -1, -1, arena); } #define MAXDIGITS 3 static int simple_format_arg_parse(PyObject *fmt, Py_ssize_t *ppos, int *spec, int *flags, int *width, int *prec) { Py_ssize_t pos = *ppos, len = PyUnicode_GET_LENGTH(fmt); Py_UCS4 ch; #define NEXTC do { \ if (pos >= len) { \ return 0; \ } \ ch = PyUnicode_READ_CHAR(fmt, pos); \ pos++; \ } while (0) *flags = 0; while (1) { NEXTC; switch (ch) { case '-': *flags |= F_LJUST; continue; case '+': *flags |= F_SIGN; continue; case ' ': *flags |= F_BLANK; continue; case '#': *flags |= F_ALT; continue; case '0': *flags |= F_ZERO; continue; } break; } if ('0' <= ch && ch <= '9') { *width = 0; int digits = 0; while ('0' <= ch && ch <= '9') { *width = *width * 10 + (ch - '0'); NEXTC; if (++digits >= MAXDIGITS) { return 0; } } } if (ch == '.') { NEXTC; *prec = 0; if ('0' <= ch && ch <= '9') { int digits = 0; while ('0' <= ch && ch <= '9') { *prec = *prec * 10 + (ch - '0'); NEXTC; if (++digits >= MAXDIGITS) { return 0; } } } } *spec = ch; *ppos = pos; return 1; #undef NEXTC } static expr_ty parse_format(PyObject *fmt, Py_ssize_t *ppos, expr_ty arg, PyArena *arena) { int spec, flags, width = -1, prec = -1; if (!simple_format_arg_parse(fmt, ppos, &spec, &flags, &width, &prec)) { // Unsupported format. return NULL; } if (spec == 's' || spec == 'r' || spec == 'a') { char buf[1 + MAXDIGITS + 1 + MAXDIGITS + 1], *p = buf; if (!(flags & F_LJUST) && width > 0) { *p++ = '>'; } if (width >= 0) { p += snprintf(p, MAXDIGITS + 1, "%d", width); } if (prec >= 0) { p += snprintf(p, MAXDIGITS + 2, ".%d", prec); } expr_ty format_spec = NULL; if (p != buf) { PyObject *str = PyUnicode_FromString(buf); if (str == NULL) { return NULL; } if (_PyArena_AddPyObject(arena, str) < 0) { Py_DECREF(str); return NULL; } format_spec = _PyAST_Constant(str, NULL, -1, -1, -1, -1, arena); if (format_spec == NULL) { return NULL; } } return _PyAST_FormattedValue(arg, spec, format_spec, arg->lineno, arg->col_offset, arg->end_lineno, arg->end_col_offset, arena); } // Unsupported format. return NULL; } static int optimize_format(expr_ty node, PyObject *fmt, asdl_expr_seq *elts, PyArena *arena) { Py_ssize_t pos = 0; Py_ssize_t cnt = 0; asdl_expr_seq *seq = _Py_asdl_expr_seq_new(asdl_seq_LEN(elts) * 2 + 1, arena); if (!seq) { return 0; } seq->size = 0; while (1) { expr_ty lit = parse_literal(fmt, &pos, arena); if (lit) { asdl_seq_SET(seq, seq->size++, lit); } else if (PyErr_Occurred()) { return 0; } if (pos >= PyUnicode_GET_LENGTH(fmt)) { break; } if (cnt >= asdl_seq_LEN(elts)) { // More format units than items. return 1; } assert(PyUnicode_READ_CHAR(fmt, pos) == '%'); pos++; expr_ty expr = parse_format(fmt, &pos, asdl_seq_GET(elts, cnt), arena); cnt++; if (!expr) { return !PyErr_Occurred(); } asdl_seq_SET(seq, seq->size++, expr); } if (cnt < asdl_seq_LEN(elts)) { // More items than format units. return 1; } expr_ty res = _PyAST_JoinedStr(seq, node->lineno, node->col_offset, node->end_lineno, node->end_col_offset, arena); if (!res) { return 0; } COPY_NODE(node, res); // PySys_FormatStderr("format = %R\n", fmt); return 1; } static int fold_binop(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) { expr_ty lhs, rhs; lhs = node->v.BinOp.left; rhs = node->v.BinOp.right; if (lhs->kind != Constant_kind) { return 1; } PyObject *lv = lhs->v.Constant.value; if (node->v.BinOp.op == Mod && rhs->kind == Tuple_kind && PyUnicode_Check(lv) && !has_starred(rhs->v.Tuple.elts)) { return optimize_format(node, lv, rhs->v.Tuple.elts, arena); } if (rhs->kind != Constant_kind) { return 1; } PyObject *rv = rhs->v.Constant.value; PyObject *newval = NULL; switch (node->v.BinOp.op) { case Add: newval = PyNumber_Add(lv, rv); break; case Sub: newval = PyNumber_Subtract(lv, rv); break; case Mult: newval = safe_multiply(lv, rv); break; case Div: newval = PyNumber_TrueDivide(lv, rv); break; case FloorDiv: newval = PyNumber_FloorDivide(lv, rv); break; case Mod: newval = safe_mod(lv, rv); break; case Pow: newval = safe_power(lv, rv); break; case LShift: newval = safe_lshift(lv, rv); break; case RShift: newval = PyNumber_Rshift(lv, rv); break; case BitOr: newval = PyNumber_Or(lv, rv); break; case BitXor: newval = PyNumber_Xor(lv, rv); break; case BitAnd: newval = PyNumber_And(lv, rv); break; // No builtin constants implement the following operators case MatMult: return 1; // No default case, so the compiler will emit a warning if new binary // operators are added without being handled here } return make_const(node, newval, arena); } static PyObject* make_const_tuple(asdl_expr_seq *elts) { for (int i = 0; i < asdl_seq_LEN(elts); i++) { expr_ty e = (expr_ty)asdl_seq_GET(elts, i); if (e->kind != Constant_kind) { return NULL; } } PyObject *newval = PyTuple_New(asdl_seq_LEN(elts)); if (newval == NULL) { return NULL; } for (int i = 0; i < asdl_seq_LEN(elts); i++) { expr_ty e = (expr_ty)asdl_seq_GET(elts, i); PyObject *v = e->v.Constant.value; PyTuple_SET_ITEM(newval, i, Py_NewRef(v)); } return newval; } static int fold_tuple(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) { PyObject *newval; if (node->v.Tuple.ctx != Load) return 1; newval = make_const_tuple(node->v.Tuple.elts); return make_const(node, newval, arena); } static int fold_subscr(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) { PyObject *newval; expr_ty arg, idx; arg = node->v.Subscript.value; idx = node->v.Subscript.slice; if (node->v.Subscript.ctx != Load || arg->kind != Constant_kind || idx->kind != Constant_kind) { return 1; } newval = PyObject_GetItem(arg->v.Constant.value, idx->v.Constant.value); return make_const(node, newval, arena); } /* Change literal list or set of constants into constant tuple or frozenset respectively. Change literal list of non-constants into tuple. Used for right operand of "in" and "not in" tests and for iterable in "for" loop and comprehensions. */ static int fold_iter(expr_ty arg, PyArena *arena, _PyASTOptimizeState *state) { PyObject *newval; if (arg->kind == List_kind) { /* First change a list into tuple. */ asdl_expr_seq *elts = arg->v.List.elts; if (has_starred(elts)) { return 1; } expr_context_ty ctx = arg->v.List.ctx; arg->kind = Tuple_kind; arg->v.Tuple.elts = elts; arg->v.Tuple.ctx = ctx; /* Try to create a constant tuple. */ newval = make_const_tuple(elts); } else if (arg->kind == Set_kind) { newval = make_const_tuple(arg->v.Set.elts); if (newval) { Py_SETREF(newval, PyFrozenSet_New(newval)); } } else { return 1; } return make_const(arg, newval, arena); } static int fold_compare(expr_ty node, PyArena *arena, _PyASTOptimizeState *state) { asdl_int_seq *ops; asdl_expr_seq *args; Py_ssize_t i; ops = node->v.Compare.ops; args = node->v.Compare.comparators; /* Change literal list or set in 'in' or 'not in' into tuple or frozenset respectively. */ i = asdl_seq_LEN(ops) - 1; int op = asdl_seq_GET(ops, i); if (op == In || op == NotIn) { if (!fold_iter((expr_ty)asdl_seq_GET(args, i), arena, state)) { return 0; } } return 1; } static int astfold_mod(mod_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_arguments(arguments_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_comprehension(comprehension_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_keyword(keyword_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_arg(arg_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_withitem(withitem_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_match_case(match_case_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_pattern(pattern_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_type_param(type_param_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); #define CALL(FUNC, TYPE, ARG) \ if (!FUNC((ARG), ctx_, state)) \ return 0; #define CALL_OPT(FUNC, TYPE, ARG) \ if ((ARG) != NULL && !FUNC((ARG), ctx_, state)) \ return 0; #define CALL_SEQ(FUNC, TYPE, ARG) { \ int i; \ asdl_ ## TYPE ## _seq *seq = (ARG); /* avoid variable capture */ \ for (i = 0; i < asdl_seq_LEN(seq); i++) { \ TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \ if (elt != NULL && !FUNC(elt, ctx_, state)) \ return 0; \ } \ } static int astfold_body(asdl_stmt_seq *stmts, PyArena *ctx_, _PyASTOptimizeState *state) { int docstring = _PyAST_GetDocString(stmts) != NULL; CALL_SEQ(astfold_stmt, stmt, stmts); if (!docstring && _PyAST_GetDocString(stmts) != NULL) { stmt_ty st = (stmt_ty)asdl_seq_GET(stmts, 0); asdl_expr_seq *values = _Py_asdl_expr_seq_new(1, ctx_); if (!values) { return 0; } asdl_seq_SET(values, 0, st->v.Expr.value); expr_ty expr = _PyAST_JoinedStr(values, st->lineno, st->col_offset, st->end_lineno, st->end_col_offset, ctx_); if (!expr) { return 0; } st->v.Expr.value = expr; } return 1; } static int astfold_mod(mod_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) { switch (node_->kind) { case Module_kind: CALL(astfold_body, asdl_seq, node_->v.Module.body); break; case Interactive_kind: CALL_SEQ(astfold_stmt, stmt, node_->v.Interactive.body); break; case Expression_kind: CALL(astfold_expr, expr_ty, node_->v.Expression.body); break; // The following top level nodes don't participate in constant folding case FunctionType_kind: break; // No default case, so the compiler will emit a warning if new top level // compilation nodes are added without being handled here } return 1; } static int astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) { if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); return 0; } switch (node_->kind) { case BoolOp_kind: CALL_SEQ(astfold_expr, expr, node_->v.BoolOp.values); break; case BinOp_kind: CALL(astfold_expr, expr_ty, node_->v.BinOp.left); CALL(astfold_expr, expr_ty, node_->v.BinOp.right); CALL(fold_binop, expr_ty, node_); break; case UnaryOp_kind: CALL(astfold_expr, expr_ty, node_->v.UnaryOp.operand); CALL(fold_unaryop, expr_ty, node_); break; case Lambda_kind: CALL(astfold_arguments, arguments_ty, node_->v.Lambda.args); CALL(astfold_expr, expr_ty, node_->v.Lambda.body); break; case IfExp_kind: CALL(astfold_expr, expr_ty, node_->v.IfExp.test); CALL(astfold_expr, expr_ty, node_->v.IfExp.body); CALL(astfold_expr, expr_ty, node_->v.IfExp.orelse); break; case Dict_kind: CALL_SEQ(astfold_expr, expr, node_->v.Dict.keys); CALL_SEQ(astfold_expr, expr, node_->v.Dict.values); break; case Set_kind: CALL_SEQ(astfold_expr, expr, node_->v.Set.elts); break; case ListComp_kind: CALL(astfold_expr, expr_ty, node_->v.ListComp.elt); CALL_SEQ(astfold_comprehension, comprehension, node_->v.ListComp.generators); break; case SetComp_kind: CALL(astfold_expr, expr_ty, node_->v.SetComp.elt); CALL_SEQ(astfold_comprehension, comprehension, node_->v.SetComp.generators); break; case DictComp_kind: CALL(astfold_expr, expr_ty, node_->v.DictComp.key); CALL(astfold_expr, expr_ty, node_->v.DictComp.value); CALL_SEQ(astfold_comprehension, comprehension, node_->v.DictComp.generators); break; case GeneratorExp_kind: CALL(astfold_expr, expr_ty, node_->v.GeneratorExp.elt); CALL_SEQ(astfold_comprehension, comprehension, node_->v.GeneratorExp.generators); break; case Await_kind: CALL(astfold_expr, expr_ty, node_->v.Await.value); break; case Yield_kind: CALL_OPT(astfold_expr, expr_ty, node_->v.Yield.value); break; case YieldFrom_kind: CALL(astfold_expr, expr_ty, node_->v.YieldFrom.value); break; case Compare_kind: CALL(astfold_expr, expr_ty, node_->v.Compare.left); CALL_SEQ(astfold_expr, expr, node_->v.Compare.comparators); CALL(fold_compare, expr_ty, node_); break; case Call_kind: CALL(astfold_expr, expr_ty, node_->v.Call.func); CALL_SEQ(astfold_expr, expr, node_->v.Call.args); CALL_SEQ(astfold_keyword, keyword, node_->v.Call.keywords); break; case FormattedValue_kind: CALL(astfold_expr, expr_ty, node_->v.FormattedValue.value); CALL_OPT(astfold_expr, expr_ty, node_->v.FormattedValue.format_spec); break; case JoinedStr_kind: CALL_SEQ(astfold_expr, expr, node_->v.JoinedStr.values); break; case Attribute_kind: CALL(astfold_expr, expr_ty, node_->v.Attribute.value); break; case Subscript_kind: CALL(astfold_expr, expr_ty, node_->v.Subscript.value); CALL(astfold_expr, expr_ty, node_->v.Subscript.slice); CALL(fold_subscr, expr_ty, node_); break; case Starred_kind: CALL(astfold_expr, expr_ty, node_->v.Starred.value); break; case Slice_kind: CALL_OPT(astfold_expr, expr_ty, node_->v.Slice.lower); CALL_OPT(astfold_expr, expr_ty, node_->v.Slice.upper); CALL_OPT(astfold_expr, expr_ty, node_->v.Slice.step); break; case List_kind: CALL_SEQ(astfold_expr, expr, node_->v.List.elts); break; case Tuple_kind: CALL_SEQ(astfold_expr, expr, node_->v.Tuple.elts); CALL(fold_tuple, expr_ty, node_); break; case Name_kind: if (node_->v.Name.ctx == Load && _PyUnicode_EqualToASCIIString(node_->v.Name.id, "__debug__")) { state->recursion_depth--; return make_const(node_, PyBool_FromLong(!state->optimize), ctx_); } break; case NamedExpr_kind: CALL(astfold_expr, expr_ty, node_->v.NamedExpr.value); break; case Constant_kind: // Already a constant, nothing further to do break; // No default case, so the compiler will emit a warning if new expression // kinds are added without being handled here } state->recursion_depth--; return 1; } static int astfold_keyword(keyword_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) { CALL(astfold_expr, expr_ty, node_->value); return 1; } static int astfold_comprehension(comprehension_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) { CALL(astfold_expr, expr_ty, node_->target); CALL(astfold_expr, expr_ty, node_->iter); CALL_SEQ(astfold_expr, expr, node_->ifs); CALL(fold_iter, expr_ty, node_->iter); return 1; } static int astfold_arguments(arguments_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) { CALL_SEQ(astfold_arg, arg, node_->posonlyargs); CALL_SEQ(astfold_arg, arg, node_->args); CALL_OPT(astfold_arg, arg_ty, node_->vararg); CALL_SEQ(astfold_arg, arg, node_->kwonlyargs); CALL_SEQ(astfold_expr, expr, node_->kw_defaults); CALL_OPT(astfold_arg, arg_ty, node_->kwarg); CALL_SEQ(astfold_expr, expr, node_->defaults); return 1; } static int astfold_arg(arg_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) { if (!(state->ff_features & CO_FUTURE_ANNOTATIONS)) { CALL_OPT(astfold_expr, expr_ty, node_->annotation); } return 1; } static int astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) { if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); return 0; } switch (node_->kind) { case FunctionDef_kind: CALL_SEQ(astfold_type_param, type_param, node_->v.FunctionDef.type_params); CALL(astfold_arguments, arguments_ty, node_->v.FunctionDef.args); CALL(astfold_body, asdl_seq, node_->v.FunctionDef.body); CALL_SEQ(astfold_expr, expr, node_->v.FunctionDef.decorator_list); if (!(state->ff_features & CO_FUTURE_ANNOTATIONS)) { CALL_OPT(astfold_expr, expr_ty, node_->v.FunctionDef.returns); } break; case AsyncFunctionDef_kind: CALL_SEQ(astfold_type_param, type_param, node_->v.AsyncFunctionDef.type_params); CALL(astfold_arguments, arguments_ty, node_->v.AsyncFunctionDef.args); CALL(astfold_body, asdl_seq, node_->v.AsyncFunctionDef.body); CALL_SEQ(astfold_expr, expr, node_->v.AsyncFunctionDef.decorator_list); if (!(state->ff_features & CO_FUTURE_ANNOTATIONS)) { CALL_OPT(astfold_expr, expr_ty, node_->v.AsyncFunctionDef.returns); } break; case ClassDef_kind: CALL_SEQ(astfold_type_param, type_param, node_->v.ClassDef.type_params); CALL_SEQ(astfold_expr, expr, node_->v.ClassDef.bases); CALL_SEQ(astfold_keyword, keyword, node_->v.ClassDef.keywords); CALL(astfold_body, asdl_seq, node_->v.ClassDef.body); CALL_SEQ(astfold_expr, expr, node_->v.ClassDef.decorator_list); break; case Return_kind: CALL_OPT(astfold_expr, expr_ty, node_->v.Return.value); break; case Delete_kind: CALL_SEQ(astfold_expr, expr, node_->v.Delete.targets); break; case Assign_kind: CALL_SEQ(astfold_expr, expr, node_->v.Assign.targets); CALL(astfold_expr, expr_ty, node_->v.Assign.value); break; case AugAssign_kind: CALL(astfold_expr, expr_ty, node_->v.AugAssign.target); CALL(astfold_expr, expr_ty, node_->v.AugAssign.value); break; case AnnAssign_kind: CALL(astfold_expr, expr_ty, node_->v.AnnAssign.target); if (!(state->ff_features & CO_FUTURE_ANNOTATIONS)) { CALL(astfold_expr, expr_ty, node_->v.AnnAssign.annotation); } CALL_OPT(astfold_expr, expr_ty, node_->v.AnnAssign.value); break; case TypeAlias_kind: CALL(astfold_expr, expr_ty, node_->v.TypeAlias.name); CALL_SEQ(astfold_type_param, type_param, node_->v.TypeAlias.type_params); CALL(astfold_expr, expr_ty, node_->v.TypeAlias.value); break; case For_kind: CALL(astfold_expr, expr_ty, node_->v.For.target); CALL(astfold_expr, expr_ty, node_->v.For.iter); CALL_SEQ(astfold_stmt, stmt, node_->v.For.body); CALL_SEQ(astfold_stmt, stmt, node_->v.For.orelse); CALL(fold_iter, expr_ty, node_->v.For.iter); break; case AsyncFor_kind: CALL(astfold_expr, expr_ty, node_->v.AsyncFor.target); CALL(astfold_expr, expr_ty, node_->v.AsyncFor.iter); CALL_SEQ(astfold_stmt, stmt, node_->v.AsyncFor.body); CALL_SEQ(astfold_stmt, stmt, node_->v.AsyncFor.orelse); break; case While_kind: CALL(astfold_expr, expr_ty, node_->v.While.test); CALL_SEQ(astfold_stmt, stmt, node_->v.While.body); CALL_SEQ(astfold_stmt, stmt, node_->v.While.orelse); break; case If_kind: CALL(astfold_expr, expr_ty, node_->v.If.test); CALL_SEQ(astfold_stmt, stmt, node_->v.If.body); CALL_SEQ(astfold_stmt, stmt, node_->v.If.orelse); break; case With_kind: CALL_SEQ(astfold_withitem, withitem, node_->v.With.items); CALL_SEQ(astfold_stmt, stmt, node_->v.With.body); break; case AsyncWith_kind: CALL_SEQ(astfold_withitem, withitem, node_->v.AsyncWith.items); CALL_SEQ(astfold_stmt, stmt, node_->v.AsyncWith.body); break; case Raise_kind: CALL_OPT(astfold_expr, expr_ty, node_->v.Raise.exc); CALL_OPT(astfold_expr, expr_ty, node_->v.Raise.cause); break; case Try_kind: CALL_SEQ(astfold_stmt, stmt, node_->v.Try.body); CALL_SEQ(astfold_excepthandler, excepthandler, node_->v.Try.handlers); CALL_SEQ(astfold_stmt, stmt, node_->v.Try.orelse); CALL_SEQ(astfold_stmt, stmt, node_->v.Try.finalbody); break; case TryStar_kind: CALL_SEQ(astfold_stmt, stmt, node_->v.TryStar.body); CALL_SEQ(astfold_excepthandler, excepthandler, node_->v.TryStar.handlers); CALL_SEQ(astfold_stmt, stmt, node_->v.TryStar.orelse); CALL_SEQ(astfold_stmt, stmt, node_->v.TryStar.finalbody); break; case Assert_kind: CALL(astfold_expr, expr_ty, node_->v.Assert.test); CALL_OPT(astfold_expr, expr_ty, node_->v.Assert.msg); break; case Expr_kind: CALL(astfold_expr, expr_ty, node_->v.Expr.value); break; case Match_kind: CALL(astfold_expr, expr_ty, node_->v.Match.subject); CALL_SEQ(astfold_match_case, match_case, node_->v.Match.cases); break; // The following statements don't contain any subexpressions to be folded case Import_kind: case ImportFrom_kind: case Global_kind: case Nonlocal_kind: case Pass_kind: case Break_kind: case Continue_kind: break; // No default case, so the compiler will emit a warning if new statement // kinds are added without being handled here } state->recursion_depth--; return 1; } static int astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) { switch (node_->kind) { case ExceptHandler_kind: CALL_OPT(astfold_expr, expr_ty, node_->v.ExceptHandler.type); CALL_SEQ(astfold_stmt, stmt, node_->v.ExceptHandler.body); break; // No default case, so the compiler will emit a warning if new handler // kinds are added without being handled here } return 1; } static int astfold_withitem(withitem_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) { CALL(astfold_expr, expr_ty, node_->context_expr); CALL_OPT(astfold_expr, expr_ty, node_->optional_vars); return 1; } static int astfold_pattern(pattern_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) { // Currently, this is really only used to form complex/negative numeric // constants in MatchValue and MatchMapping nodes // We still recurse into all subexpressions and subpatterns anyway if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); return 0; } switch (node_->kind) { case MatchValue_kind: CALL(astfold_expr, expr_ty, node_->v.MatchValue.value); break; case MatchSingleton_kind: break; case MatchSequence_kind: CALL_SEQ(astfold_pattern, pattern, node_->v.MatchSequence.patterns); break; case MatchMapping_kind: CALL_SEQ(astfold_expr, expr, node_->v.MatchMapping.keys); CALL_SEQ(astfold_pattern, pattern, node_->v.MatchMapping.patterns); break; case MatchClass_kind: CALL(astfold_expr, expr_ty, node_->v.MatchClass.cls); CALL_SEQ(astfold_pattern, pattern, node_->v.MatchClass.patterns); CALL_SEQ(astfold_pattern, pattern, node_->v.MatchClass.kwd_patterns); break; case MatchStar_kind: break; case MatchAs_kind: if (node_->v.MatchAs.pattern) { CALL(astfold_pattern, pattern_ty, node_->v.MatchAs.pattern); } break; case MatchOr_kind: CALL_SEQ(astfold_pattern, pattern, node_->v.MatchOr.patterns); break; // No default case, so the compiler will emit a warning if new pattern // kinds are added without being handled here } state->recursion_depth--; return 1; } static int astfold_match_case(match_case_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) { CALL(astfold_pattern, expr_ty, node_->pattern); CALL_OPT(astfold_expr, expr_ty, node_->guard); CALL_SEQ(astfold_stmt, stmt, node_->body); return 1; } static int astfold_type_param(type_param_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) { switch (node_->kind) { case TypeVar_kind: CALL_OPT(astfold_expr, expr_ty, node_->v.TypeVar.bound); break; case ParamSpec_kind: break; case TypeVarTuple_kind: break; } return 1; } #undef CALL #undef CALL_OPT #undef CALL_SEQ /* See comments in symtable.c. */ #define COMPILER_STACK_FRAME_SCALE 3 int _PyAST_Optimize(mod_ty mod, PyArena *arena, int optimize, int ff_features) { PyThreadState *tstate; int starting_recursion_depth; _PyASTOptimizeState state; state.optimize = optimize; state.ff_features = ff_features; /* Setup recursion depth check counters */ tstate = _PyThreadState_GET(); if (!tstate) { return 0; } /* Be careful here to prevent overflow. */ int recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining; starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE; state.recursion_depth = starting_recursion_depth; state.recursion_limit = C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE; int ret = astfold_mod(mod, arena, &state); assert(ret || PyErr_Occurred()); /* Check that the recursion depth counting balanced correctly */ if (ret && state.recursion_depth != starting_recursion_depth) { PyErr_Format(PyExc_SystemError, "AST optimizer recursion depth mismatch (before=%d, after=%d)", starting_recursion_depth, state.recursion_depth); return 0; } return ret; } ================================================ FILE: Ast_Unparse.c ================================================ #include "Python.h" #include "pycore_ast.h" // expr_ty #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_runtime.h" // _Py_ID() #include // DBL_MAX_10_EXP #include /* This limited unparser is used to convert annotations back to strings * during compilation rather than being a full AST unparser. * See ast.unparse for a full unparser (written in Python) */ _Py_DECLARE_STR(open_br, "{"); _Py_DECLARE_STR(dbl_open_br, "{{"); _Py_DECLARE_STR(close_br, "}"); _Py_DECLARE_STR(dbl_close_br, "}}"); /* We would statically initialize this if doing so were simple enough. */ #define _str_replace_inf(interp) \ _Py_INTERP_CACHED_OBJECT(interp, str_replace_inf) /* Forward declarations for recursion via helper functions. */ static PyObject * expr_as_unicode(expr_ty e, int level); static int append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level); static int append_joinedstr(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec); static int append_formattedvalue(_PyUnicodeWriter *writer, expr_ty e); static int append_ast_slice(_PyUnicodeWriter *writer, expr_ty e); static int append_charp(_PyUnicodeWriter *writer, const char *charp) { return _PyUnicodeWriter_WriteASCIIString(writer, charp, -1); } #define APPEND_STR_FINISH(str) do { \ return append_charp(writer, (str)); \ } while (0) #define APPEND_STR(str) do { \ if (-1 == append_charp(writer, (str))) { \ return -1; \ } \ } while (0) #define APPEND_STR_IF(cond, str) do { \ if ((cond) && -1 == append_charp(writer, (str))) { \ return -1; \ } \ } while (0) #define APPEND_STR_IF_NOT_FIRST(str) do { \ APPEND_STR_IF(!first, (str)); \ first = false; \ } while (0) #define APPEND_EXPR(expr, pr) do { \ if (-1 == append_ast_expr(writer, (expr), (pr))) { \ return -1; \ } \ } while (0) #define APPEND(type, value) do { \ if (-1 == append_ast_ ## type(writer, (value))) { \ return -1; \ } \ } while (0) static int append_repr(_PyUnicodeWriter *writer, PyObject *obj) { PyObject *repr = PyObject_Repr(obj); if (!repr) { return -1; } if ((PyFloat_CheckExact(obj) && Py_IS_INFINITY(PyFloat_AS_DOUBLE(obj))) || PyComplex_CheckExact(obj)) { PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *new_repr = PyUnicode_Replace( repr, &_Py_ID(inf), _str_replace_inf(interp), -1 ); Py_DECREF(repr); if (!new_repr) { return -1; } repr = new_repr; } int ret = _PyUnicodeWriter_WriteStr(writer, repr); Py_DECREF(repr); return ret; } /* Priority levels */ enum { PR_TUPLE, PR_TEST, /* 'if'-'else', 'lambda' */ PR_OR, /* 'or' */ PR_AND, /* 'and' */ PR_NOT, /* 'not' */ PR_CMP, /* '<', '>', '==', '>=', '<=', '!=', 'in', 'not in', 'is', 'is not' */ PR_EXPR, PR_BOR = PR_EXPR, /* '|' */ PR_BXOR, /* '^' */ PR_BAND, /* '&' */ PR_SHIFT, /* '<<', '>>' */ PR_ARITH, /* '+', '-' */ PR_TERM, /* '*', '@', '/', '%', '//' */ PR_FACTOR, /* unary '+', '-', '~' */ PR_POWER, /* '**' */ PR_AWAIT, /* 'await' */ PR_ATOM, }; static int append_ast_boolop(_PyUnicodeWriter *writer, expr_ty e, int level) { Py_ssize_t i, value_count; asdl_expr_seq *values; const char *op = (e->v.BoolOp.op == And) ? " and " : " or "; int pr = (e->v.BoolOp.op == And) ? PR_AND : PR_OR; APPEND_STR_IF(level > pr, "("); values = e->v.BoolOp.values; value_count = asdl_seq_LEN(values); for (i = 0; i < value_count; ++i) { APPEND_STR_IF(i > 0, op); APPEND_EXPR((expr_ty)asdl_seq_GET(values, i), pr + 1); } APPEND_STR_IF(level > pr, ")"); return 0; } static int append_ast_binop(_PyUnicodeWriter *writer, expr_ty e, int level) { const char *op; int pr; bool rassoc = false; /* is right-associative? */ switch (e->v.BinOp.op) { case Add: op = " + "; pr = PR_ARITH; break; case Sub: op = " - "; pr = PR_ARITH; break; case Mult: op = " * "; pr = PR_TERM; break; case MatMult: op = " @ "; pr = PR_TERM; break; case Div: op = " / "; pr = PR_TERM; break; case Mod: op = " % "; pr = PR_TERM; break; case LShift: op = " << "; pr = PR_SHIFT; break; case RShift: op = " >> "; pr = PR_SHIFT; break; case BitOr: op = " | "; pr = PR_BOR; break; case BitXor: op = " ^ "; pr = PR_BXOR; break; case BitAnd: op = " & "; pr = PR_BAND; break; case FloorDiv: op = " // "; pr = PR_TERM; break; case Pow: op = " ** "; pr = PR_POWER; rassoc = true; break; default: PyErr_SetString(PyExc_SystemError, "unknown binary operator"); return -1; } APPEND_STR_IF(level > pr, "("); APPEND_EXPR(e->v.BinOp.left, pr + rassoc); APPEND_STR(op); APPEND_EXPR(e->v.BinOp.right, pr + !rassoc); APPEND_STR_IF(level > pr, ")"); return 0; } static int append_ast_unaryop(_PyUnicodeWriter *writer, expr_ty e, int level) { const char *op; int pr; switch (e->v.UnaryOp.op) { case Invert: op = "~"; pr = PR_FACTOR; break; case Not: op = "not "; pr = PR_NOT; break; case UAdd: op = "+"; pr = PR_FACTOR; break; case USub: op = "-"; pr = PR_FACTOR; break; default: PyErr_SetString(PyExc_SystemError, "unknown unary operator"); return -1; } APPEND_STR_IF(level > pr, "("); APPEND_STR(op); APPEND_EXPR(e->v.UnaryOp.operand, pr); APPEND_STR_IF(level > pr, ")"); return 0; } static int append_ast_arg(_PyUnicodeWriter *writer, arg_ty arg) { if (-1 == _PyUnicodeWriter_WriteStr(writer, arg->arg)) { return -1; } if (arg->annotation) { APPEND_STR(": "); APPEND_EXPR(arg->annotation, PR_TEST); } return 0; } static int append_ast_args(_PyUnicodeWriter *writer, arguments_ty args) { bool first; Py_ssize_t i, di, arg_count, posonlyarg_count, default_count; first = true; /* positional-only and positional arguments with defaults */ posonlyarg_count = asdl_seq_LEN(args->posonlyargs); arg_count = asdl_seq_LEN(args->args); default_count = asdl_seq_LEN(args->defaults); for (i = 0; i < posonlyarg_count + arg_count; i++) { APPEND_STR_IF_NOT_FIRST(", "); if (i < posonlyarg_count){ APPEND(arg, (arg_ty)asdl_seq_GET(args->posonlyargs, i)); } else { APPEND(arg, (arg_ty)asdl_seq_GET(args->args, i-posonlyarg_count)); } di = i - posonlyarg_count - arg_count + default_count; if (di >= 0) { APPEND_STR("="); APPEND_EXPR((expr_ty)asdl_seq_GET(args->defaults, di), PR_TEST); } if (posonlyarg_count && i + 1 == posonlyarg_count) { APPEND_STR(", /"); } } /* vararg, or bare '*' if no varargs but keyword-only arguments present */ if (args->vararg || asdl_seq_LEN(args->kwonlyargs)) { APPEND_STR_IF_NOT_FIRST(", "); APPEND_STR("*"); if (args->vararg) { APPEND(arg, args->vararg); } } /* keyword-only arguments */ arg_count = asdl_seq_LEN(args->kwonlyargs); default_count = asdl_seq_LEN(args->kw_defaults); for (i = 0; i < arg_count; i++) { APPEND_STR_IF_NOT_FIRST(", "); APPEND(arg, (arg_ty)asdl_seq_GET(args->kwonlyargs, i)); di = i - arg_count + default_count; if (di >= 0) { expr_ty default_ = (expr_ty)asdl_seq_GET(args->kw_defaults, di); if (default_) { APPEND_STR("="); APPEND_EXPR(default_, PR_TEST); } } } /* **kwargs */ if (args->kwarg) { APPEND_STR_IF_NOT_FIRST(", "); APPEND_STR("**"); APPEND(arg, args->kwarg); } return 0; } static int append_ast_lambda(_PyUnicodeWriter *writer, expr_ty e, int level) { APPEND_STR_IF(level > PR_TEST, "("); Py_ssize_t n_positional = (asdl_seq_LEN(e->v.Lambda.args->args) + asdl_seq_LEN(e->v.Lambda.args->posonlyargs)); APPEND_STR(n_positional ? "lambda " : "lambda"); APPEND(args, e->v.Lambda.args); APPEND_STR(": "); APPEND_EXPR(e->v.Lambda.body, PR_TEST); APPEND_STR_IF(level > PR_TEST, ")"); return 0; } static int append_ast_ifexp(_PyUnicodeWriter *writer, expr_ty e, int level) { APPEND_STR_IF(level > PR_TEST, "("); APPEND_EXPR(e->v.IfExp.body, PR_TEST + 1); APPEND_STR(" if "); APPEND_EXPR(e->v.IfExp.test, PR_TEST + 1); APPEND_STR(" else "); APPEND_EXPR(e->v.IfExp.orelse, PR_TEST); APPEND_STR_IF(level > PR_TEST, ")"); return 0; } static int append_ast_dict(_PyUnicodeWriter *writer, expr_ty e) { Py_ssize_t i, value_count; expr_ty key_node; APPEND_STR("{"); value_count = asdl_seq_LEN(e->v.Dict.values); for (i = 0; i < value_count; i++) { APPEND_STR_IF(i > 0, ", "); key_node = (expr_ty)asdl_seq_GET(e->v.Dict.keys, i); if (key_node != NULL) { APPEND_EXPR(key_node, PR_TEST); APPEND_STR(": "); APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Dict.values, i), PR_TEST); } else { APPEND_STR("**"); APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Dict.values, i), PR_EXPR); } } APPEND_STR_FINISH("}"); } static int append_ast_set(_PyUnicodeWriter *writer, expr_ty e) { Py_ssize_t i, elem_count; APPEND_STR("{"); elem_count = asdl_seq_LEN(e->v.Set.elts); for (i = 0; i < elem_count; i++) { APPEND_STR_IF(i > 0, ", "); APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Set.elts, i), PR_TEST); } APPEND_STR_FINISH("}"); } static int append_ast_list(_PyUnicodeWriter *writer, expr_ty e) { Py_ssize_t i, elem_count; APPEND_STR("["); elem_count = asdl_seq_LEN(e->v.List.elts); for (i = 0; i < elem_count; i++) { APPEND_STR_IF(i > 0, ", "); APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.List.elts, i), PR_TEST); } APPEND_STR_FINISH("]"); } static int append_ast_tuple(_PyUnicodeWriter *writer, expr_ty e, int level) { Py_ssize_t i, elem_count; elem_count = asdl_seq_LEN(e->v.Tuple.elts); if (elem_count == 0) { APPEND_STR_FINISH("()"); } APPEND_STR_IF(level > PR_TUPLE, "("); for (i = 0; i < elem_count; i++) { APPEND_STR_IF(i > 0, ", "); APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Tuple.elts, i), PR_TEST); } APPEND_STR_IF(elem_count == 1, ","); APPEND_STR_IF(level > PR_TUPLE, ")"); return 0; } static int append_ast_comprehension(_PyUnicodeWriter *writer, comprehension_ty gen) { Py_ssize_t i, if_count; APPEND_STR(gen->is_async ? " async for " : " for "); APPEND_EXPR(gen->target, PR_TUPLE); APPEND_STR(" in "); APPEND_EXPR(gen->iter, PR_TEST + 1); if_count = asdl_seq_LEN(gen->ifs); for (i = 0; i < if_count; i++) { APPEND_STR(" if "); APPEND_EXPR((expr_ty)asdl_seq_GET(gen->ifs, i), PR_TEST + 1); } return 0; } static int append_ast_comprehensions(_PyUnicodeWriter *writer, asdl_comprehension_seq *comprehensions) { Py_ssize_t i, gen_count; gen_count = asdl_seq_LEN(comprehensions); for (i = 0; i < gen_count; i++) { APPEND(comprehension, (comprehension_ty)asdl_seq_GET(comprehensions, i)); } return 0; } static int append_ast_genexp(_PyUnicodeWriter *writer, expr_ty e) { APPEND_STR("("); APPEND_EXPR(e->v.GeneratorExp.elt, PR_TEST); APPEND(comprehensions, e->v.GeneratorExp.generators); APPEND_STR_FINISH(")"); } static int append_ast_listcomp(_PyUnicodeWriter *writer, expr_ty e) { APPEND_STR("["); APPEND_EXPR(e->v.ListComp.elt, PR_TEST); APPEND(comprehensions, e->v.ListComp.generators); APPEND_STR_FINISH("]"); } static int append_ast_setcomp(_PyUnicodeWriter *writer, expr_ty e) { APPEND_STR("{"); APPEND_EXPR(e->v.SetComp.elt, PR_TEST); APPEND(comprehensions, e->v.SetComp.generators); APPEND_STR_FINISH("}"); } static int append_ast_dictcomp(_PyUnicodeWriter *writer, expr_ty e) { APPEND_STR("{"); APPEND_EXPR(e->v.DictComp.key, PR_TEST); APPEND_STR(": "); APPEND_EXPR(e->v.DictComp.value, PR_TEST); APPEND(comprehensions, e->v.DictComp.generators); APPEND_STR_FINISH("}"); } static int append_ast_compare(_PyUnicodeWriter *writer, expr_ty e, int level) { const char *op; Py_ssize_t i, comparator_count; asdl_expr_seq *comparators; asdl_int_seq *ops; APPEND_STR_IF(level > PR_CMP, "("); comparators = e->v.Compare.comparators; ops = e->v.Compare.ops; comparator_count = asdl_seq_LEN(comparators); assert(comparator_count > 0); assert(comparator_count == asdl_seq_LEN(ops)); APPEND_EXPR(e->v.Compare.left, PR_CMP + 1); for (i = 0; i < comparator_count; i++) { switch ((cmpop_ty)asdl_seq_GET(ops, i)) { case Eq: op = " == "; break; case NotEq: op = " != "; break; case Lt: op = " < "; break; case LtE: op = " <= "; break; case Gt: op = " > "; break; case GtE: op = " >= "; break; case Is: op = " is "; break; case IsNot: op = " is not "; break; case In: op = " in "; break; case NotIn: op = " not in "; break; default: PyErr_SetString(PyExc_SystemError, "unexpected comparison kind"); return -1; } APPEND_STR(op); APPEND_EXPR((expr_ty)asdl_seq_GET(comparators, i), PR_CMP + 1); } APPEND_STR_IF(level > PR_CMP, ")"); return 0; } static int append_ast_keyword(_PyUnicodeWriter *writer, keyword_ty kw) { if (kw->arg == NULL) { APPEND_STR("**"); } else { if (-1 == _PyUnicodeWriter_WriteStr(writer, kw->arg)) { return -1; } APPEND_STR("="); } APPEND_EXPR(kw->value, PR_TEST); return 0; } static int append_ast_call(_PyUnicodeWriter *writer, expr_ty e) { bool first; Py_ssize_t i, arg_count, kw_count; expr_ty expr; APPEND_EXPR(e->v.Call.func, PR_ATOM); arg_count = asdl_seq_LEN(e->v.Call.args); kw_count = asdl_seq_LEN(e->v.Call.keywords); if (arg_count == 1 && kw_count == 0) { expr = (expr_ty)asdl_seq_GET(e->v.Call.args, 0); if (expr->kind == GeneratorExp_kind) { /* Special case: a single generator expression. */ return append_ast_genexp(writer, expr); } } APPEND_STR("("); first = true; for (i = 0; i < arg_count; i++) { APPEND_STR_IF_NOT_FIRST(", "); APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Call.args, i), PR_TEST); } for (i = 0; i < kw_count; i++) { APPEND_STR_IF_NOT_FIRST(", "); APPEND(keyword, (keyword_ty)asdl_seq_GET(e->v.Call.keywords, i)); } APPEND_STR_FINISH(")"); } static PyObject * escape_braces(PyObject *orig) { PyObject *temp; PyObject *result; temp = PyUnicode_Replace(orig, &_Py_STR(open_br), &_Py_STR(dbl_open_br), -1); if (!temp) { return NULL; } result = PyUnicode_Replace(temp, &_Py_STR(close_br), &_Py_STR(dbl_close_br), -1); Py_DECREF(temp); return result; } static int append_fstring_unicode(_PyUnicodeWriter *writer, PyObject *unicode) { PyObject *escaped; int result = -1; escaped = escape_braces(unicode); if (escaped) { result = _PyUnicodeWriter_WriteStr(writer, escaped); Py_DECREF(escaped); } return result; } static int append_fstring_element(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) { switch (e->kind) { case Constant_kind: return append_fstring_unicode(writer, e->v.Constant.value); case JoinedStr_kind: return append_joinedstr(writer, e, is_format_spec); case FormattedValue_kind: return append_formattedvalue(writer, e); default: PyErr_SetString(PyExc_SystemError, "unknown expression kind inside f-string"); return -1; } } /* Build body separately to enable wrapping the entire stream of Strs, Constants and FormattedValues in one opening and one closing quote. */ static PyObject * build_fstring_body(asdl_expr_seq *values, bool is_format_spec) { Py_ssize_t i, value_count; _PyUnicodeWriter body_writer; _PyUnicodeWriter_Init(&body_writer); body_writer.min_length = 256; body_writer.overallocate = 1; value_count = asdl_seq_LEN(values); for (i = 0; i < value_count; ++i) { if (-1 == append_fstring_element(&body_writer, (expr_ty)asdl_seq_GET(values, i), is_format_spec )) { _PyUnicodeWriter_Dealloc(&body_writer); return NULL; } } return _PyUnicodeWriter_Finish(&body_writer); } static int append_joinedstr(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) { int result = -1; PyObject *body = build_fstring_body(e->v.JoinedStr.values, is_format_spec); if (!body) { return -1; } if (!is_format_spec) { if (-1 != append_charp(writer, "f") && -1 != append_repr(writer, body)) { result = 0; } } else { result = _PyUnicodeWriter_WriteStr(writer, body); } Py_DECREF(body); return result; } static int append_formattedvalue(_PyUnicodeWriter *writer, expr_ty e) { const char *conversion; const char *outer_brace = "{"; /* Grammar allows PR_TUPLE, but use >PR_TEST for adding parenthesis around a lambda with ':' */ PyObject *temp_fv_str = expr_as_unicode(e->v.FormattedValue.value, PR_TEST + 1); if (!temp_fv_str) { return -1; } if (PyUnicode_Find(temp_fv_str, &_Py_STR(open_br), 0, 1, 1) == 0) { /* Expression starts with a brace, split it with a space from the outer one. */ outer_brace = "{ "; } if (-1 == append_charp(writer, outer_brace)) { Py_DECREF(temp_fv_str); return -1; } if (-1 == _PyUnicodeWriter_WriteStr(writer, temp_fv_str)) { Py_DECREF(temp_fv_str); return -1; } Py_DECREF(temp_fv_str); if (e->v.FormattedValue.conversion > 0) { switch (e->v.FormattedValue.conversion) { case 'a': conversion = "!a"; break; case 'r': conversion = "!r"; break; case 's': conversion = "!s"; break; default: PyErr_SetString(PyExc_SystemError, "unknown f-value conversion kind"); return -1; } APPEND_STR(conversion); } if (e->v.FormattedValue.format_spec) { if (-1 == _PyUnicodeWriter_WriteASCIIString(writer, ":", 1) || -1 == append_fstring_element(writer, e->v.FormattedValue.format_spec, true )) { return -1; } } APPEND_STR_FINISH("}"); } static int append_ast_constant(_PyUnicodeWriter *writer, PyObject *constant) { if (PyTuple_CheckExact(constant)) { Py_ssize_t i, elem_count; elem_count = PyTuple_GET_SIZE(constant); APPEND_STR("("); for (i = 0; i < elem_count; i++) { APPEND_STR_IF(i > 0, ", "); if (append_ast_constant(writer, PyTuple_GET_ITEM(constant, i)) < 0) { return -1; } } APPEND_STR_IF(elem_count == 1, ","); APPEND_STR(")"); return 0; } return append_repr(writer, constant); } static int append_ast_attribute(_PyUnicodeWriter *writer, expr_ty e) { const char *period; expr_ty v = e->v.Attribute.value; APPEND_EXPR(v, PR_ATOM); /* Special case: integers require a space for attribute access to be unambiguous. */ if (v->kind == Constant_kind && PyLong_CheckExact(v->v.Constant.value)) { period = " ."; } else { period = "."; } APPEND_STR(period); return _PyUnicodeWriter_WriteStr(writer, e->v.Attribute.attr); } static int append_ast_slice(_PyUnicodeWriter *writer, expr_ty e) { if (e->v.Slice.lower) { APPEND_EXPR(e->v.Slice.lower, PR_TEST); } APPEND_STR(":"); if (e->v.Slice.upper) { APPEND_EXPR(e->v.Slice.upper, PR_TEST); } if (e->v.Slice.step) { APPEND_STR(":"); APPEND_EXPR(e->v.Slice.step, PR_TEST); } return 0; } static int append_ast_subscript(_PyUnicodeWriter *writer, expr_ty e) { APPEND_EXPR(e->v.Subscript.value, PR_ATOM); APPEND_STR("["); APPEND_EXPR(e->v.Subscript.slice, PR_TUPLE); APPEND_STR_FINISH("]"); } static int append_ast_starred(_PyUnicodeWriter *writer, expr_ty e) { APPEND_STR("*"); APPEND_EXPR(e->v.Starred.value, PR_EXPR); return 0; } static int append_ast_yield(_PyUnicodeWriter *writer, expr_ty e) { if (!e->v.Yield.value) { APPEND_STR_FINISH("(yield)"); } APPEND_STR("(yield "); APPEND_EXPR(e->v.Yield.value, PR_TEST); APPEND_STR_FINISH(")"); } static int append_ast_yield_from(_PyUnicodeWriter *writer, expr_ty e) { APPEND_STR("(yield from "); APPEND_EXPR(e->v.YieldFrom.value, PR_TEST); APPEND_STR_FINISH(")"); } static int append_ast_await(_PyUnicodeWriter *writer, expr_ty e, int level) { APPEND_STR_IF(level > PR_AWAIT, "("); APPEND_STR("await "); APPEND_EXPR(e->v.Await.value, PR_ATOM); APPEND_STR_IF(level > PR_AWAIT, ")"); return 0; } static int append_named_expr(_PyUnicodeWriter *writer, expr_ty e, int level) { APPEND_STR_IF(level > PR_TUPLE, "("); APPEND_EXPR(e->v.NamedExpr.target, PR_ATOM); APPEND_STR(" := "); APPEND_EXPR(e->v.NamedExpr.value, PR_ATOM); APPEND_STR_IF(level > PR_TUPLE, ")"); return 0; } static int append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level) { switch (e->kind) { case BoolOp_kind: return append_ast_boolop(writer, e, level); case BinOp_kind: return append_ast_binop(writer, e, level); case UnaryOp_kind: return append_ast_unaryop(writer, e, level); case Lambda_kind: return append_ast_lambda(writer, e, level); case IfExp_kind: return append_ast_ifexp(writer, e, level); case Dict_kind: return append_ast_dict(writer, e); case Set_kind: return append_ast_set(writer, e); case GeneratorExp_kind: return append_ast_genexp(writer, e); case ListComp_kind: return append_ast_listcomp(writer, e); case SetComp_kind: return append_ast_setcomp(writer, e); case DictComp_kind: return append_ast_dictcomp(writer, e); case Yield_kind: return append_ast_yield(writer, e); case YieldFrom_kind: return append_ast_yield_from(writer, e); case Await_kind: return append_ast_await(writer, e, level); case Compare_kind: return append_ast_compare(writer, e, level); case Call_kind: return append_ast_call(writer, e); case Constant_kind: if (e->v.Constant.value == Py_Ellipsis) { APPEND_STR_FINISH("..."); } if (e->v.Constant.kind != NULL && -1 == _PyUnicodeWriter_WriteStr(writer, e->v.Constant.kind)) { return -1; } return append_ast_constant(writer, e->v.Constant.value); case JoinedStr_kind: return append_joinedstr(writer, e, false); case FormattedValue_kind: return append_formattedvalue(writer, e); /* The following exprs can be assignment targets. */ case Attribute_kind: return append_ast_attribute(writer, e); case Subscript_kind: return append_ast_subscript(writer, e); case Starred_kind: return append_ast_starred(writer, e); case Slice_kind: return append_ast_slice(writer, e); case Name_kind: return _PyUnicodeWriter_WriteStr(writer, e->v.Name.id); case List_kind: return append_ast_list(writer, e); case Tuple_kind: return append_ast_tuple(writer, e, level); case NamedExpr_kind: return append_named_expr(writer, e, level); // No default so compiler emits a warning for unhandled cases } PyErr_SetString(PyExc_SystemError, "unknown expression kind"); return -1; } static int maybe_init_static_strings(void) { PyInterpreterState *interp = _PyInterpreterState_GET(); if (_str_replace_inf(interp) == NULL) { PyObject *tmp = PyUnicode_FromFormat("1e%d", 1 + DBL_MAX_10_EXP); if (tmp == NULL) { return -1; } _str_replace_inf(interp) = tmp; } return 0; } static PyObject * expr_as_unicode(expr_ty e, int level) { _PyUnicodeWriter writer; _PyUnicodeWriter_Init(&writer); writer.min_length = 256; writer.overallocate = 1; if (-1 == maybe_init_static_strings() || -1 == append_ast_expr(&writer, e, level)) { _PyUnicodeWriter_Dealloc(&writer); return NULL; } return _PyUnicodeWriter_Finish(&writer); } PyObject * _PyAST_ExprAsUnicode(expr_ty e) { return expr_as_unicode(e, PR_TEST); } ================================================ FILE: BltinModule.c ================================================ /* Built-in functions */ #include "Python.h" #include #include "pycore_ast.h" // _PyAST_Validate() #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_compile.h" // _PyAST_Compile() #include "pycore_long.h" // _PyLong_CompactValue #include "pycore_object.h" // _Py_AddToAllObjects() #include "pycore_pyerrors.h" // _PyErr_NoMemory() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_tuple.h" // _PyTuple_FromArray() #include "pycore_ceval.h" // _PyEval_Vector() #include "clinic/bltinmodule.c.h" static PyObject* update_bases(PyObject *bases, PyObject *const *args, Py_ssize_t nargs) { Py_ssize_t i, j; PyObject *base, *meth, *new_base, *result, *new_bases = NULL; assert(PyTuple_Check(bases)); for (i = 0; i < nargs; i++) { base = args[i]; if (PyType_Check(base)) { if (new_bases) { /* If we already have made a replacement, then we append every normal base, otherwise just skip it. */ if (PyList_Append(new_bases, base) < 0) { goto error; } } continue; } if (_PyObject_LookupAttr(base, &_Py_ID(__mro_entries__), &meth) < 0) { goto error; } if (!meth) { if (new_bases) { if (PyList_Append(new_bases, base) < 0) { goto error; } } continue; } new_base = PyObject_CallOneArg(meth, bases); Py_DECREF(meth); if (!new_base) { goto error; } if (!PyTuple_Check(new_base)) { PyErr_SetString(PyExc_TypeError, "__mro_entries__ must return a tuple"); Py_DECREF(new_base); goto error; } if (!new_bases) { /* If this is a first successful replacement, create new_bases list and copy previously encountered bases. */ if (!(new_bases = PyList_New(i))) { Py_DECREF(new_base); goto error; } for (j = 0; j < i; j++) { base = args[j]; PyList_SET_ITEM(new_bases, j, Py_NewRef(base)); } } j = PyList_GET_SIZE(new_bases); if (PyList_SetSlice(new_bases, j, j, new_base) < 0) { Py_DECREF(new_base); goto error; } Py_DECREF(new_base); } if (!new_bases) { return bases; } result = PyList_AsTuple(new_bases); Py_DECREF(new_bases); return result; error: Py_XDECREF(new_bases); return NULL; } /* AC: cannot convert yet, waiting for *args support */ static PyObject * builtin___build_class__(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *func, *name, *winner, *prep; PyObject *cls = NULL, *cell = NULL, *ns = NULL, *meta = NULL, *orig_bases = NULL; PyObject *mkw = NULL, *bases = NULL; int isclass = 0; /* initialize to prevent gcc warning */ if (nargs < 2) { PyErr_SetString(PyExc_TypeError, "__build_class__: not enough arguments"); return NULL; } func = args[0]; /* Better be callable */ if (!PyFunction_Check(func)) { PyErr_SetString(PyExc_TypeError, "__build_class__: func must be a function"); return NULL; } name = args[1]; if (!PyUnicode_Check(name)) { PyErr_SetString(PyExc_TypeError, "__build_class__: name is not a string"); return NULL; } orig_bases = _PyTuple_FromArray(args + 2, nargs - 2); if (orig_bases == NULL) return NULL; bases = update_bases(orig_bases, args + 2, nargs - 2); if (bases == NULL) { Py_DECREF(orig_bases); return NULL; } if (kwnames == NULL) { meta = NULL; mkw = NULL; } else { mkw = _PyStack_AsDict(args + nargs, kwnames); if (mkw == NULL) { goto error; } meta = _PyDict_GetItemWithError(mkw, &_Py_ID(metaclass)); if (meta != NULL) { Py_INCREF(meta); if (PyDict_DelItem(mkw, &_Py_ID(metaclass)) < 0) { goto error; } /* metaclass is explicitly given, check if it's indeed a class */ isclass = PyType_Check(meta); } else if (PyErr_Occurred()) { goto error; } } if (meta == NULL) { /* if there are no bases, use type: */ if (PyTuple_GET_SIZE(bases) == 0) { meta = (PyObject *) (&PyType_Type); } /* else get the type of the first base */ else { PyObject *base0 = PyTuple_GET_ITEM(bases, 0); meta = (PyObject *)Py_TYPE(base0); } Py_INCREF(meta); isclass = 1; /* meta is really a class */ } if (isclass) { /* meta is really a class, so check for a more derived metaclass, or possible metaclass conflicts: */ winner = (PyObject *)_PyType_CalculateMetaclass((PyTypeObject *)meta, bases); if (winner == NULL) { goto error; } if (winner != meta) { Py_SETREF(meta, Py_NewRef(winner)); } } /* else: meta is not a class, so we cannot do the metaclass calculation, so we will use the explicitly given object as it is */ if (_PyObject_LookupAttr(meta, &_Py_ID(__prepare__), &prep) < 0) { ns = NULL; } else if (prep == NULL) { ns = PyDict_New(); } else { PyObject *pargs[2] = {name, bases}; ns = PyObject_VectorcallDict(prep, pargs, 2, mkw); Py_DECREF(prep); } if (ns == NULL) { goto error; } if (!PyMapping_Check(ns)) { PyErr_Format(PyExc_TypeError, "%.200s.__prepare__() must return a mapping, not %.200s", isclass ? ((PyTypeObject *)meta)->tp_name : "", Py_TYPE(ns)->tp_name); goto error; } PyThreadState *tstate = _PyThreadState_GET(); EVAL_CALL_STAT_INC(EVAL_CALL_BUILD_CLASS); cell = _PyEval_Vector(tstate, (PyFunctionObject *)func, ns, NULL, 0, NULL); if (cell != NULL) { if (bases != orig_bases) { if (PyMapping_SetItemString(ns, "__orig_bases__", orig_bases) < 0) { goto error; } } PyObject *margs[3] = {name, bases, ns}; cls = PyObject_VectorcallDict(meta, margs, 3, mkw); if (cls != NULL && PyType_Check(cls) && PyCell_Check(cell)) { PyObject *cell_cls = PyCell_GET(cell); if (cell_cls != cls) { if (cell_cls == NULL) { const char *msg = "__class__ not set defining %.200R as %.200R. " "Was __classcell__ propagated to type.__new__?"; PyErr_Format(PyExc_RuntimeError, msg, name, cls); } else { const char *msg = "__class__ set to %.200R defining %.200R as %.200R"; PyErr_Format(PyExc_TypeError, msg, cell_cls, name, cls); } Py_SETREF(cls, NULL); goto error; } } } error: Py_XDECREF(cell); Py_XDECREF(ns); Py_XDECREF(meta); Py_XDECREF(mkw); if (bases != orig_bases) { Py_DECREF(orig_bases); } Py_DECREF(bases); return cls; } PyDoc_STRVAR(build_class_doc, "__build_class__(func, name, /, *bases, [metaclass], **kwds) -> class\n\ \n\ Internal helper function used by the class statement."); /*[clinic input] __import__ as builtin___import__ name: object globals: object(c_default="NULL") = None locals: object(c_default="NULL") = None fromlist: object(c_default="NULL") = () level: int = 0 Import a module. Because this function is meant for use by the Python interpreter and not for general use, it is better to use importlib.import_module() to programmatically import a module. The globals argument is only used to determine the context; they are not modified. The locals argument is unused. The fromlist should be a list of names to emulate ``from name import ...``, or an empty list to emulate ``import name``. When importing a module from a package, note that __import__('A.B', ...) returns package A when fromlist is empty, but its submodule B when fromlist is not empty. The level argument is used to determine whether to perform absolute or relative imports: 0 is absolute, while a positive number is the number of parent directories to search relative to the current module. [clinic start generated code]*/ static PyObject * builtin___import___impl(PyObject *module, PyObject *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level) /*[clinic end generated code: output=4febeda88a0cd245 input=73f4b960ea5b9dd6]*/ { return PyImport_ImportModuleLevelObject(name, globals, locals, fromlist, level); } /*[clinic input] abs as builtin_abs x: object / Return the absolute value of the argument. [clinic start generated code]*/ static PyObject * builtin_abs(PyObject *module, PyObject *x) /*[clinic end generated code: output=b1b433b9e51356f5 input=bed4ca14e29c20d1]*/ { return PyNumber_Absolute(x); } /*[clinic input] all as builtin_all iterable: object / Return True if bool(x) is True for all values x in the iterable. If the iterable is empty, return True. [clinic start generated code]*/ static PyObject * builtin_all(PyObject *module, PyObject *iterable) /*[clinic end generated code: output=ca2a7127276f79b3 input=1a7c5d1bc3438a21]*/ { PyObject *it, *item; PyObject *(*iternext)(PyObject *); int cmp; it = PyObject_GetIter(iterable); if (it == NULL) return NULL; iternext = *Py_TYPE(it)->tp_iternext; for (;;) { item = iternext(it); if (item == NULL) break; cmp = PyObject_IsTrue(item); Py_DECREF(item); if (cmp < 0) { Py_DECREF(it); return NULL; } if (cmp == 0) { Py_DECREF(it); Py_RETURN_FALSE; } } Py_DECREF(it); if (PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear(); else return NULL; } Py_RETURN_TRUE; } /*[clinic input] any as builtin_any iterable: object / Return True if bool(x) is True for any x in the iterable. If the iterable is empty, return False. [clinic start generated code]*/ static PyObject * builtin_any(PyObject *module, PyObject *iterable) /*[clinic end generated code: output=fa65684748caa60e input=41d7451c23384f24]*/ { PyObject *it, *item; PyObject *(*iternext)(PyObject *); int cmp; it = PyObject_GetIter(iterable); if (it == NULL) return NULL; iternext = *Py_TYPE(it)->tp_iternext; for (;;) { item = iternext(it); if (item == NULL) break; cmp = PyObject_IsTrue(item); Py_DECREF(item); if (cmp < 0) { Py_DECREF(it); return NULL; } if (cmp > 0) { Py_DECREF(it); Py_RETURN_TRUE; } } Py_DECREF(it); if (PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear(); else return NULL; } Py_RETURN_FALSE; } /*[clinic input] ascii as builtin_ascii obj: object / Return an ASCII-only representation of an object. As repr(), return a string containing a printable representation of an object, but escape the non-ASCII characters in the string returned by repr() using \\x, \\u or \\U escapes. This generates a string similar to that returned by repr() in Python 2. [clinic start generated code]*/ static PyObject * builtin_ascii(PyObject *module, PyObject *obj) /*[clinic end generated code: output=6d37b3f0984c7eb9 input=4c62732e1b3a3cc9]*/ { return PyObject_ASCII(obj); } /*[clinic input] bin as builtin_bin number: object / Return the binary representation of an integer. >>> bin(2796202) '0b1010101010101010101010' [clinic start generated code]*/ static PyObject * builtin_bin(PyObject *module, PyObject *number) /*[clinic end generated code: output=b6fc4ad5e649f4f7 input=53f8a0264bacaf90]*/ { return PyNumber_ToBase(number, 2); } /*[clinic input] callable as builtin_callable obj: object / Return whether the object is callable (i.e., some kind of function). Note that classes are callable, as are instances of classes with a __call__() method. [clinic start generated code]*/ static PyObject * builtin_callable(PyObject *module, PyObject *obj) /*[clinic end generated code: output=2b095d59d934cb7e input=1423bab99cc41f58]*/ { return PyBool_FromLong((long)PyCallable_Check(obj)); } static PyObject * builtin_breakpoint(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *keywords) { PyObject *hook = PySys_GetObject("breakpointhook"); if (hook == NULL) { PyErr_SetString(PyExc_RuntimeError, "lost sys.breakpointhook"); return NULL; } if (PySys_Audit("builtins.breakpoint", "O", hook) < 0) { return NULL; } Py_INCREF(hook); PyObject *retval = PyObject_Vectorcall(hook, args, nargs, keywords); Py_DECREF(hook); return retval; } PyDoc_STRVAR(breakpoint_doc, "breakpoint(*args, **kws)\n\ \n\ Call sys.breakpointhook(*args, **kws). sys.breakpointhook() must accept\n\ whatever arguments are passed.\n\ \n\ By default, this drops you into the pdb debugger."); typedef struct { PyObject_HEAD PyObject *func; PyObject *it; } filterobject; static PyObject * filter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *func, *seq; PyObject *it; filterobject *lz; if ((type == &PyFilter_Type || type->tp_init == PyFilter_Type.tp_init) && !_PyArg_NoKeywords("filter", kwds)) return NULL; if (!PyArg_UnpackTuple(args, "filter", 2, 2, &func, &seq)) return NULL; /* Get iterator. */ it = PyObject_GetIter(seq); if (it == NULL) return NULL; /* create filterobject structure */ lz = (filterobject *)type->tp_alloc(type, 0); if (lz == NULL) { Py_DECREF(it); return NULL; } lz->func = Py_NewRef(func); lz->it = it; return (PyObject *)lz; } static PyObject * filter_vectorcall(PyObject *type, PyObject * const*args, size_t nargsf, PyObject *kwnames) { PyTypeObject *tp = _PyType_CAST(type); if (tp == &PyFilter_Type && !_PyArg_NoKwnames("filter", kwnames)) { return NULL; } Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); if (!_PyArg_CheckPositional("filter", nargs, 2, 2)) { return NULL; } PyObject *it = PyObject_GetIter(args[1]); if (it == NULL) { return NULL; } filterobject *lz = (filterobject *)tp->tp_alloc(tp, 0); if (lz == NULL) { Py_DECREF(it); return NULL; } lz->func = Py_NewRef(args[0]); lz->it = it; return (PyObject *)lz; } static void filter_dealloc(filterobject *lz) { PyObject_GC_UnTrack(lz); Py_TRASHCAN_BEGIN(lz, filter_dealloc) Py_XDECREF(lz->func); Py_XDECREF(lz->it); Py_TYPE(lz)->tp_free(lz); Py_TRASHCAN_END } static int filter_traverse(filterobject *lz, visitproc visit, void *arg) { Py_VISIT(lz->it); Py_VISIT(lz->func); return 0; } static PyObject * filter_next(filterobject *lz) { PyObject *item; PyObject *it = lz->it; long ok; PyObject *(*iternext)(PyObject *); int checktrue = lz->func == Py_None || lz->func == (PyObject *)&PyBool_Type; iternext = *Py_TYPE(it)->tp_iternext; for (;;) { item = iternext(it); if (item == NULL) return NULL; if (checktrue) { ok = PyObject_IsTrue(item); } else { PyObject *good; good = PyObject_CallOneArg(lz->func, item); if (good == NULL) { Py_DECREF(item); return NULL; } ok = PyObject_IsTrue(good); Py_DECREF(good); } if (ok > 0) return item; Py_DECREF(item); if (ok < 0) return NULL; } } static PyObject * filter_reduce(filterobject *lz, PyObject *Py_UNUSED(ignored)) { return Py_BuildValue("O(OO)", Py_TYPE(lz), lz->func, lz->it); } PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); static PyMethodDef filter_methods[] = { {"__reduce__", _PyCFunction_CAST(filter_reduce), METH_NOARGS, reduce_doc}, {NULL, NULL} /* sentinel */ }; PyDoc_STRVAR(filter_doc, "filter(function or None, iterable) --> filter object\n\ \n\ Return an iterator yielding those items of iterable for which function(item)\n\ is true. If function is None, return the items that are true."); PyTypeObject PyFilter_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "filter", /* tp_name */ sizeof(filterobject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)filter_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags */ filter_doc, /* tp_doc */ (traverseproc)filter_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)filter_next, /* tp_iternext */ filter_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ filter_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ .tp_vectorcall = (vectorcallfunc)filter_vectorcall }; /*[clinic input] format as builtin_format value: object format_spec: unicode(c_default="NULL") = '' / Return type(value).__format__(value, format_spec) Many built-in types implement format_spec according to the Format Specification Mini-language. See help('FORMATTING'). If type(value) does not supply a method named __format__ and format_spec is empty, then str(value) is returned. See also help('SPECIALMETHODS'). [clinic start generated code]*/ static PyObject * builtin_format_impl(PyObject *module, PyObject *value, PyObject *format_spec) /*[clinic end generated code: output=2f40bdfa4954b077 input=45ef3934b86d5624]*/ { return PyObject_Format(value, format_spec); } /*[clinic input] chr as builtin_chr i: int / Return a Unicode string of one character with ordinal i; 0 <= i <= 0x10ffff. [clinic start generated code]*/ static PyObject * builtin_chr_impl(PyObject *module, int i) /*[clinic end generated code: output=c733afcd200afcb7 input=3f604ef45a70750d]*/ { return PyUnicode_FromOrdinal(i); } /*[clinic input] compile as builtin_compile source: object filename: object(converter="PyUnicode_FSDecoder") mode: str flags: int = 0 dont_inherit: bool = False optimize: int = -1 * _feature_version as feature_version: int = -1 Compile source into a code object that can be executed by exec() or eval(). The source code may represent a Python module, statement or expression. The filename will be used for run-time error messages. The mode must be 'exec' to compile a module, 'single' to compile a single (interactive) statement, or 'eval' to compile an expression. The flags argument, if present, controls which future statements influence the compilation of the code. The dont_inherit argument, if true, stops the compilation inheriting the effects of any future statements in effect in the code calling compile; if absent or false these statements do influence the compilation, in addition to any features explicitly specified. [clinic start generated code]*/ static PyObject * builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename, const char *mode, int flags, int dont_inherit, int optimize, int feature_version) /*[clinic end generated code: output=b0c09c84f116d3d7 input=cc78e20e7c7682ba]*/ { PyObject *source_copy; const char *str; int compile_mode = -1; int is_ast; int start[] = {Py_file_input, Py_eval_input, Py_single_input, Py_func_type_input}; PyObject *result; PyCompilerFlags cf = _PyCompilerFlags_INIT; cf.cf_flags = flags | PyCF_SOURCE_IS_UTF8; if (feature_version >= 0 && (flags & PyCF_ONLY_AST)) { cf.cf_feature_version = feature_version; } if (flags & ~(PyCF_MASK | PyCF_MASK_OBSOLETE | PyCF_COMPILE_MASK)) { PyErr_SetString(PyExc_ValueError, "compile(): unrecognised flags"); goto error; } /* XXX Warn if (supplied_flags & PyCF_MASK_OBSOLETE) != 0? */ if (optimize < -1 || optimize > 2) { PyErr_SetString(PyExc_ValueError, "compile(): invalid optimize value"); goto error; } if (!dont_inherit) { PyEval_MergeCompilerFlags(&cf); } if (strcmp(mode, "exec") == 0) compile_mode = 0; else if (strcmp(mode, "eval") == 0) compile_mode = 1; else if (strcmp(mode, "single") == 0) compile_mode = 2; else if (strcmp(mode, "func_type") == 0) { if (!(flags & PyCF_ONLY_AST)) { PyErr_SetString(PyExc_ValueError, "compile() mode 'func_type' requires flag PyCF_ONLY_AST"); goto error; } compile_mode = 3; } else { const char *msg; if (flags & PyCF_ONLY_AST) msg = "compile() mode must be 'exec', 'eval', 'single' or 'func_type'"; else msg = "compile() mode must be 'exec', 'eval' or 'single'"; PyErr_SetString(PyExc_ValueError, msg); goto error; } is_ast = PyAST_Check(source); if (is_ast == -1) goto error; if (is_ast) { if (flags & PyCF_ONLY_AST) { result = Py_NewRef(source); } else { PyArena *arena; mod_ty mod; arena = _PyArena_New(); if (arena == NULL) goto error; mod = PyAST_obj2mod(source, arena, compile_mode); if (mod == NULL || !_PyAST_Validate(mod)) { _PyArena_Free(arena); goto error; } result = (PyObject*)_PyAST_Compile(mod, filename, &cf, optimize, arena); _PyArena_Free(arena); } goto finally; } str = _Py_SourceAsString(source, "compile", "string, bytes or AST", &cf, &source_copy); if (str == NULL) goto error; result = Py_CompileStringObject(str, filename, start[compile_mode], &cf, optimize); Py_XDECREF(source_copy); goto finally; error: result = NULL; finally: Py_DECREF(filename); return result; } /*[clinic input] dir as builtin_dir arg: object = NULL / Show attributes of an object. If called without an argument, return the names in the current scope. Else, return an alphabetized list of names comprising (some of) the attributes of the given object, and of attributes reachable from it. If the object supplies a method named __dir__, it will be used; otherwise the default dir() logic is used and returns: for a module object: the module's attributes. for a class object: its attributes, and recursively the attributes of its bases. for any other object: its attributes, its class's attributes, and recursively the attributes of its class's base classes. [clinic start generated code]*/ static PyObject * builtin_dir_impl(PyObject *module, PyObject *arg) /*[clinic end generated code: output=24f2c7a52c1e3b08 input=ed6d6ccb13d52251]*/ { return PyObject_Dir(arg); } /*[clinic input] divmod as builtin_divmod x: object y: object / Return the tuple (x//y, x%y). Invariant: div*y + mod == x. [clinic start generated code]*/ static PyObject * builtin_divmod_impl(PyObject *module, PyObject *x, PyObject *y) /*[clinic end generated code: output=b06d8a5f6e0c745e input=175ad9c84ff41a85]*/ { return PyNumber_Divmod(x, y); } /*[clinic input] eval as builtin_eval source: object globals: object = None locals: object = None / Evaluate the given source in the context of globals and locals. The source may be a string representing a Python expression or a code object as returned by compile(). The globals must be a dictionary and locals can be any mapping, defaulting to the current globals and locals. If only globals is given, locals defaults to it. [clinic start generated code]*/ static PyObject * builtin_eval_impl(PyObject *module, PyObject *source, PyObject *globals, PyObject *locals) /*[clinic end generated code: output=0a0824aa70093116 input=11ee718a8640e527]*/ { PyObject *result, *source_copy; const char *str; if (locals != Py_None && !PyMapping_Check(locals)) { PyErr_SetString(PyExc_TypeError, "locals must be a mapping"); return NULL; } if (globals != Py_None && !PyDict_Check(globals)) { PyErr_SetString(PyExc_TypeError, PyMapping_Check(globals) ? "globals must be a real dict; try eval(expr, {}, mapping)" : "globals must be a dict"); return NULL; } if (globals == Py_None) { globals = PyEval_GetGlobals(); if (locals == Py_None) { locals = PyEval_GetLocals(); if (locals == NULL) return NULL; } } else if (locals == Py_None) locals = globals; if (globals == NULL || locals == NULL) { PyErr_SetString(PyExc_TypeError, "eval must be given globals and locals " "when called without a frame"); return NULL; } int r = PyDict_Contains(globals, &_Py_ID(__builtins__)); if (r == 0) { r = PyDict_SetItem(globals, &_Py_ID(__builtins__), PyEval_GetBuiltins()); } if (r < 0) { return NULL; } if (PyCode_Check(source)) { if (PySys_Audit("exec", "O", source) < 0) { return NULL; } if (PyCode_GetNumFree((PyCodeObject *)source) > 0) { PyErr_SetString(PyExc_TypeError, "code object passed to eval() may not contain free variables"); return NULL; } return PyEval_EvalCode(source, globals, locals); } PyCompilerFlags cf = _PyCompilerFlags_INIT; cf.cf_flags = PyCF_SOURCE_IS_UTF8; str = _Py_SourceAsString(source, "eval", "string, bytes or code", &cf, &source_copy); if (str == NULL) return NULL; while (*str == ' ' || *str == '\t') str++; (void)PyEval_MergeCompilerFlags(&cf); result = PyRun_StringFlags(str, Py_eval_input, globals, locals, &cf); Py_XDECREF(source_copy); return result; } /*[clinic input] exec as builtin_exec source: object globals: object = None locals: object = None / * closure: object(c_default="NULL") = None Execute the given source in the context of globals and locals. The source may be a string representing one or more Python statements or a code object as returned by compile(). The globals must be a dictionary and locals can be any mapping, defaulting to the current globals and locals. If only globals is given, locals defaults to it. The closure must be a tuple of cellvars, and can only be used when source is a code object requiring exactly that many cellvars. [clinic start generated code]*/ static PyObject * builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, PyObject *locals, PyObject *closure) /*[clinic end generated code: output=7579eb4e7646743d input=f13a7e2b503d1d9a]*/ { PyObject *v; if (globals == Py_None) { globals = PyEval_GetGlobals(); if (locals == Py_None) { locals = PyEval_GetLocals(); if (locals == NULL) return NULL; } if (!globals || !locals) { PyErr_SetString(PyExc_SystemError, "globals and locals cannot be NULL"); return NULL; } } else if (locals == Py_None) locals = globals; if (!PyDict_Check(globals)) { PyErr_Format(PyExc_TypeError, "exec() globals must be a dict, not %.100s", Py_TYPE(globals)->tp_name); return NULL; } if (!PyMapping_Check(locals)) { PyErr_Format(PyExc_TypeError, "locals must be a mapping or None, not %.100s", Py_TYPE(locals)->tp_name); return NULL; } int r = PyDict_Contains(globals, &_Py_ID(__builtins__)); if (r == 0) { r = PyDict_SetItem(globals, &_Py_ID(__builtins__), PyEval_GetBuiltins()); } if (r < 0) { return NULL; } if (closure == Py_None) { closure = NULL; } if (PyCode_Check(source)) { Py_ssize_t num_free = PyCode_GetNumFree((PyCodeObject *)source); if (num_free == 0) { if (closure) { PyErr_SetString(PyExc_TypeError, "cannot use a closure with this code object"); return NULL; } } else { int closure_is_ok = closure && PyTuple_CheckExact(closure) && (PyTuple_GET_SIZE(closure) == num_free); if (closure_is_ok) { for (Py_ssize_t i = 0; i < num_free; i++) { PyObject *cell = PyTuple_GET_ITEM(closure, i); if (!PyCell_Check(cell)) { closure_is_ok = 0; break; } } } if (!closure_is_ok) { PyErr_Format(PyExc_TypeError, "code object requires a closure of exactly length %zd", num_free); return NULL; } } if (PySys_Audit("exec", "O", source) < 0) { return NULL; } if (!closure) { v = PyEval_EvalCode(source, globals, locals); } else { v = PyEval_EvalCodeEx(source, globals, locals, NULL, 0, NULL, 0, NULL, 0, NULL, closure); } } else { if (closure != NULL) { PyErr_SetString(PyExc_TypeError, "closure can only be used when source is a code object"); } PyObject *source_copy; const char *str; PyCompilerFlags cf = _PyCompilerFlags_INIT; cf.cf_flags = PyCF_SOURCE_IS_UTF8; str = _Py_SourceAsString(source, "exec", "string, bytes or code", &cf, &source_copy); if (str == NULL) return NULL; if (PyEval_MergeCompilerFlags(&cf)) v = PyRun_StringFlags(str, Py_file_input, globals, locals, &cf); else v = PyRun_String(str, Py_file_input, globals, locals); Py_XDECREF(source_copy); } if (v == NULL) return NULL; Py_DECREF(v); Py_RETURN_NONE; } /*[clinic input] getattr as builtin_getattr object: object name: object default: object = NULL / Get a named attribute from an object. getattr(x, 'y') is equivalent to x.y When a default argument is given, it is returned when the attribute doesn't exist; without it, an exception is raised in that case. [clinic start generated code]*/ static PyObject * builtin_getattr_impl(PyObject *module, PyObject *object, PyObject *name, PyObject *default_value) /*[clinic end generated code: output=74ad0e225e3f701c input=d7562cd4c3556171]*/ { PyObject *result; if (default_value != NULL) { if (_PyObject_LookupAttr(object, name, &result) == 0) { return Py_NewRef(default_value); } } else { result = PyObject_GetAttr(object, name); } return result; } /*[clinic input] globals as builtin_globals Return the dictionary containing the current scope's global variables. NOTE: Updates to this dictionary *will* affect name lookups in the current global scope and vice-versa. [clinic start generated code]*/ static PyObject * builtin_globals_impl(PyObject *module) /*[clinic end generated code: output=e5dd1527067b94d2 input=9327576f92bb48ba]*/ { PyObject *d; d = PyEval_GetGlobals(); return Py_XNewRef(d); } /*[clinic input] hasattr as builtin_hasattr obj: object name: object / Return whether the object has an attribute with the given name. This is done by calling getattr(obj, name) and catching AttributeError. [clinic start generated code]*/ static PyObject * builtin_hasattr_impl(PyObject *module, PyObject *obj, PyObject *name) /*[clinic end generated code: output=a7aff2090a4151e5 input=0faec9787d979542]*/ { PyObject *v; if (_PyObject_LookupAttr(obj, name, &v) < 0) { return NULL; } if (v == NULL) { Py_RETURN_FALSE; } Py_DECREF(v); Py_RETURN_TRUE; } /* AC: gdb's integration with CPython relies on builtin_id having * the *exact* parameter names of "self" and "v", so we ensure we * preserve those name rather than using the AC defaults. */ /*[clinic input] id as builtin_id self: self(type="PyModuleDef *") obj as v: object / Return the identity of an object. This is guaranteed to be unique among simultaneously existing objects. (CPython uses the object's memory address.) [clinic start generated code]*/ static PyObject * builtin_id(PyModuleDef *self, PyObject *v) /*[clinic end generated code: output=0aa640785f697f65 input=5a534136419631f4]*/ { PyObject *id = PyLong_FromVoidPtr(v); if (id && PySys_Audit("builtins.id", "O", id) < 0) { Py_DECREF(id); return NULL; } return id; } /* map object ************************************************************/ typedef struct { PyObject_HEAD PyObject *iters; PyObject *func; } mapobject; static PyObject * map_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *it, *iters, *func; mapobject *lz; Py_ssize_t numargs, i; if ((type == &PyMap_Type || type->tp_init == PyMap_Type.tp_init) && !_PyArg_NoKeywords("map", kwds)) return NULL; numargs = PyTuple_Size(args); if (numargs < 2) { PyErr_SetString(PyExc_TypeError, "map() must have at least two arguments."); return NULL; } iters = PyTuple_New(numargs-1); if (iters == NULL) return NULL; for (i=1 ; itp_alloc(type, 0); if (lz == NULL) { Py_DECREF(iters); return NULL; } lz->iters = iters; func = PyTuple_GET_ITEM(args, 0); lz->func = Py_NewRef(func); return (PyObject *)lz; } static PyObject * map_vectorcall(PyObject *type, PyObject * const*args, size_t nargsf, PyObject *kwnames) { PyTypeObject *tp = _PyType_CAST(type); if (tp == &PyMap_Type && !_PyArg_NoKwnames("map", kwnames)) { return NULL; } Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); if (nargs < 2) { PyErr_SetString(PyExc_TypeError, "map() must have at least two arguments."); return NULL; } PyObject *iters = PyTuple_New(nargs-1); if (iters == NULL) { return NULL; } for (int i=1; itp_alloc(tp, 0); if (lz == NULL) { Py_DECREF(iters); return NULL; } lz->iters = iters; lz->func = Py_NewRef(args[0]); return (PyObject *)lz; } static void map_dealloc(mapobject *lz) { PyObject_GC_UnTrack(lz); Py_XDECREF(lz->iters); Py_XDECREF(lz->func); Py_TYPE(lz)->tp_free(lz); } static int map_traverse(mapobject *lz, visitproc visit, void *arg) { Py_VISIT(lz->iters); Py_VISIT(lz->func); return 0; } static PyObject * map_next(mapobject *lz) { PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; PyObject **stack; PyObject *result = NULL; PyThreadState *tstate = _PyThreadState_GET(); const Py_ssize_t niters = PyTuple_GET_SIZE(lz->iters); if (niters <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) { stack = small_stack; } else { stack = PyMem_Malloc(niters * sizeof(stack[0])); if (stack == NULL) { _PyErr_NoMemory(tstate); return NULL; } } Py_ssize_t nargs = 0; for (Py_ssize_t i=0; i < niters; i++) { PyObject *it = PyTuple_GET_ITEM(lz->iters, i); PyObject *val = Py_TYPE(it)->tp_iternext(it); if (val == NULL) { goto exit; } stack[i] = val; nargs++; } result = _PyObject_VectorcallTstate(tstate, lz->func, stack, nargs, NULL); exit: for (Py_ssize_t i=0; i < nargs; i++) { Py_DECREF(stack[i]); } if (stack != small_stack) { PyMem_Free(stack); } return result; } static PyObject * map_reduce(mapobject *lz, PyObject *Py_UNUSED(ignored)) { Py_ssize_t numargs = PyTuple_GET_SIZE(lz->iters); PyObject *args = PyTuple_New(numargs+1); Py_ssize_t i; if (args == NULL) return NULL; PyTuple_SET_ITEM(args, 0, Py_NewRef(lz->func)); for (i = 0; iiters, i); PyTuple_SET_ITEM(args, i+1, Py_NewRef(it)); } return Py_BuildValue("ON", Py_TYPE(lz), args); } static PyMethodDef map_methods[] = { {"__reduce__", _PyCFunction_CAST(map_reduce), METH_NOARGS, reduce_doc}, {NULL, NULL} /* sentinel */ }; PyDoc_STRVAR(map_doc, "map(func, *iterables) --> map object\n\ \n\ Make an iterator that computes the function using arguments from\n\ each of the iterables. Stops when the shortest iterable is exhausted."); PyTypeObject PyMap_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "map", /* tp_name */ sizeof(mapobject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)map_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags */ map_doc, /* tp_doc */ (traverseproc)map_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)map_next, /* tp_iternext */ map_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ map_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ .tp_vectorcall = (vectorcallfunc)map_vectorcall }; /*[clinic input] next as builtin_next iterator: object default: object = NULL / Return the next item from the iterator. If default is given and the iterator is exhausted, it is returned instead of raising StopIteration. [clinic start generated code]*/ static PyObject * builtin_next_impl(PyObject *module, PyObject *iterator, PyObject *default_value) /*[clinic end generated code: output=a38a94eeb447fef9 input=180f9984f182020f]*/ { PyObject *res; if (!PyIter_Check(iterator)) { PyErr_Format(PyExc_TypeError, "'%.200s' object is not an iterator", Py_TYPE(iterator)->tp_name); return NULL; } res = (*Py_TYPE(iterator)->tp_iternext)(iterator); if (res != NULL) { return res; } else if (default_value != NULL) { if (PyErr_Occurred()) { if(!PyErr_ExceptionMatches(PyExc_StopIteration)) return NULL; PyErr_Clear(); } return Py_NewRef(default_value); } else if (PyErr_Occurred()) { return NULL; } else { PyErr_SetNone(PyExc_StopIteration); return NULL; } } /*[clinic input] setattr as builtin_setattr obj: object name: object value: object / Sets the named attribute on the given object to the specified value. setattr(x, 'y', v) is equivalent to ``x.y = v`` [clinic start generated code]*/ static PyObject * builtin_setattr_impl(PyObject *module, PyObject *obj, PyObject *name, PyObject *value) /*[clinic end generated code: output=dc2ce1d1add9acb4 input=5e26417f2e8598d4]*/ { if (PyObject_SetAttr(obj, name, value) != 0) return NULL; Py_RETURN_NONE; } /*[clinic input] delattr as builtin_delattr obj: object name: object / Deletes the named attribute from the given object. delattr(x, 'y') is equivalent to ``del x.y`` [clinic start generated code]*/ static PyObject * builtin_delattr_impl(PyObject *module, PyObject *obj, PyObject *name) /*[clinic end generated code: output=85134bc58dff79fa input=164865623abe7216]*/ { if (PyObject_SetAttr(obj, name, (PyObject *)NULL) != 0) return NULL; Py_RETURN_NONE; } /*[clinic input] hash as builtin_hash obj: object / Return the hash value for the given object. Two objects that compare equal must also have the same hash value, but the reverse is not necessarily true. [clinic start generated code]*/ static PyObject * builtin_hash(PyObject *module, PyObject *obj) /*[clinic end generated code: output=237668e9d7688db7 input=58c48be822bf9c54]*/ { Py_hash_t x; x = PyObject_Hash(obj); if (x == -1) return NULL; return PyLong_FromSsize_t(x); } /*[clinic input] hex as builtin_hex number: object / Return the hexadecimal representation of an integer. >>> hex(12648430) '0xc0ffee' [clinic start generated code]*/ static PyObject * builtin_hex(PyObject *module, PyObject *number) /*[clinic end generated code: output=e46b612169099408 input=e645aff5fc7d540e]*/ { return PyNumber_ToBase(number, 16); } /*[clinic input] iter as builtin_iter object: object sentinel: object = NULL / Get an iterator from an object. In the first form, the argument must supply its own iterator, or be a sequence. In the second form, the callable is called until it returns the sentinel. [clinic start generated code]*/ static PyObject * builtin_iter_impl(PyObject *module, PyObject *object, PyObject *sentinel) /*[clinic end generated code: output=12cf64203c195a94 input=a5d64d9d81880ba6]*/ { if (sentinel == NULL) return PyObject_GetIter(object); if (!PyCallable_Check(object)) { PyErr_SetString(PyExc_TypeError, "iter(object, sentinel): object must be callable"); return NULL; } return PyCallIter_New(object, sentinel); } /*[clinic input] aiter as builtin_aiter async_iterable: object / Return an AsyncIterator for an AsyncIterable object. [clinic start generated code]*/ static PyObject * builtin_aiter(PyObject *module, PyObject *async_iterable) /*[clinic end generated code: output=1bae108d86f7960e input=473993d0cacc7d23]*/ { return PyObject_GetAIter(async_iterable); } PyObject *PyAnextAwaitable_New(PyObject *, PyObject *); /*[clinic input] anext as builtin_anext aiterator: object default: object = NULL / async anext(aiterator[, default]) Return the next item from the async iterator. If default is given and the async iterator is exhausted, it is returned instead of raising StopAsyncIteration. [clinic start generated code]*/ static PyObject * builtin_anext_impl(PyObject *module, PyObject *aiterator, PyObject *default_value) /*[clinic end generated code: output=f02c060c163a81fa input=8f63f4f78590bb4c]*/ { PyTypeObject *t; PyObject *awaitable; t = Py_TYPE(aiterator); if (t->tp_as_async == NULL || t->tp_as_async->am_anext == NULL) { PyErr_Format(PyExc_TypeError, "'%.200s' object is not an async iterator", t->tp_name); return NULL; } awaitable = (*t->tp_as_async->am_anext)(aiterator); if (default_value == NULL) { return awaitable; } PyObject* new_awaitable = PyAnextAwaitable_New( awaitable, default_value); Py_DECREF(awaitable); return new_awaitable; } /*[clinic input] len as builtin_len obj: object / Return the number of items in a container. [clinic start generated code]*/ static PyObject * builtin_len(PyObject *module, PyObject *obj) /*[clinic end generated code: output=fa7a270d314dfb6c input=bc55598da9e9c9b5]*/ { Py_ssize_t res; res = PyObject_Size(obj); if (res < 0) { assert(PyErr_Occurred()); return NULL; } return PyLong_FromSsize_t(res); } /*[clinic input] locals as builtin_locals Return a dictionary containing the current scope's local variables. NOTE: Whether or not updates to this dictionary will affect name lookups in the local scope and vice-versa is *implementation dependent* and not covered by any backwards compatibility guarantees. [clinic start generated code]*/ static PyObject * builtin_locals_impl(PyObject *module) /*[clinic end generated code: output=b46c94015ce11448 input=7874018d478d5c4b]*/ { PyObject *d; d = PyEval_GetLocals(); return Py_XNewRef(d); } static PyObject * min_max(PyObject *args, PyObject *kwds, int op) { PyObject *v, *it, *item, *val, *maxitem, *maxval, *keyfunc=NULL; PyObject *emptytuple, *defaultval = NULL; static char *kwlist[] = {"key", "default", NULL}; const char *name = op == Py_LT ? "min" : "max"; const int positional = PyTuple_Size(args) > 1; int ret; if (positional) { v = args; } else if (!PyArg_UnpackTuple(args, name, 1, 1, &v)) { if (PyExceptionClass_Check(PyExc_TypeError)) { PyErr_Format(PyExc_TypeError, "%s expected at least 1 argument, got 0", name); } return NULL; } emptytuple = PyTuple_New(0); if (emptytuple == NULL) return NULL; ret = PyArg_ParseTupleAndKeywords(emptytuple, kwds, (op == Py_LT) ? "|$OO:min" : "|$OO:max", kwlist, &keyfunc, &defaultval); Py_DECREF(emptytuple); if (!ret) return NULL; if (positional && defaultval != NULL) { PyErr_Format(PyExc_TypeError, "Cannot specify a default for %s() with multiple " "positional arguments", name); return NULL; } it = PyObject_GetIter(v); if (it == NULL) { return NULL; } if (keyfunc == Py_None) { keyfunc = NULL; } maxitem = NULL; /* the result */ maxval = NULL; /* the value associated with the result */ while (( item = PyIter_Next(it) )) { /* get the value from the key function */ if (keyfunc != NULL) { val = PyObject_CallOneArg(keyfunc, item); if (val == NULL) goto Fail_it_item; } /* no key function; the value is the item */ else { val = Py_NewRef(item); } /* maximum value and item are unset; set them */ if (maxval == NULL) { maxitem = item; maxval = val; } /* maximum value and item are set; update them as necessary */ else { int cmp = PyObject_RichCompareBool(val, maxval, op); if (cmp < 0) goto Fail_it_item_and_val; else if (cmp > 0) { Py_DECREF(maxval); Py_DECREF(maxitem); maxval = val; maxitem = item; } else { Py_DECREF(item); Py_DECREF(val); } } } if (PyErr_Occurred()) goto Fail_it; if (maxval == NULL) { assert(maxitem == NULL); if (defaultval != NULL) { maxitem = Py_NewRef(defaultval); } else { PyErr_Format(PyExc_ValueError, "%s() iterable argument is empty", name); } } else Py_DECREF(maxval); Py_DECREF(it); return maxitem; Fail_it_item_and_val: Py_DECREF(val); Fail_it_item: Py_DECREF(item); Fail_it: Py_XDECREF(maxval); Py_XDECREF(maxitem); Py_DECREF(it); return NULL; } /* AC: cannot convert yet, waiting for *args support */ static PyObject * builtin_min(PyObject *self, PyObject *args, PyObject *kwds) { return min_max(args, kwds, Py_LT); } PyDoc_STRVAR(min_doc, "min(iterable, *[, default=obj, key=func]) -> value\n\ min(arg1, arg2, *args, *[, key=func]) -> value\n\ \n\ With a single iterable argument, return its smallest item. The\n\ default keyword-only argument specifies an object to return if\n\ the provided iterable is empty.\n\ With two or more arguments, return the smallest argument."); /* AC: cannot convert yet, waiting for *args support */ static PyObject * builtin_max(PyObject *self, PyObject *args, PyObject *kwds) { return min_max(args, kwds, Py_GT); } PyDoc_STRVAR(max_doc, "max(iterable, *[, default=obj, key=func]) -> value\n\ max(arg1, arg2, *args, *[, key=func]) -> value\n\ \n\ With a single iterable argument, return its biggest item. The\n\ default keyword-only argument specifies an object to return if\n\ the provided iterable is empty.\n\ With two or more arguments, return the largest argument."); /*[clinic input] oct as builtin_oct number: object / Return the octal representation of an integer. >>> oct(342391) '0o1234567' [clinic start generated code]*/ static PyObject * builtin_oct(PyObject *module, PyObject *number) /*[clinic end generated code: output=40a34656b6875352 input=ad6b274af4016c72]*/ { return PyNumber_ToBase(number, 8); } /*[clinic input] ord as builtin_ord c: object / Return the Unicode code point for a one-character string. [clinic start generated code]*/ static PyObject * builtin_ord(PyObject *module, PyObject *c) /*[clinic end generated code: output=4fa5e87a323bae71 input=3064e5d6203ad012]*/ { long ord; Py_ssize_t size; if (PyBytes_Check(c)) { size = PyBytes_GET_SIZE(c); if (size == 1) { ord = (long)((unsigned char)*PyBytes_AS_STRING(c)); return PyLong_FromLong(ord); } } else if (PyUnicode_Check(c)) { size = PyUnicode_GET_LENGTH(c); if (size == 1) { ord = (long)PyUnicode_READ_CHAR(c, 0); return PyLong_FromLong(ord); } } else if (PyByteArray_Check(c)) { /* XXX Hopefully this is temporary */ size = PyByteArray_GET_SIZE(c); if (size == 1) { ord = (long)((unsigned char)*PyByteArray_AS_STRING(c)); return PyLong_FromLong(ord); } } else { PyErr_Format(PyExc_TypeError, "ord() expected string of length 1, but " \ "%.200s found", Py_TYPE(c)->tp_name); return NULL; } PyErr_Format(PyExc_TypeError, "ord() expected a character, " "but string of length %zd found", size); return NULL; } /*[clinic input] pow as builtin_pow base: object exp: object mod: object = None Equivalent to base**exp with 2 arguments or base**exp % mod with 3 arguments Some types, such as ints, are able to use a more efficient algorithm when invoked using the three argument form. [clinic start generated code]*/ static PyObject * builtin_pow_impl(PyObject *module, PyObject *base, PyObject *exp, PyObject *mod) /*[clinic end generated code: output=3ca1538221bbf15f input=435dbd48a12efb23]*/ { return PyNumber_Power(base, exp, mod); } /*[clinic input] print as builtin_print *args: object sep: object(c_default="Py_None") = ' ' string inserted between values, default a space. end: object(c_default="Py_None") = '\n' string appended after the last value, default a newline. file: object = None a file-like object (stream); defaults to the current sys.stdout. flush: bool = False whether to forcibly flush the stream. Prints the values to a stream, or to sys.stdout by default. [clinic start generated code]*/ static PyObject * builtin_print_impl(PyObject *module, PyObject *args, PyObject *sep, PyObject *end, PyObject *file, int flush) /*[clinic end generated code: output=3cfc0940f5bc237b input=c143c575d24fe665]*/ { int i, err; if (file == Py_None) { PyThreadState *tstate = _PyThreadState_GET(); file = _PySys_GetAttr(tstate, &_Py_ID(stdout)); if (file == NULL) { PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout"); return NULL; } /* sys.stdout may be None when FILE* stdout isn't connected */ if (file == Py_None) { Py_RETURN_NONE; } } if (sep == Py_None) { sep = NULL; } else if (sep && !PyUnicode_Check(sep)) { PyErr_Format(PyExc_TypeError, "sep must be None or a string, not %.200s", Py_TYPE(sep)->tp_name); return NULL; } if (end == Py_None) { end = NULL; } else if (end && !PyUnicode_Check(end)) { PyErr_Format(PyExc_TypeError, "end must be None or a string, not %.200s", Py_TYPE(end)->tp_name); return NULL; } for (i = 0; i < PyTuple_GET_SIZE(args); i++) { if (i > 0) { if (sep == NULL) { err = PyFile_WriteString(" ", file); } else { err = PyFile_WriteObject(sep, file, Py_PRINT_RAW); } if (err) { return NULL; } } err = PyFile_WriteObject(PyTuple_GET_ITEM(args, i), file, Py_PRINT_RAW); if (err) { return NULL; } } if (end == NULL) { err = PyFile_WriteString("\n", file); } else { err = PyFile_WriteObject(end, file, Py_PRINT_RAW); } if (err) { return NULL; } if (flush) { PyObject *tmp = PyObject_CallMethodNoArgs(file, &_Py_ID(flush)); if (tmp == NULL) { return NULL; } Py_DECREF(tmp); } Py_RETURN_NONE; } /*[clinic input] input as builtin_input prompt: object(c_default="NULL") = "" / Read a string from standard input. The trailing newline is stripped. The prompt string, if given, is printed to standard output without a trailing newline before reading input. If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError. On *nix systems, readline is used if available. [clinic start generated code]*/ static PyObject * builtin_input_impl(PyObject *module, PyObject *prompt) /*[clinic end generated code: output=83db5a191e7a0d60 input=159c46d4ae40977e]*/ { PyThreadState *tstate = _PyThreadState_GET(); PyObject *fin = _PySys_GetAttr( tstate, &_Py_ID(stdin)); PyObject *fout = _PySys_GetAttr( tstate, &_Py_ID(stdout)); PyObject *ferr = _PySys_GetAttr( tstate, &_Py_ID(stderr)); PyObject *tmp; long fd; int tty; /* Check that stdin/out/err are intact */ if (fin == NULL || fin == Py_None) { PyErr_SetString(PyExc_RuntimeError, "input(): lost sys.stdin"); return NULL; } if (fout == NULL || fout == Py_None) { PyErr_SetString(PyExc_RuntimeError, "input(): lost sys.stdout"); return NULL; } if (ferr == NULL || ferr == Py_None) { PyErr_SetString(PyExc_RuntimeError, "input(): lost sys.stderr"); return NULL; } if (PySys_Audit("builtins.input", "O", prompt ? prompt : Py_None) < 0) { return NULL; } /* First of all, flush stderr */ tmp = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush)); if (tmp == NULL) PyErr_Clear(); else Py_DECREF(tmp); /* We should only use (GNU) readline if Python's sys.stdin and sys.stdout are the same as C's stdin and stdout, because we need to pass it those. */ tmp = PyObject_CallMethodNoArgs(fin, &_Py_ID(fileno)); if (tmp == NULL) { PyErr_Clear(); tty = 0; } else { fd = PyLong_AsLong(tmp); Py_DECREF(tmp); if (fd < 0 && PyErr_Occurred()) return NULL; tty = fd == fileno(stdin) && isatty(fd); } if (tty) { tmp = PyObject_CallMethodNoArgs(fout, &_Py_ID(fileno)); if (tmp == NULL) { PyErr_Clear(); tty = 0; } else { fd = PyLong_AsLong(tmp); Py_DECREF(tmp); if (fd < 0 && PyErr_Occurred()) return NULL; tty = fd == fileno(stdout) && isatty(fd); } } /* If we're interactive, use (GNU) readline */ if (tty) { PyObject *po = NULL; const char *promptstr; char *s = NULL; PyObject *stdin_encoding = NULL, *stdin_errors = NULL; PyObject *stdout_encoding = NULL, *stdout_errors = NULL; const char *stdin_encoding_str, *stdin_errors_str; PyObject *result; size_t len; /* stdin is a text stream, so it must have an encoding. */ stdin_encoding = PyObject_GetAttr(fin, &_Py_ID(encoding)); stdin_errors = PyObject_GetAttr(fin, &_Py_ID(errors)); if (!stdin_encoding || !stdin_errors || !PyUnicode_Check(stdin_encoding) || !PyUnicode_Check(stdin_errors)) { tty = 0; goto _readline_errors; } stdin_encoding_str = PyUnicode_AsUTF8(stdin_encoding); stdin_errors_str = PyUnicode_AsUTF8(stdin_errors); if (!stdin_encoding_str || !stdin_errors_str) goto _readline_errors; tmp = PyObject_CallMethodNoArgs(fout, &_Py_ID(flush)); if (tmp == NULL) PyErr_Clear(); else Py_DECREF(tmp); if (prompt != NULL) { /* We have a prompt, encode it as stdout would */ const char *stdout_encoding_str, *stdout_errors_str; PyObject *stringpo; stdout_encoding = PyObject_GetAttr(fout, &_Py_ID(encoding)); stdout_errors = PyObject_GetAttr(fout, &_Py_ID(errors)); if (!stdout_encoding || !stdout_errors || !PyUnicode_Check(stdout_encoding) || !PyUnicode_Check(stdout_errors)) { tty = 0; goto _readline_errors; } stdout_encoding_str = PyUnicode_AsUTF8(stdout_encoding); stdout_errors_str = PyUnicode_AsUTF8(stdout_errors); if (!stdout_encoding_str || !stdout_errors_str) goto _readline_errors; stringpo = PyObject_Str(prompt); if (stringpo == NULL) goto _readline_errors; po = PyUnicode_AsEncodedString(stringpo, stdout_encoding_str, stdout_errors_str); Py_CLEAR(stdout_encoding); Py_CLEAR(stdout_errors); Py_CLEAR(stringpo); if (po == NULL) goto _readline_errors; assert(PyBytes_Check(po)); promptstr = PyBytes_AS_STRING(po); } else { po = NULL; promptstr = ""; } s = PyOS_Readline(stdin, stdout, promptstr); if (s == NULL) { PyErr_CheckSignals(); if (!PyErr_Occurred()) PyErr_SetNone(PyExc_KeyboardInterrupt); goto _readline_errors; } len = strlen(s); if (len == 0) { PyErr_SetNone(PyExc_EOFError); result = NULL; } else { if (len > PY_SSIZE_T_MAX) { PyErr_SetString(PyExc_OverflowError, "input: input too long"); result = NULL; } else { len--; /* strip trailing '\n' */ if (len != 0 && s[len-1] == '\r') len--; /* strip trailing '\r' */ result = PyUnicode_Decode(s, len, stdin_encoding_str, stdin_errors_str); } } Py_DECREF(stdin_encoding); Py_DECREF(stdin_errors); Py_XDECREF(po); PyMem_Free(s); if (result != NULL) { if (PySys_Audit("builtins.input/result", "O", result) < 0) { return NULL; } } return result; _readline_errors: Py_XDECREF(stdin_encoding); Py_XDECREF(stdout_encoding); Py_XDECREF(stdin_errors); Py_XDECREF(stdout_errors); Py_XDECREF(po); if (tty) return NULL; PyErr_Clear(); } /* Fallback if we're not interactive */ if (prompt != NULL) { if (PyFile_WriteObject(prompt, fout, Py_PRINT_RAW) != 0) return NULL; } tmp = PyObject_CallMethodNoArgs(fout, &_Py_ID(flush)); if (tmp == NULL) PyErr_Clear(); else Py_DECREF(tmp); return PyFile_GetLine(fin, -1); } /*[clinic input] repr as builtin_repr obj: object / Return the canonical string representation of the object. For many object types, including most builtins, eval(repr(obj)) == obj. [clinic start generated code]*/ static PyObject * builtin_repr(PyObject *module, PyObject *obj) /*[clinic end generated code: output=7ed3778c44fd0194 input=1c9e6d66d3e3be04]*/ { return PyObject_Repr(obj); } /*[clinic input] round as builtin_round number: object ndigits: object = None Round a number to a given precision in decimal digits. The return value is an integer if ndigits is omitted or None. Otherwise the return value has the same type as the number. ndigits may be negative. [clinic start generated code]*/ static PyObject * builtin_round_impl(PyObject *module, PyObject *number, PyObject *ndigits) /*[clinic end generated code: output=ff0d9dd176c02ede input=275678471d7aca15]*/ { PyObject *round, *result; if (!_PyType_IsReady(Py_TYPE(number))) { if (PyType_Ready(Py_TYPE(number)) < 0) return NULL; } round = _PyObject_LookupSpecial(number, &_Py_ID(__round__)); if (round == NULL) { if (!PyErr_Occurred()) PyErr_Format(PyExc_TypeError, "type %.100s doesn't define __round__ method", Py_TYPE(number)->tp_name); return NULL; } if (ndigits == Py_None) result = _PyObject_CallNoArgs(round); else result = PyObject_CallOneArg(round, ndigits); Py_DECREF(round); return result; } /*AC: we need to keep the kwds dict intact to easily call into the * list.sort method, which isn't currently supported in AC. So we just use * the initially generated signature with a custom implementation. */ /* [disabled clinic input] sorted as builtin_sorted iterable as seq: object key as keyfunc: object = None reverse: object = False Return a new list containing all items from the iterable in ascending order. A custom key function can be supplied to customize the sort order, and the reverse flag can be set to request the result in descending order. [end disabled clinic input]*/ PyDoc_STRVAR(builtin_sorted__doc__, "sorted($module, iterable, /, *, key=None, reverse=False)\n" "--\n" "\n" "Return a new list containing all items from the iterable in ascending order.\n" "\n" "A custom key function can be supplied to customize the sort order, and the\n" "reverse flag can be set to request the result in descending order."); #define BUILTIN_SORTED_METHODDEF \ {"sorted", _PyCFunction_CAST(builtin_sorted), METH_FASTCALL | METH_KEYWORDS, builtin_sorted__doc__}, static PyObject * builtin_sorted(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *newlist, *v, *seq, *callable; /* Keyword arguments are passed through list.sort() which will check them. */ if (!_PyArg_UnpackStack(args, nargs, "sorted", 1, 1, &seq)) return NULL; newlist = PySequence_List(seq); if (newlist == NULL) return NULL; callable = PyObject_GetAttr(newlist, &_Py_ID(sort)); if (callable == NULL) { Py_DECREF(newlist); return NULL; } assert(nargs >= 1); v = PyObject_Vectorcall(callable, args + 1, nargs - 1, kwnames); Py_DECREF(callable); if (v == NULL) { Py_DECREF(newlist); return NULL; } Py_DECREF(v); return newlist; } /*[clinic input] vars as builtin_vars object: object = NULL / Show vars. Without arguments, equivalent to locals(). With an argument, equivalent to object.__dict__. [clinic start generated code]*/ static PyObject * builtin_vars_impl(PyObject *module, PyObject *object) /*[clinic end generated code: output=840a7f64007a3e0a input=80cbdef9182c4ba3]*/ { PyObject *d; if (object == NULL) { d = Py_XNewRef(PyEval_GetLocals()); } else { if (_PyObject_LookupAttr(object, &_Py_ID(__dict__), &d) == 0) { PyErr_SetString(PyExc_TypeError, "vars() argument must have __dict__ attribute"); } } return d; } /*[clinic input] sum as builtin_sum iterable: object / start: object(c_default="NULL") = 0 Return the sum of a 'start' value (default: 0) plus an iterable of numbers When the iterable is empty, return the start value. This function is intended specifically for use with numeric values and may reject non-numeric types. [clinic start generated code]*/ static PyObject * builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) /*[clinic end generated code: output=df758cec7d1d302f input=162b50765250d222]*/ { PyObject *result = start; PyObject *temp, *item, *iter; iter = PyObject_GetIter(iterable); if (iter == NULL) return NULL; if (result == NULL) { result = PyLong_FromLong(0); if (result == NULL) { Py_DECREF(iter); return NULL; } } else { /* reject string values for 'start' parameter */ if (PyUnicode_Check(result)) { PyErr_SetString(PyExc_TypeError, "sum() can't sum strings [use ''.join(seq) instead]"); Py_DECREF(iter); return NULL; } if (PyBytes_Check(result)) { PyErr_SetString(PyExc_TypeError, "sum() can't sum bytes [use b''.join(seq) instead]"); Py_DECREF(iter); return NULL; } if (PyByteArray_Check(result)) { PyErr_SetString(PyExc_TypeError, "sum() can't sum bytearray [use b''.join(seq) instead]"); Py_DECREF(iter); return NULL; } Py_INCREF(result); } #ifndef SLOW_SUM /* Fast addition by keeping temporary sums in C instead of new Python objects. Assumes all inputs are the same type. If the assumption fails, default to the more general routine. */ if (PyLong_CheckExact(result)) { int overflow; Py_ssize_t i_result = PyLong_AsLongAndOverflow(result, &overflow); /* If this already overflowed, don't even enter the loop. */ if (overflow == 0) { Py_SETREF(result, NULL); } while(result == NULL) { item = PyIter_Next(iter); if (item == NULL) { Py_DECREF(iter); if (PyErr_Occurred()) return NULL; return PyLong_FromSsize_t(i_result); } if (PyLong_CheckExact(item) || PyBool_Check(item)) { Py_ssize_t b; overflow = 0; /* Single digits are common, fast, and cannot overflow on unpacking. */ if (_PyLong_IsCompact((PyLongObject *)item)) { b = _PyLong_CompactValue((PyLongObject *)item); } else { b = PyLong_AsLongAndOverflow(item, &overflow); } if (overflow == 0 && (i_result >= 0 ? (b <= LONG_MAX - i_result) : (b >= LONG_MIN - i_result))) { i_result += b; Py_DECREF(item); continue; } } /* Either overflowed or is not an int. Restore real objects and process normally */ result = PyLong_FromSsize_t(i_result); if (result == NULL) { Py_DECREF(item); Py_DECREF(iter); return NULL; } temp = PyNumber_Add(result, item); Py_DECREF(result); Py_DECREF(item); result = temp; if (result == NULL) { Py_DECREF(iter); return NULL; } } } if (PyFloat_CheckExact(result)) { double f_result = PyFloat_AS_DOUBLE(result); double c = 0.0; Py_SETREF(result, NULL); while(result == NULL) { item = PyIter_Next(iter); if (item == NULL) { Py_DECREF(iter); if (PyErr_Occurred()) return NULL; /* Avoid losing the sign on a negative result, and don't let adding the compensation convert an infinite or overflowed sum to a NaN. */ if (c && Py_IS_FINITE(c)) { f_result += c; } return PyFloat_FromDouble(f_result); } if (PyFloat_CheckExact(item)) { // Improved Kahan–Babuška algorithm by Arnold Neumaier // https://www.mat.univie.ac.at/~neum/scan/01.pdf double x = PyFloat_AS_DOUBLE(item); double t = f_result + x; if (fabs(f_result) >= fabs(x)) { c += (f_result - t) + x; } else { c += (x - t) + f_result; } f_result = t; _Py_DECREF_SPECIALIZED(item, _PyFloat_ExactDealloc); continue; } if (PyLong_Check(item)) { long value; int overflow; value = PyLong_AsLongAndOverflow(item, &overflow); if (!overflow) { f_result += (double)value; Py_DECREF(item); continue; } } if (c && Py_IS_FINITE(c)) { f_result += c; } result = PyFloat_FromDouble(f_result); if (result == NULL) { Py_DECREF(item); Py_DECREF(iter); return NULL; } temp = PyNumber_Add(result, item); Py_DECREF(result); Py_DECREF(item); result = temp; if (result == NULL) { Py_DECREF(iter); return NULL; } } } #endif for(;;) { item = PyIter_Next(iter); if (item == NULL) { /* error, or end-of-sequence */ if (PyErr_Occurred()) { Py_SETREF(result, NULL); } break; } /* It's tempting to use PyNumber_InPlaceAdd instead of PyNumber_Add here, to avoid quadratic running time when doing 'sum(list_of_lists, [])'. However, this would produce a change in behaviour: a snippet like empty = [] sum([[x] for x in range(10)], empty) would change the value of empty. In fact, using in-place addition rather that binary addition for any of the steps introduces subtle behavior changes: https://bugs.python.org/issue18305 */ temp = PyNumber_Add(result, item); Py_DECREF(result); Py_DECREF(item); result = temp; if (result == NULL) break; } Py_DECREF(iter); return result; } /*[clinic input] isinstance as builtin_isinstance obj: object class_or_tuple: object / Return whether an object is an instance of a class or of a subclass thereof. A tuple, as in ``isinstance(x, (A, B, ...))``, may be given as the target to check against. This is equivalent to ``isinstance(x, A) or isinstance(x, B) or ...`` etc. [clinic start generated code]*/ static PyObject * builtin_isinstance_impl(PyObject *module, PyObject *obj, PyObject *class_or_tuple) /*[clinic end generated code: output=6faf01472c13b003 input=ffa743db1daf7549]*/ { int retval; retval = PyObject_IsInstance(obj, class_or_tuple); if (retval < 0) return NULL; return PyBool_FromLong(retval); } /*[clinic input] issubclass as builtin_issubclass cls: object class_or_tuple: object / Return whether 'cls' is derived from another class or is the same class. A tuple, as in ``issubclass(x, (A, B, ...))``, may be given as the target to check against. This is equivalent to ``issubclass(x, A) or issubclass(x, B) or ...``. [clinic start generated code]*/ static PyObject * builtin_issubclass_impl(PyObject *module, PyObject *cls, PyObject *class_or_tuple) /*[clinic end generated code: output=358412410cd7a250 input=a24b9f3d58c370d6]*/ { int retval; retval = PyObject_IsSubclass(cls, class_or_tuple); if (retval < 0) return NULL; return PyBool_FromLong(retval); } typedef struct { PyObject_HEAD Py_ssize_t tuplesize; PyObject *ittuple; /* tuple of iterators */ PyObject *result; int strict; } zipobject; static PyObject * zip_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { zipobject *lz; Py_ssize_t i; PyObject *ittuple; /* tuple of iterators */ PyObject *result; Py_ssize_t tuplesize; int strict = 0; if (kwds) { PyObject *empty = PyTuple_New(0); if (empty == NULL) { return NULL; } static char *kwlist[] = {"strict", NULL}; int parsed = PyArg_ParseTupleAndKeywords( empty, kwds, "|$p:zip", kwlist, &strict); Py_DECREF(empty); if (!parsed) { return NULL; } } /* args must be a tuple */ assert(PyTuple_Check(args)); tuplesize = PyTuple_GET_SIZE(args); /* obtain iterators */ ittuple = PyTuple_New(tuplesize); if (ittuple == NULL) return NULL; for (i=0; i < tuplesize; ++i) { PyObject *item = PyTuple_GET_ITEM(args, i); PyObject *it = PyObject_GetIter(item); if (it == NULL) { Py_DECREF(ittuple); return NULL; } PyTuple_SET_ITEM(ittuple, i, it); } /* create a result holder */ result = PyTuple_New(tuplesize); if (result == NULL) { Py_DECREF(ittuple); return NULL; } for (i=0 ; i < tuplesize ; i++) { PyTuple_SET_ITEM(result, i, Py_NewRef(Py_None)); } /* create zipobject structure */ lz = (zipobject *)type->tp_alloc(type, 0); if (lz == NULL) { Py_DECREF(ittuple); Py_DECREF(result); return NULL; } lz->ittuple = ittuple; lz->tuplesize = tuplesize; lz->result = result; lz->strict = strict; return (PyObject *)lz; } static void zip_dealloc(zipobject *lz) { PyObject_GC_UnTrack(lz); Py_XDECREF(lz->ittuple); Py_XDECREF(lz->result); Py_TYPE(lz)->tp_free(lz); } static int zip_traverse(zipobject *lz, visitproc visit, void *arg) { Py_VISIT(lz->ittuple); Py_VISIT(lz->result); return 0; } static PyObject * zip_next(zipobject *lz) { Py_ssize_t i; Py_ssize_t tuplesize = lz->tuplesize; PyObject *result = lz->result; PyObject *it; PyObject *item; PyObject *olditem; if (tuplesize == 0) return NULL; if (Py_REFCNT(result) == 1) { Py_INCREF(result); for (i=0 ; i < tuplesize ; i++) { it = PyTuple_GET_ITEM(lz->ittuple, i); item = (*Py_TYPE(it)->tp_iternext)(it); if (item == NULL) { Py_DECREF(result); if (lz->strict) { goto check; } return NULL; } olditem = PyTuple_GET_ITEM(result, i); PyTuple_SET_ITEM(result, i, item); Py_DECREF(olditem); } // bpo-42536: The GC may have untracked this result tuple. Since we're // recycling it, make sure it's tracked again: if (!_PyObject_GC_IS_TRACKED(result)) { _PyObject_GC_TRACK(result); } } else { result = PyTuple_New(tuplesize); if (result == NULL) return NULL; for (i=0 ; i < tuplesize ; i++) { it = PyTuple_GET_ITEM(lz->ittuple, i); item = (*Py_TYPE(it)->tp_iternext)(it); if (item == NULL) { Py_DECREF(result); if (lz->strict) { goto check; } return NULL; } PyTuple_SET_ITEM(result, i, item); } } return result; check: if (PyErr_Occurred()) { if (!PyErr_ExceptionMatches(PyExc_StopIteration)) { // next() on argument i raised an exception (not StopIteration) return NULL; } PyErr_Clear(); } if (i) { // ValueError: zip() argument 2 is shorter than argument 1 // ValueError: zip() argument 3 is shorter than arguments 1-2 const char* plural = i == 1 ? " " : "s 1-"; return PyErr_Format(PyExc_ValueError, "zip() argument %d is shorter than argument%s%d", i + 1, plural, i); } for (i = 1; i < tuplesize; i++) { it = PyTuple_GET_ITEM(lz->ittuple, i); item = (*Py_TYPE(it)->tp_iternext)(it); if (item) { Py_DECREF(item); const char* plural = i == 1 ? " " : "s 1-"; return PyErr_Format(PyExc_ValueError, "zip() argument %d is longer than argument%s%d", i + 1, plural, i); } if (PyErr_Occurred()) { if (!PyErr_ExceptionMatches(PyExc_StopIteration)) { // next() on argument i raised an exception (not StopIteration) return NULL; } PyErr_Clear(); } // Argument i is exhausted. So far so good... } // All arguments are exhausted. Success! return NULL; } static PyObject * zip_reduce(zipobject *lz, PyObject *Py_UNUSED(ignored)) { /* Just recreate the zip with the internal iterator tuple */ if (lz->strict) { return PyTuple_Pack(3, Py_TYPE(lz), lz->ittuple, Py_True); } return PyTuple_Pack(2, Py_TYPE(lz), lz->ittuple); } PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); static PyObject * zip_setstate(zipobject *lz, PyObject *state) { int strict = PyObject_IsTrue(state); if (strict < 0) { return NULL; } lz->strict = strict; Py_RETURN_NONE; } static PyMethodDef zip_methods[] = { {"__reduce__", _PyCFunction_CAST(zip_reduce), METH_NOARGS, reduce_doc}, {"__setstate__", _PyCFunction_CAST(zip_setstate), METH_O, setstate_doc}, {NULL} /* sentinel */ }; PyDoc_STRVAR(zip_doc, "zip(*iterables, strict=False) --> Yield tuples until an input is exhausted.\n\ \n\ >>> list(zip('abcdefg', range(3), range(4)))\n\ [('a', 0, 0), ('b', 1, 1), ('c', 2, 2)]\n\ \n\ The zip object yields n-length tuples, where n is the number of iterables\n\ passed as positional arguments to zip(). The i-th element in every tuple\n\ comes from the i-th iterable argument to zip(). This continues until the\n\ shortest argument is exhausted.\n\ \n\ If strict is true and one of the arguments is exhausted before the others,\n\ raise a ValueError."); PyTypeObject PyZip_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "zip", /* tp_name */ sizeof(zipobject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)zip_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags */ zip_doc, /* tp_doc */ (traverseproc)zip_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)zip_next, /* tp_iternext */ zip_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ zip_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ }; static PyMethodDef builtin_methods[] = { {"__build_class__", _PyCFunction_CAST(builtin___build_class__), METH_FASTCALL | METH_KEYWORDS, build_class_doc}, BUILTIN___IMPORT___METHODDEF BUILTIN_ABS_METHODDEF BUILTIN_ALL_METHODDEF BUILTIN_ANY_METHODDEF BUILTIN_ASCII_METHODDEF BUILTIN_BIN_METHODDEF {"breakpoint", _PyCFunction_CAST(builtin_breakpoint), METH_FASTCALL | METH_KEYWORDS, breakpoint_doc}, BUILTIN_CALLABLE_METHODDEF BUILTIN_CHR_METHODDEF BUILTIN_COMPILE_METHODDEF BUILTIN_DELATTR_METHODDEF BUILTIN_DIR_METHODDEF BUILTIN_DIVMOD_METHODDEF BUILTIN_EVAL_METHODDEF BUILTIN_EXEC_METHODDEF BUILTIN_FORMAT_METHODDEF BUILTIN_GETATTR_METHODDEF BUILTIN_GLOBALS_METHODDEF BUILTIN_HASATTR_METHODDEF BUILTIN_HASH_METHODDEF BUILTIN_HEX_METHODDEF BUILTIN_ID_METHODDEF BUILTIN_INPUT_METHODDEF BUILTIN_ISINSTANCE_METHODDEF BUILTIN_ISSUBCLASS_METHODDEF BUILTIN_ITER_METHODDEF BUILTIN_AITER_METHODDEF BUILTIN_LEN_METHODDEF BUILTIN_LOCALS_METHODDEF {"max", _PyCFunction_CAST(builtin_max), METH_VARARGS | METH_KEYWORDS, max_doc}, {"min", _PyCFunction_CAST(builtin_min), METH_VARARGS | METH_KEYWORDS, min_doc}, BUILTIN_NEXT_METHODDEF BUILTIN_ANEXT_METHODDEF BUILTIN_OCT_METHODDEF BUILTIN_ORD_METHODDEF BUILTIN_POW_METHODDEF BUILTIN_PRINT_METHODDEF BUILTIN_REPR_METHODDEF BUILTIN_ROUND_METHODDEF BUILTIN_SETATTR_METHODDEF BUILTIN_SORTED_METHODDEF BUILTIN_SUM_METHODDEF BUILTIN_VARS_METHODDEF {NULL, NULL}, }; PyDoc_STRVAR(builtin_doc, "Built-in functions, types, exceptions, and other objects.\n\ \n\ This module provides direct access to all 'built-in'\n\ identifiers of Python; for example, builtins.len is\n\ the full name for the built-in function len().\n\ \n\ This module is not normally accessed explicitly by most\n\ applications, but can be useful in modules that provide\n\ objects with the same name as a built-in value, but in\n\ which the built-in of that name is also needed."); static struct PyModuleDef builtinsmodule = { PyModuleDef_HEAD_INIT, "builtins", builtin_doc, -1, /* multiple "initialization" just copies the module dict. */ builtin_methods, NULL, NULL, NULL, NULL }; PyObject * _PyBuiltin_Init(PyInterpreterState *interp) { PyObject *mod, *dict, *debug; const PyConfig *config = _PyInterpreterState_GetConfig(interp); mod = _PyModule_CreateInitialized(&builtinsmodule, PYTHON_API_VERSION); if (mod == NULL) return NULL; dict = PyModule_GetDict(mod); #ifdef Py_TRACE_REFS /* "builtins" exposes a number of statically allocated objects * that, before this code was added in 2.3, never showed up in * the list of "all objects" maintained by Py_TRACE_REFS. As a * result, programs leaking references to None and False (etc) * couldn't be diagnosed by examining sys.getobjects(0). */ #define ADD_TO_ALL(OBJECT) _Py_AddToAllObjects((PyObject *)(OBJECT), 0) #else #define ADD_TO_ALL(OBJECT) (void)0 #endif #define SETBUILTIN(NAME, OBJECT) \ if (PyDict_SetItemString(dict, NAME, (PyObject *)OBJECT) < 0) \ return NULL; \ ADD_TO_ALL(OBJECT) SETBUILTIN("None", Py_None); SETBUILTIN("Ellipsis", Py_Ellipsis); SETBUILTIN("NotImplemented", Py_NotImplemented); SETBUILTIN("False", Py_False); SETBUILTIN("True", Py_True); SETBUILTIN("bool", &PyBool_Type); SETBUILTIN("memoryview", &PyMemoryView_Type); SETBUILTIN("bytearray", &PyByteArray_Type); SETBUILTIN("bytes", &PyBytes_Type); SETBUILTIN("classmethod", &PyClassMethod_Type); SETBUILTIN("complex", &PyComplex_Type); SETBUILTIN("dict", &PyDict_Type); SETBUILTIN("enumerate", &PyEnum_Type); SETBUILTIN("filter", &PyFilter_Type); SETBUILTIN("float", &PyFloat_Type); SETBUILTIN("frozenset", &PyFrozenSet_Type); SETBUILTIN("property", &PyProperty_Type); SETBUILTIN("int", &PyLong_Type); SETBUILTIN("list", &PyList_Type); SETBUILTIN("map", &PyMap_Type); SETBUILTIN("object", &PyBaseObject_Type); SETBUILTIN("range", &PyRange_Type); SETBUILTIN("reversed", &PyReversed_Type); SETBUILTIN("set", &PySet_Type); SETBUILTIN("slice", &PySlice_Type); SETBUILTIN("staticmethod", &PyStaticMethod_Type); SETBUILTIN("str", &PyUnicode_Type); SETBUILTIN("super", &PySuper_Type); SETBUILTIN("tuple", &PyTuple_Type); SETBUILTIN("type", &PyType_Type); SETBUILTIN("zip", &PyZip_Type); debug = PyBool_FromLong(config->optimization_level == 0); if (PyDict_SetItemString(dict, "__debug__", debug) < 0) { Py_DECREF(debug); return NULL; } Py_DECREF(debug); return mod; #undef ADD_TO_ALL #undef SETBUILTIN } ================================================ FILE: Bootstrap_Hash.c ================================================ #include "Python.h" #include "pycore_initconfig.h" #include "pycore_fileutils.h" // _Py_fstat_noraise() #include "pycore_runtime.h" // _PyRuntime #ifdef MS_WINDOWS # include # include #else # include # ifdef HAVE_SYS_STAT_H # include # endif # ifdef HAVE_LINUX_RANDOM_H # include # endif # if defined(HAVE_SYS_RANDOM_H) && (defined(HAVE_GETRANDOM) || defined(HAVE_GETENTROPY)) # include # endif # if !defined(HAVE_GETRANDOM) && defined(HAVE_GETRANDOM_SYSCALL) # include # endif #endif #ifdef _Py_MEMORY_SANITIZER # include #endif #if defined(__APPLE__) && defined(__has_builtin) # if __has_builtin(__builtin_available) # define HAVE_GETENTRYPY_GETRANDOM_RUNTIME __builtin_available(macOS 10.12, iOS 10.10, tvOS 10.0, watchOS 3.0, *) # endif #endif #ifndef HAVE_GETENTRYPY_GETRANDOM_RUNTIME # define HAVE_GETENTRYPY_GETRANDOM_RUNTIME 1 #endif #ifdef Py_DEBUG int _Py_HashSecret_Initialized = 0; #else static int _Py_HashSecret_Initialized = 0; #endif #ifdef MS_WINDOWS /* Fill buffer with size pseudo-random bytes generated by the Windows CryptoGen API. Return 0 on success, or raise an exception and return -1 on error. */ static int win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise) { while (size > 0) { DWORD chunk = (DWORD)Py_MIN(size, PY_DWORD_MAX); NTSTATUS status = BCryptGenRandom(NULL, buffer, chunk, BCRYPT_USE_SYSTEM_PREFERRED_RNG); if (!BCRYPT_SUCCESS(status)) { /* BCryptGenRandom() failed */ if (raise) { PyErr_SetFromWindowsErr(0); } return -1; } buffer += chunk; size -= chunk; } return 0; } #else /* !MS_WINDOWS */ #if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL) #define PY_GETRANDOM 1 /* Call getrandom() to get random bytes: - Return 1 on success - Return 0 if getrandom() is not available (failed with ENOSYS or EPERM), or if getrandom(GRND_NONBLOCK) failed with EAGAIN (system urandom not initialized yet) and raise=0. - Raise an exception (if raise is non-zero) and return -1 on error: if getrandom() failed with EINTR, raise is non-zero and the Python signal handler raised an exception, or if getrandom() failed with a different error. getrandom() is retried if it failed with EINTR: interrupted by a signal. */ static int py_getrandom(void *buffer, Py_ssize_t size, int blocking, int raise) { /* Is getrandom() supported by the running kernel? Set to 0 if getrandom() failed with ENOSYS or EPERM. Need Linux kernel 3.17 or newer, or Solaris 11.3 or newer */ static int getrandom_works = 1; int flags; char *dest; long n; if (!getrandom_works) { return 0; } flags = blocking ? 0 : GRND_NONBLOCK; dest = buffer; while (0 < size) { #if defined(__sun) && defined(__SVR4) /* Issue #26735: On Solaris, getrandom() is limited to returning up to 1024 bytes. Call it multiple times if more bytes are requested. */ n = Py_MIN(size, 1024); #else n = Py_MIN(size, LONG_MAX); #endif errno = 0; #ifdef HAVE_GETRANDOM if (raise) { Py_BEGIN_ALLOW_THREADS n = getrandom(dest, n, flags); Py_END_ALLOW_THREADS } else { n = getrandom(dest, n, flags); } #else /* On Linux, use the syscall() function because the GNU libc doesn't expose the Linux getrandom() syscall yet. See: https://sourceware.org/bugzilla/show_bug.cgi?id=17252 */ if (raise) { Py_BEGIN_ALLOW_THREADS n = syscall(SYS_getrandom, dest, n, flags); Py_END_ALLOW_THREADS } else { n = syscall(SYS_getrandom, dest, n, flags); } # ifdef _Py_MEMORY_SANITIZER if (n > 0) { __msan_unpoison(dest, n); } # endif #endif if (n < 0) { /* ENOSYS: the syscall is not supported by the kernel. EPERM: the syscall is blocked by a security policy (ex: SECCOMP) or something else. */ if (errno == ENOSYS || errno == EPERM) { getrandom_works = 0; return 0; } /* getrandom(GRND_NONBLOCK) fails with EAGAIN if the system urandom is not initialized yet. For _PyRandom_Init(), we ignore the error and fall back on reading /dev/urandom which never blocks, even if the system urandom is not initialized yet: see the PEP 524. */ if (errno == EAGAIN && !raise && !blocking) { return 0; } if (errno == EINTR) { if (raise) { if (PyErr_CheckSignals()) { return -1; } } /* retry getrandom() if it was interrupted by a signal */ continue; } if (raise) { PyErr_SetFromErrno(PyExc_OSError); } return -1; } dest += n; size -= n; } return 1; } #elif defined(HAVE_GETENTROPY) #define PY_GETENTROPY 1 /* Fill buffer with size pseudo-random bytes generated by getentropy(): - Return 1 on success - Return 0 if getentropy() syscall is not available (failed with ENOSYS or EPERM). - Raise an exception (if raise is non-zero) and return -1 on error: if getentropy() failed with EINTR, raise is non-zero and the Python signal handler raised an exception, or if getentropy() failed with a different error. getentropy() is retried if it failed with EINTR: interrupted by a signal. */ #if defined(__APPLE__) && defined(__has_attribute) && __has_attribute(availability) static int py_getentropy(char *buffer, Py_ssize_t size, int raise) __attribute__((availability(macos,introduced=10.12))) __attribute__((availability(ios,introduced=10.0))) __attribute__((availability(tvos,introduced=10.0))) __attribute__((availability(watchos,introduced=3.0))); #endif static int py_getentropy(char *buffer, Py_ssize_t size, int raise) { /* Is getentropy() supported by the running kernel? Set to 0 if getentropy() failed with ENOSYS or EPERM. */ static int getentropy_works = 1; if (!getentropy_works) { return 0; } while (size > 0) { /* getentropy() is limited to returning up to 256 bytes. Call it multiple times if more bytes are requested. */ Py_ssize_t len = Py_MIN(size, 256); int res; if (raise) { Py_BEGIN_ALLOW_THREADS res = getentropy(buffer, len); Py_END_ALLOW_THREADS } else { res = getentropy(buffer, len); } if (res < 0) { /* ENOSYS: the syscall is not supported by the running kernel. EPERM: the syscall is blocked by a security policy (ex: SECCOMP) or something else. */ if (errno == ENOSYS || errno == EPERM) { getentropy_works = 0; return 0; } if (errno == EINTR) { if (raise) { if (PyErr_CheckSignals()) { return -1; } } /* retry getentropy() if it was interrupted by a signal */ continue; } if (raise) { PyErr_SetFromErrno(PyExc_OSError); } return -1; } buffer += len; size -= len; } return 1; } #endif /* defined(HAVE_GETENTROPY) && !(defined(__sun) && defined(__SVR4)) */ #define urandom_cache (_PyRuntime.pyhash_state.urandom_cache) /* Read random bytes from the /dev/urandom device: - Return 0 on success - Raise an exception (if raise is non-zero) and return -1 on error Possible causes of errors: - open() failed with ENOENT, ENXIO, ENODEV, EACCES: the /dev/urandom device was not found. For example, it was removed manually or not exposed in a chroot or container. - open() failed with a different error - fstat() failed - read() failed or returned 0 read() is retried if it failed with EINTR: interrupted by a signal. The file descriptor of the device is kept open between calls to avoid using many file descriptors when run in parallel from multiple threads: see the issue #18756. st_dev and st_ino fields of the file descriptor (from fstat()) are cached to check if the file descriptor was replaced by a different file (which is likely a bug in the application): see the issue #21207. If the file descriptor was closed or replaced, open a new file descriptor but don't close the old file descriptor: it probably points to something important for some third-party code. */ static int dev_urandom(char *buffer, Py_ssize_t size, int raise) { int fd; Py_ssize_t n; if (raise) { struct _Py_stat_struct st; int fstat_result; if (urandom_cache.fd >= 0) { Py_BEGIN_ALLOW_THREADS fstat_result = _Py_fstat_noraise(urandom_cache.fd, &st); Py_END_ALLOW_THREADS /* Does the fd point to the same thing as before? (issue #21207) */ if (fstat_result || st.st_dev != urandom_cache.st_dev || st.st_ino != urandom_cache.st_ino) { /* Something changed: forget the cached fd (but don't close it, since it probably points to something important for some third-party code). */ urandom_cache.fd = -1; } } if (urandom_cache.fd >= 0) fd = urandom_cache.fd; else { fd = _Py_open("/dev/urandom", O_RDONLY); if (fd < 0) { if (errno == ENOENT || errno == ENXIO || errno == ENODEV || errno == EACCES) { PyErr_SetString(PyExc_NotImplementedError, "/dev/urandom (or equivalent) not found"); } /* otherwise, keep the OSError exception raised by _Py_open() */ return -1; } if (urandom_cache.fd >= 0) { /* urandom_fd was initialized by another thread while we were not holding the GIL, keep it. */ close(fd); fd = urandom_cache.fd; } else { if (_Py_fstat(fd, &st)) { close(fd); return -1; } else { urandom_cache.fd = fd; urandom_cache.st_dev = st.st_dev; urandom_cache.st_ino = st.st_ino; } } } do { n = _Py_read(fd, buffer, (size_t)size); if (n == -1) return -1; if (n == 0) { PyErr_Format(PyExc_RuntimeError, "Failed to read %zi bytes from /dev/urandom", size); return -1; } buffer += n; size -= n; } while (0 < size); } else { fd = _Py_open_noraise("/dev/urandom", O_RDONLY); if (fd < 0) { return -1; } while (0 < size) { do { n = read(fd, buffer, (size_t)size); } while (n < 0 && errno == EINTR); if (n <= 0) { /* stop on error or if read(size) returned 0 */ close(fd); return -1; } buffer += n; size -= n; } close(fd); } return 0; } static void dev_urandom_close(void) { if (urandom_cache.fd >= 0) { close(urandom_cache.fd); urandom_cache.fd = -1; } } #undef urandom_cache #endif /* !MS_WINDOWS */ /* Fill buffer with pseudo-random bytes generated by a linear congruent generator (LCG): x(n+1) = (x(n) * 214013 + 2531011) % 2^32 Use bits 23..16 of x(n) to generate a byte. */ static void lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size) { size_t index; unsigned int x; x = x0; for (index=0; index < size; index++) { x *= 214013; x += 2531011; /* modulo 2 ^ (8 * sizeof(int)) */ buffer[index] = (x >> 16) & 0xff; } } /* Read random bytes: - Return 0 on success - Raise an exception (if raise is non-zero) and return -1 on error Used sources of entropy ordered by preference, preferred source first: - BCryptGenRandom() on Windows - getrandom() function (ex: Linux and Solaris): call py_getrandom() - getentropy() function (ex: OpenBSD): call py_getentropy() - /dev/urandom device Read from the /dev/urandom device if getrandom() or getentropy() function is not available or does not work. Prefer getrandom() over getentropy() because getrandom() supports blocking and non-blocking mode: see the PEP 524. Python requires non-blocking RNG at startup to initialize its hash secret, but os.urandom() must block until the system urandom is initialized (at least on Linux 3.17 and newer). Prefer getrandom() and getentropy() over reading directly /dev/urandom because these functions don't need file descriptors and so avoid ENFILE or EMFILE errors (too many open files): see the issue #18756. Only the getrandom() function supports non-blocking mode. Only use RNG running in the kernel. They are more secure because it is harder to get the internal state of a RNG running in the kernel land than a RNG running in the user land. The kernel has a direct access to the hardware and has access to hardware RNG, they are used as entropy sources. Note: the OpenSSL RAND_pseudo_bytes() function does not automatically reseed its RNG on fork(), two child processes (with the same pid) generate the same random numbers: see issue #18747. Kernel RNGs don't have this issue, they have access to good quality entropy sources. If raise is zero: - Don't raise an exception on error - Don't call the Python signal handler (don't call PyErr_CheckSignals()) if a function fails with EINTR: retry directly the interrupted function - Don't release the GIL to call functions. */ static int pyurandom(void *buffer, Py_ssize_t size, int blocking, int raise) { #if defined(PY_GETRANDOM) || defined(PY_GETENTROPY) int res; #endif if (size < 0) { if (raise) { PyErr_Format(PyExc_ValueError, "negative argument not allowed"); } return -1; } if (size == 0) { return 0; } #ifdef MS_WINDOWS return win32_urandom((unsigned char *)buffer, size, raise); #else #if defined(PY_GETRANDOM) || defined(PY_GETENTROPY) if (HAVE_GETENTRYPY_GETRANDOM_RUNTIME) { #ifdef PY_GETRANDOM res = py_getrandom(buffer, size, blocking, raise); #else res = py_getentropy(buffer, size, raise); #endif if (res < 0) { return -1; } if (res == 1) { return 0; } /* getrandom() or getentropy() function is not available: failed with ENOSYS or EPERM. Fall back on reading from /dev/urandom. */ } /* end of availability block */ #endif return dev_urandom(buffer, size, raise); #endif } /* Fill buffer with size pseudo-random bytes from the operating system random number generator (RNG). It is suitable for most cryptographic purposes except long living private keys for asymmetric encryption. On Linux 3.17 and newer, the getrandom() syscall is used in blocking mode: block until the system urandom entropy pool is initialized (128 bits are collected by the kernel). Return 0 on success. Raise an exception and return -1 on error. */ int _PyOS_URandom(void *buffer, Py_ssize_t size) { return pyurandom(buffer, size, 1, 1); } /* Fill buffer with size pseudo-random bytes from the operating system random number generator (RNG). It is not suitable for cryptographic purpose. On Linux 3.17 and newer (when getrandom() syscall is used), if the system urandom is not initialized yet, the function returns "weak" entropy read from /dev/urandom. Return 0 on success. Raise an exception and return -1 on error. */ int _PyOS_URandomNonblock(void *buffer, Py_ssize_t size) { return pyurandom(buffer, size, 0, 1); } PyStatus _Py_HashRandomization_Init(const PyConfig *config) { void *secret = &_Py_HashSecret; Py_ssize_t secret_size = sizeof(_Py_HashSecret_t); if (_Py_HashSecret_Initialized) { return _PyStatus_OK(); } _Py_HashSecret_Initialized = 1; if (config->use_hash_seed) { if (config->hash_seed == 0) { /* disable the randomized hash */ memset(secret, 0, secret_size); } else { /* use the specified hash seed */ lcg_urandom(config->hash_seed, secret, secret_size); } } else { /* use a random hash seed */ int res; /* _PyRandom_Init() is called very early in the Python initialization and so exceptions cannot be used (use raise=0). _PyRandom_Init() must not block Python initialization: call pyurandom() is non-blocking mode (blocking=0): see the PEP 524. */ res = pyurandom(secret, secret_size, 0, 0); if (res < 0) { return _PyStatus_ERR("failed to get random numbers " "to initialize Python"); } } return _PyStatus_OK(); } void _Py_HashRandomization_Fini(void) { #ifndef MS_WINDOWS dev_urandom_close(); #endif } ================================================ FILE: ByteCodes.c ================================================ // This file contains instruction definitions. // It is read by Tools/cases_generator/generate_cases.py // to generate Python/generated_cases.c.h. // Note that there is some dummy C code at the top and bottom of the file // to fool text editors like VS Code into believing this is valid C code. // The actual instruction definitions start at // BEGIN BYTECODES //. // See Tools/cases_generator/README.md for more information. #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_call.h" // _PyObject_FastCallDictTstate() #include "pycore_ceval.h" // _PyEval_SignalAsyncExc() #include "pycore_code.h" #include "pycore_function.h" #include "pycore_intrinsics.h" #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_instruments.h" #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_moduleobject.h" // PyModuleObject #include "pycore_opcode.h" // EXTRA_CASES #include "pycore_opcode_utils.h" // MAKE_FUNCTION_* #include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_range.h" // _PyRangeIterObject #include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs #include "pycore_sysmodule.h" // _PySys_Audit() #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "pycore_typeobject.h" // _PySuper_Lookup() #include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS #include "pycore_dict.h" #include "dictobject.h" #include "pycore_frame.h" #include "opcode.h" #include "optimizer.h" #include "pydtrace.h" #include "setobject.h" #include "structmember.h" // struct PyMemberDef, T_OFFSET_EX #define USE_COMPUTED_GOTOS 0 #include "ceval_macros.h" /* Flow control macros */ #define DEOPT_IF(cond, instname) ((void)0) #define ERROR_IF(cond, labelname) ((void)0) #define GO_TO_INSTRUCTION(instname) ((void)0) #define inst(name, ...) case name: #define op(name, ...) /* NAME is ignored */ #define macro(name) static int MACRO_##name #define super(name) static int SUPER_##name #define family(name, ...) static int family_##name // Dummy variables for stack effects. static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub; static PyObject *container, *start, *stop, *v, *lhs, *rhs, *res2; static PyObject *list, *tuple, *dict, *owner, *set, *str, *tup, *map, *keys; static PyObject *exit_func, *lasti, *val, *retval, *obj, *iter; static PyObject *aiter, *awaitable, *iterable, *w, *exc_value, *bc, *locals; static PyObject *orig, *excs, *update, *b, *fromlist, *level, *from; static PyObject **pieces, **values; static size_t jump; // Dummy variables for cache effects static uint16_t invert, counter, index, hint; static uint32_t type_version; static PyObject * dummy_func( PyThreadState *tstate, _PyInterpreterFrame *frame, unsigned char opcode, unsigned int oparg, _PyCFrame cframe, _Py_CODEUNIT *next_instr, PyObject **stack_pointer, PyObject *kwnames, int throwflag, binaryfunc binary_ops[], PyObject *args[] ) { // Dummy labels. pop_1_error: // Dummy locals. PyObject *annotations; PyObject *attrs; PyObject *bottom; PyObject *callable; PyObject *callargs; PyObject *closure; PyObject *codeobj; PyObject *cond; PyObject *defaults; PyObject *descr; _PyInterpreterFrame entry_frame; PyObject *exc; PyObject *exit; PyObject *fget; PyObject *fmt_spec; PyObject *func; uint32_t func_version; PyObject *getattribute; PyObject *kwargs; PyObject *kwdefaults; PyObject *len_o; PyObject *match; PyObject *match_type; PyObject *method; PyObject *mgr; Py_ssize_t min_args; PyObject *names; PyObject *new_exc; PyObject *next; PyObject *none; PyObject *null; PyObject *prev_exc; PyObject *receiver; PyObject *rest; int result; PyObject *self; PyObject *seq; PyObject *slice; PyObject *step; PyObject *subject; PyObject *top; PyObject *type; PyObject *typevars; int values_or_none; switch (opcode) { // BEGIN BYTECODES // inst(NOP, (--)) { } inst(RESUME, (--)) { assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); /* Possibly combine this with eval breaker */ if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) { int err = _Py_Instrument(frame->f_code, tstate->interp); ERROR_IF(err, error); next_instr--; } else if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker) && oparg < 2) { goto handle_eval_breaker; } } inst(INSTRUMENTED_RESUME, (--)) { /* Possible performance enhancement: * We need to check the eval breaker anyway, can we * combine the instrument verison check and the eval breaker test? */ if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) { if (_Py_Instrument(frame->f_code, tstate->interp)) { goto error; } next_instr--; } else { _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation( tstate, oparg > 0, frame, next_instr-1); stack_pointer = _PyFrame_GetStackPointer(frame); ERROR_IF(err, error); if (frame->prev_instr != next_instr-1) { /* Instrumentation has jumped */ next_instr = frame->prev_instr; DISPATCH(); } if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker) && oparg < 2) { goto handle_eval_breaker; } } } inst(LOAD_CLOSURE, (-- value)) { /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); ERROR_IF(value == NULL, unbound_local_error); Py_INCREF(value); } inst(LOAD_FAST_CHECK, (-- value)) { value = GETLOCAL(oparg); ERROR_IF(value == NULL, unbound_local_error); Py_INCREF(value); } inst(LOAD_FAST, (-- value)) { value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); } inst(LOAD_FAST_AND_CLEAR, (-- value)) { value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; } inst(LOAD_FAST_LOAD_FAST, ( -- value1, value2)) { uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; value1 = GETLOCAL(oparg1); value2 = GETLOCAL(oparg2); Py_INCREF(value1); Py_INCREF(value2); } inst(LOAD_CONST, (-- value)) { value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); } inst(STORE_FAST, (value --)) { SETLOCAL(oparg, value); } inst(STORE_FAST_LOAD_FAST, (value1 -- value2)) { uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); value2 = GETLOCAL(oparg2); Py_INCREF(value2); } inst(STORE_FAST_STORE_FAST, (value2, value1 --)) { uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); SETLOCAL(oparg2, value2); } inst(POP_TOP, (value --)) { DECREF_INPUTS(); } inst(PUSH_NULL, (-- res)) { res = NULL; } macro(END_FOR) = POP_TOP + POP_TOP; inst(INSTRUMENTED_END_FOR, (receiver, value --)) { /* Need to create a fake StopIteration error here, * to conform to PEP 380 */ if (PyGen_Check(receiver)) { PyErr_SetObject(PyExc_StopIteration, value); if (monitor_stop_iteration(tstate, frame, next_instr-1)) { goto error; } PyErr_SetRaisedException(NULL); } DECREF_INPUTS(); } inst(END_SEND, (receiver, value -- value)) { Py_DECREF(receiver); } inst(INSTRUMENTED_END_SEND, (receiver, value -- value)) { if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) { PyErr_SetObject(PyExc_StopIteration, value); if (monitor_stop_iteration(tstate, frame, next_instr-1)) { goto error; } PyErr_SetRaisedException(NULL); } Py_DECREF(receiver); } inst(UNARY_NEGATIVE, (value -- res)) { res = PyNumber_Negative(value); DECREF_INPUTS(); ERROR_IF(res == NULL, error); } inst(UNARY_NOT, (value -- res)) { int err = PyObject_IsTrue(value); DECREF_INPUTS(); ERROR_IF(err < 0, error); if (err == 0) { res = Py_True; } else { res = Py_False; } } inst(UNARY_INVERT, (value -- res)) { res = PyNumber_Invert(value); DECREF_INPUTS(); ERROR_IF(res == NULL, error); } family(binary_op, INLINE_CACHE_ENTRIES_BINARY_OP) = { BINARY_OP, BINARY_OP_MULTIPLY_INT, BINARY_OP_ADD_INT, BINARY_OP_SUBTRACT_INT, BINARY_OP_MULTIPLY_FLOAT, BINARY_OP_ADD_FLOAT, BINARY_OP_SUBTRACT_FLOAT, BINARY_OP_ADD_UNICODE, // BINARY_OP_INPLACE_ADD_UNICODE, // See comments at that opcode. }; op(_GUARD_BOTH_INT, (left, right -- left, right)) { DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); } op(_BINARY_OP_MULTIPLY_INT, (unused/1, left, right -- res)) { STAT_INC(BINARY_OP, hit); res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); ERROR_IF(res == NULL, error); } op(_BINARY_OP_ADD_INT, (unused/1, left, right -- res)) { STAT_INC(BINARY_OP, hit); res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); ERROR_IF(res == NULL, error); } op(_BINARY_OP_SUBTRACT_INT, (unused/1, left, right -- res)) { STAT_INC(BINARY_OP, hit); res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); ERROR_IF(res == NULL, error); } macro(BINARY_OP_MULTIPLY_INT) = _GUARD_BOTH_INT + _BINARY_OP_MULTIPLY_INT; macro(BINARY_OP_ADD_INT) = _GUARD_BOTH_INT + _BINARY_OP_ADD_INT; macro(BINARY_OP_SUBTRACT_INT) = _GUARD_BOTH_INT + _BINARY_OP_SUBTRACT_INT; op(_GUARD_BOTH_FLOAT, (left, right -- left, right)) { DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); } op(_BINARY_OP_MULTIPLY_FLOAT, (unused/1, left, right -- res)) { STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); } op(_BINARY_OP_ADD_FLOAT, (unused/1, left, right -- res)) { STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); } op(_BINARY_OP_SUBTRACT_FLOAT, (unused/1, left, right -- res)) { STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); } macro(BINARY_OP_MULTIPLY_FLOAT) = _GUARD_BOTH_FLOAT + _BINARY_OP_MULTIPLY_FLOAT; macro(BINARY_OP_ADD_FLOAT) = _GUARD_BOTH_FLOAT + _BINARY_OP_ADD_FLOAT; macro(BINARY_OP_SUBTRACT_FLOAT) = _GUARD_BOTH_FLOAT + _BINARY_OP_SUBTRACT_FLOAT; op(_GUARD_BOTH_UNICODE, (left, right -- left, right)) { DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); } op(_BINARY_OP_ADD_UNICODE, (unused/1, left, right -- res)) { STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); ERROR_IF(res == NULL, error); } macro(BINARY_OP_ADD_UNICODE) = _GUARD_BOTH_UNICODE + _BINARY_OP_ADD_UNICODE; // This is a subtle one. It's a super-instruction for // BINARY_OP_ADD_UNICODE followed by STORE_FAST // where the store goes into the left argument. // So the inputs are the same as for all BINARY_OP // specializations, but there is no output. // At the end we just skip over the STORE_FAST. op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) { _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; assert(true_next.op.code == STORE_FAST); PyObject **target_local = &GETLOCAL(true_next.op.arg); DEOPT_IF(*target_local != left, BINARY_OP); STAT_INC(BINARY_OP, hit); /* Handle `left = left + right` or `left += right` for str. * * When possible, extend `left` in place rather than * allocating a new PyUnicodeObject. This attempts to avoid * quadratic behavior when one neglects to use str.join(). * * If `left` has only two references remaining (one from * the stack, one in the locals), DECREFing `left` leaves * only the locals reference, so PyUnicode_Append knows * that the string is safe to mutate. */ assert(Py_REFCNT(left) >= 2); _Py_DECREF_NO_DEALLOC(left); PyUnicode_Append(target_local, right); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); ERROR_IF(*target_local == NULL, error); // The STORE_FAST is already done. JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); } macro(BINARY_OP_INPLACE_ADD_UNICODE) = _GUARD_BOTH_UNICODE + _BINARY_OP_INPLACE_ADD_UNICODE; family(binary_subscr, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = { BINARY_SUBSCR, BINARY_SUBSCR_DICT, BINARY_SUBSCR_GETITEM, BINARY_SUBSCR_LIST_INT, BINARY_SUBSCR_TUPLE_INT, }; inst(BINARY_SUBSCR, (unused/1, container, sub -- res)) { #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_BinarySubscr(container, sub, next_instr); DISPATCH_SAME_OPARG(); } STAT_INC(BINARY_SUBSCR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ res = PyObject_GetItem(container, sub); DECREF_INPUTS(); ERROR_IF(res == NULL, error); } inst(BINARY_SLICE, (container, start, stop -- res)) { PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. if (slice == NULL) { res = NULL; } else { res = PyObject_GetItem(container, slice); Py_DECREF(slice); } Py_DECREF(container); ERROR_IF(res == NULL, error); } inst(STORE_SLICE, (v, container, start, stop -- )) { PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { err = 1; } else { err = PyObject_SetItem(container, slice, v); Py_DECREF(slice); } Py_DECREF(v); Py_DECREF(container); ERROR_IF(err, error); } inst(BINARY_SUBSCR_LIST_INT, (unused/1, list, sub -- res)) { DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyList_Size(list) DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyList_GET_ITEM(list, index); assert(res != NULL); Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); } inst(BINARY_SUBSCR_TUPLE_INT, (unused/1, tuple, sub -- res)) { DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyTuple_Size(list) DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyTuple_GET_ITEM(tuple, index); assert(res != NULL); Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); } inst(BINARY_SUBSCR_DICT, (unused/1, dict, sub -- res)) { DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); if (res == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } DECREF_INPUTS(); ERROR_IF(true, error); } Py_INCREF(res); // Do this before DECREF'ing dict, sub DECREF_INPUTS(); } inst(BINARY_SUBSCR_GETITEM, (unused/1, container, sub -- unused)) { DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; PyObject *cached = ht->_spec_cache.getitem; DEOPT_IF(cached == NULL, BINARY_SUBSCR); assert(PyFunction_Check(cached)); PyFunctionObject *getitem = (PyFunctionObject *)cached; uint32_t cached_version = ht->_spec_cache.getitem_version; DEOPT_IF(getitem->func_version != cached_version, BINARY_SUBSCR); PyCodeObject *code = (PyCodeObject *)getitem->func_code; assert(code->co_argcount == 2); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); Py_INCREF(getitem); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, getitem, 2); STACK_SHRINK(2); new_frame->localsplus[0] = container; new_frame->localsplus[1] = sub; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); } inst(LIST_APPEND, (list, unused[oparg-1], v -- list, unused[oparg-1])) { ERROR_IF(_PyList_AppendTakeRef((PyListObject *)list, v) < 0, error); } inst(SET_ADD, (set, unused[oparg-1], v -- set, unused[oparg-1])) { int err = PySet_Add(set, v); DECREF_INPUTS(); ERROR_IF(err, error); } family(store_subscr, INLINE_CACHE_ENTRIES_STORE_SUBSCR) = { STORE_SUBSCR, STORE_SUBSCR_DICT, STORE_SUBSCR_LIST_INT, }; inst(STORE_SUBSCR, (counter/1, v, container, sub -- )) { #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; _Py_Specialize_StoreSubscr(container, sub, next_instr); DISPATCH_SAME_OPARG(); } STAT_INC(STORE_SUBSCR, deferred); _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); #else (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); DECREF_INPUTS(); ERROR_IF(err, error); } inst(STORE_SUBSCR_LIST_INT, (unused/1, value, list, sub -- )) { DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); // Ensure nonnegative, zero-or-one-digit ints. DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), STORE_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; // Ensure index < len(list) DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); PyObject *old_value = PyList_GET_ITEM(list, index); PyList_SET_ITEM(list, index, value); assert(old_value != NULL); Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); } inst(STORE_SUBSCR_DICT, (unused/1, value, dict, sub -- )) { DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); ERROR_IF(err, error); } inst(DELETE_SUBSCR, (container, sub --)) { /* del container[sub] */ int err = PyObject_DelItem(container, sub); DECREF_INPUTS(); ERROR_IF(err, error); } inst(CALL_INTRINSIC_1, (value -- res)) { assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); DECREF_INPUTS(); ERROR_IF(res == NULL, error); } inst(CALL_INTRINSIC_2, (value2, value1 -- res)) { assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); DECREF_INPUTS(); ERROR_IF(res == NULL, error); } inst(RAISE_VARARGS, (args[oparg] -- )) { PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: cause = args[1]; /* fall through */ case 1: exc = args[0]; /* fall through */ case 0: ERROR_IF(do_raise(tstate, exc, cause), exception_unwind); break; default: _PyErr_SetString(tstate, PyExc_SystemError, "bad RAISE_VARARGS oparg"); break; } ERROR_IF(true, error); } inst(INTERPRETER_EXIT, (retval --)) { assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() assert(EMPTY()); /* Restore previous cframe and return. */ tstate->cframe = cframe.previous; assert(tstate->cframe->current_frame == frame->previous); assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); return retval; } inst(RETURN_VALUE, (retval --)) { STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); _Py_LeaveRecursiveCallPy(tstate); assert(frame != &entry_frame); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; } inst(INSTRUMENTED_RETURN_VALUE, (retval --)) { int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); if (err) goto error; STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); _Py_LeaveRecursiveCallPy(tstate); assert(frame != &entry_frame); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; } inst(RETURN_CONST, (--)) { PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); _Py_LeaveRecursiveCallPy(tstate); assert(frame != &entry_frame); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; } inst(INSTRUMENTED_RETURN_CONST, (--)) { PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); if (err) goto error; Py_INCREF(retval); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); _Py_LeaveRecursiveCallPy(tstate); assert(frame != &entry_frame); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; } inst(GET_AITER, (obj -- iter)) { unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); if (type->tp_as_async != NULL) { getter = type->tp_as_async->am_aiter; } if (getter == NULL) { _PyErr_Format(tstate, PyExc_TypeError, "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); DECREF_INPUTS(); ERROR_IF(true, error); } iter = (*getter)(obj); DECREF_INPUTS(); ERROR_IF(iter == NULL, error); if (Py_TYPE(iter)->tp_as_async == NULL || Py_TYPE(iter)->tp_as_async->am_anext == NULL) { _PyErr_Format(tstate, PyExc_TypeError, "'async for' received an object from __aiter__ " "that does not implement __anext__: %.100s", Py_TYPE(iter)->tp_name); Py_DECREF(iter); ERROR_IF(true, error); } } inst(GET_ANEXT, (aiter -- aiter, awaitable)) { unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); if (PyAsyncGen_CheckExact(aiter)) { awaitable = type->tp_as_async->am_anext(aiter); if (awaitable == NULL) { goto error; } } else { if (type->tp_as_async != NULL){ getter = type->tp_as_async->am_anext; } if (getter != NULL) { next_iter = (*getter)(aiter); if (next_iter == NULL) { goto error; } } else { _PyErr_Format(tstate, PyExc_TypeError, "'async for' requires an iterator with " "__anext__ method, got %.100s", type->tp_name); goto error; } awaitable = _PyCoro_GetAwaitableIter(next_iter); if (awaitable == NULL) { _PyErr_FormatFromCause( PyExc_TypeError, "'async for' received an invalid object " "from __anext__: %.100s", Py_TYPE(next_iter)->tp_name); Py_DECREF(next_iter); goto error; } else { Py_DECREF(next_iter); } } } inst(GET_AWAITABLE, (iterable -- iter)) { iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } DECREF_INPUTS(); if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); if (yf != NULL) { /* `iter` is a coroutine object that is being awaited, `yf` is a pointer to the current awaitable being awaited on. */ Py_DECREF(yf); Py_CLEAR(iter); _PyErr_SetString(tstate, PyExc_RuntimeError, "coroutine is being awaited already"); /* The code below jumps to `error` if `iter` is NULL. */ } } ERROR_IF(iter == NULL, error); } family(send, INLINE_CACHE_ENTRIES_SEND) = { SEND, SEND_GEN, }; inst(SEND, (unused/1, receiver, v -- receiver, retval)) { #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_Send(receiver, next_instr); DISPATCH_SAME_OPARG(); } STAT_INC(SEND, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ assert(frame != &entry_frame); if ((tstate->interp->eval_frame == NULL) && (Py_TYPE(receiver) == &PyGen_Type || Py_TYPE(receiver) == &PyCoro_Type) && ((PyGenObject *)receiver)->gi_frame_state < FRAME_EXECUTING) { PyGenObject *gen = (PyGenObject *)receiver; _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; frame->return_offset = oparg; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); } if (Py_IsNone(v) && PyIter_Check(receiver)) { retval = Py_TYPE(receiver)->tp_iternext(receiver); } else { retval = PyObject_CallMethodOneArg(receiver, &_Py_ID(send), v); } if (retval == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_StopIteration) ) { monitor_raise(tstate, frame, next_instr-1); } if (_PyGen_FetchStopIterationValue(&retval) == 0) { assert(retval != NULL); JUMPBY(oparg); } else { goto error; } } Py_DECREF(v); } inst(SEND_GEN, (unused/1, receiver, v -- receiver, unused)) { DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND); STAT_INC(SEND, hit); _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; frame->return_offset = oparg; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); } inst(INSTRUMENTED_YIELD_VALUE, (retval -- unused)) { assert(frame != &entry_frame); PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; _PyFrame_SetStackPointer(frame, stack_pointer - 1); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_YIELD, frame, next_instr-1, retval); if (err) goto error; tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *gen_frame = frame; frame = cframe.current_frame = frame->previous; gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; } inst(YIELD_VALUE, (retval -- unused)) { // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. assert(frame != &entry_frame); PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; _PyFrame_SetStackPointer(frame, stack_pointer - 1); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *gen_frame = frame; frame = cframe.current_frame = frame->previous; gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; } inst(POP_EXCEPT, (exc_value -- )) { _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); } inst(RERAISE, (values[oparg], exc -- values[oparg])) { assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; if (PyLong_Check(lasti)) { frame->prev_instr = _PyCode_CODE(frame->f_code) + PyLong_AsLong(lasti); assert(!_PyErr_Occurred(tstate)); } else { assert(PyLong_Check(lasti)); _PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int"); goto error; } } assert(exc && PyExceptionInstance_Check(exc)); Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } inst(END_ASYNC_FOR, (awaitable, exc -- )) { assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { DECREF_INPUTS(); } else { Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } } inst(CLEANUP_THROW, (sub_iter, last_sent_val, exc_value -- none, value)) { assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); DECREF_INPUTS(); none = Py_None; } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } } inst(LOAD_ASSERTION_ERROR, ( -- value)) { value = Py_NewRef(PyExc_AssertionError); } inst(LOAD_BUILD_CLASS, ( -- bc)) { if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); if (bc == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_SetString(tstate, PyExc_NameError, "__build_class__ not found"); } ERROR_IF(true, error); } Py_INCREF(bc); } else { bc = PyObject_GetItem(BUILTINS(), &_Py_ID(__build_class__)); if (bc == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) _PyErr_SetString(tstate, PyExc_NameError, "__build_class__ not found"); ERROR_IF(true, error); } } } inst(STORE_NAME, (v -- )) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); DECREF_INPUTS(); ERROR_IF(true, error); } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); DECREF_INPUTS(); ERROR_IF(err, error); } inst(DELETE_NAME, (--)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals when deleting %R", name); goto error; } err = PyObject_DelItem(ns, name); // Can't use ERROR_IF here. if (err != 0) { format_exc_check_arg(tstate, PyExc_NameError, NAME_ERROR_MSG, name); goto error; } } family(unpack_sequence, INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE) = { UNPACK_SEQUENCE, UNPACK_SEQUENCE_TWO_TUPLE, UNPACK_SEQUENCE_TUPLE, UNPACK_SEQUENCE_LIST, }; inst(UNPACK_SEQUENCE, (unused/1, seq -- unused[oparg])) { #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_UnpackSequence(seq, next_instr, oparg); DISPATCH_SAME_OPARG(); } STAT_INC(UNPACK_SEQUENCE, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); DECREF_INPUTS(); ERROR_IF(res == 0, error); } inst(UNPACK_SEQUENCE_TWO_TUPLE, (unused/1, seq -- values[oparg])) { DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); DECREF_INPUTS(); } inst(UNPACK_SEQUENCE_TUPLE, (unused/1, seq -- values[oparg])) { DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); PyObject **items = _PyTuple_ITEMS(seq); for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } DECREF_INPUTS(); } inst(UNPACK_SEQUENCE_LIST, (unused/1, seq -- values[oparg])) { DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); PyObject **items = _PyList_ITEMS(seq); for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } DECREF_INPUTS(); } inst(UNPACK_EX, (seq -- unused[oparg & 0xFF], unused, unused[oparg >> 8])) { int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); DECREF_INPUTS(); ERROR_IF(res == 0, error); } family(store_attr, INLINE_CACHE_ENTRIES_STORE_ATTR) = { STORE_ATTR, STORE_ATTR_INSTANCE_VALUE, STORE_ATTR_SLOT, STORE_ATTR_WITH_HINT, }; inst(STORE_ATTR, (counter/1, unused/3, v, owner --)) { #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); next_instr--; _Py_Specialize_StoreAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); } STAT_INC(STORE_ATTR, deferred); _PyAttrCache *cache = (_PyAttrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); #else (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); DECREF_INPUTS(); ERROR_IF(err, error); } inst(DELETE_ATTR, (owner --)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); DECREF_INPUTS(); ERROR_IF(err, error); } inst(STORE_GLOBAL, (v --)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); DECREF_INPUTS(); ERROR_IF(err, error); } inst(DELETE_GLOBAL, (--)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); // Can't use ERROR_IF here. if (err != 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { format_exc_check_arg(tstate, PyExc_NameError, NAME_ERROR_MSG, name); } goto error; } } op(_LOAD_LOCALS, ( -- locals)) { locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, "no locals found"); ERROR_IF(true, error); } Py_INCREF(locals); } macro(LOAD_LOCALS) = _LOAD_LOCALS; op(_LOAD_FROM_DICT_OR_GLOBALS, (mod_or_class_dict -- v)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); if (v != NULL) { Py_INCREF(v); } else if (_PyErr_Occurred(tstate)) { Py_DECREF(mod_or_class_dict); goto error; } } else { v = PyObject_GetItem(mod_or_class_dict, name); if (v == NULL) { if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { Py_DECREF(mod_or_class_dict); goto error; } _PyErr_Clear(tstate); } } Py_DECREF(mod_or_class_dict); if (v == NULL) { v = PyDict_GetItemWithError(GLOBALS(), name); if (v != NULL) { Py_INCREF(v); } else if (_PyErr_Occurred(tstate)) { goto error; } else { if (PyDict_CheckExact(BUILTINS())) { v = PyDict_GetItemWithError(BUILTINS(), name); if (v == NULL) { if (!_PyErr_Occurred(tstate)) { format_exc_check_arg( tstate, PyExc_NameError, NAME_ERROR_MSG, name); } goto error; } Py_INCREF(v); } else { v = PyObject_GetItem(BUILTINS(), name); if (v == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { format_exc_check_arg( tstate, PyExc_NameError, NAME_ERROR_MSG, name); } goto error; } } } } } macro(LOAD_NAME) = _LOAD_LOCALS + _LOAD_FROM_DICT_OR_GLOBALS; macro(LOAD_FROM_DICT_OR_GLOBALS) = _LOAD_FROM_DICT_OR_GLOBALS; family(load_global, INLINE_CACHE_ENTRIES_LOAD_GLOBAL) = { LOAD_GLOBAL, LOAD_GLOBAL_MODULE, LOAD_GLOBAL_BUILTIN, }; inst(LOAD_GLOBAL, (unused/1, unused/1, unused/1, unused/1 -- null if (oparg & 1), v)) { #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name); DISPATCH_SAME_OPARG(); } STAT_INC(LOAD_GLOBAL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); if (PyDict_CheckExact(GLOBALS()) && PyDict_CheckExact(BUILTINS())) { v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), (PyDictObject *)BUILTINS(), name); if (v == NULL) { if (!_PyErr_Occurred(tstate)) { /* _PyDict_LoadGlobal() returns NULL without raising * an exception if the key doesn't exist */ format_exc_check_arg(tstate, PyExc_NameError, NAME_ERROR_MSG, name); } ERROR_IF(true, error); } Py_INCREF(v); } else { /* Slow-path if globals or builtins is not a dict */ /* namespace 1: globals */ v = PyObject_GetItem(GLOBALS(), name); if (v == NULL) { ERROR_IF(!_PyErr_ExceptionMatches(tstate, PyExc_KeyError), error); _PyErr_Clear(tstate); /* namespace 2: builtins */ v = PyObject_GetItem(BUILTINS(), name); if (v == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { format_exc_check_arg( tstate, PyExc_NameError, NAME_ERROR_MSG, name); } ERROR_IF(true, error); } } } null = NULL; } inst(LOAD_GLOBAL_MODULE, (unused/1, index/1, version/1, unused/1 -- null if (oparg & 1), res)) { DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); assert(DK_IS_UNICODE(dict->ma_keys)); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); res = entries[index].me_value; DEOPT_IF(res == NULL, LOAD_GLOBAL); Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; } inst(LOAD_GLOBAL_BUILTIN, (unused/1, index/1, mod_version/1, bltn_version/1 -- null if (oparg & 1), res)) { DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); PyDictObject *bdict = (PyDictObject *)BUILTINS(); assert(opcode == LOAD_GLOBAL_BUILTIN); DEOPT_IF(mdict->ma_keys->dk_version != mod_version, LOAD_GLOBAL); DEOPT_IF(bdict->ma_keys->dk_version != bltn_version, LOAD_GLOBAL); assert(DK_IS_UNICODE(bdict->ma_keys)); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); res = entries[index].me_value; DEOPT_IF(res == NULL, LOAD_GLOBAL); Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; } inst(DELETE_FAST, (--)) { PyObject *v = GETLOCAL(oparg); ERROR_IF(v == NULL, unbound_local_error); SETLOCAL(oparg, NULL); } inst(MAKE_CELL, (--)) { // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); PyObject *cell = PyCell_New(initial); if (cell == NULL) { goto resume_with_error; } SETLOCAL(oparg, cell); } inst(DELETE_DEREF, (--)) { PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. // Fortunately we don't need its superpower. if (oldobj == NULL) { format_exc_unbound(tstate, frame->f_code, oparg); goto error; } PyCell_SET(cell, NULL); Py_DECREF(oldobj); } inst(LOAD_FROM_DICT_OR_DEREF, (class_dict -- value)) { PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); name = PyTuple_GET_ITEM(frame->f_code->co_localsplusnames, oparg); if (PyDict_CheckExact(class_dict)) { value = PyDict_GetItemWithError(class_dict, name); if (value != NULL) { Py_INCREF(value); } else if (_PyErr_Occurred(tstate)) { Py_DECREF(class_dict); goto error; } } else { value = PyObject_GetItem(class_dict, name); if (value == NULL) { if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { Py_DECREF(class_dict); goto error; } _PyErr_Clear(tstate); } } Py_DECREF(class_dict); if (!value) { PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { format_exc_unbound(tstate, frame->f_code, oparg); goto error; } Py_INCREF(value); } } inst(LOAD_DEREF, ( -- value)) { PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { format_exc_unbound(tstate, frame->f_code, oparg); ERROR_IF(true, error); } Py_INCREF(value); } inst(STORE_DEREF, (v --)) { PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); } inst(COPY_FREE_VARS, (--)) { /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure; assert(oparg == co->co_nfreevars); int offset = co->co_nlocalsplus - oparg; for (int i = 0; i < oparg; ++i) { PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } } inst(BUILD_STRING, (pieces[oparg] -- str)) { str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); DECREF_INPUTS(); ERROR_IF(str == NULL, error); } inst(BUILD_TUPLE, (values[oparg] -- tup)) { tup = _PyTuple_FromArraySteal(values, oparg); ERROR_IF(tup == NULL, error); } inst(BUILD_LIST, (values[oparg] -- list)) { list = _PyList_FromArraySteal(values, oparg); ERROR_IF(list == NULL, error); } inst(LIST_EXTEND, (list, unused[oparg-1], iterable -- list, unused[oparg-1])) { PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && (Py_TYPE(iterable)->tp_iter == NULL && !PySequence_Check(iterable))) { _PyErr_Clear(tstate); _PyErr_Format(tstate, PyExc_TypeError, "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } DECREF_INPUTS(); ERROR_IF(true, error); } assert(Py_IsNone(none_val)); DECREF_INPUTS(); } inst(SET_UPDATE, (set, unused[oparg-1], iterable -- set, unused[oparg-1])) { int err = _PySet_Update(set, iterable); DECREF_INPUTS(); ERROR_IF(err < 0, error); } inst(BUILD_SET, (values[oparg] -- set)) { set = PySet_New(NULL); if (set == NULL) goto error; int err = 0; for (int i = 0; i < oparg; i++) { PyObject *item = values[i]; if (err == 0) err = PySet_Add(set, item); Py_DECREF(item); } if (err != 0) { Py_DECREF(set); ERROR_IF(true, error); } } inst(BUILD_MAP, (values[oparg*2] -- map)) { map = _PyDict_FromItems( values, 2, values+1, 2, oparg); if (map == NULL) goto error; DECREF_INPUTS(); ERROR_IF(map == NULL, error); } inst(SETUP_ANNOTATIONS, (--)) { int err; PyObject *ann_dict; if (LOCALS() == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when setting up annotations"); ERROR_IF(true, error); } /* check if __annotations__ in locals()... */ if (PyDict_CheckExact(LOCALS())) { ann_dict = _PyDict_GetItemWithError(LOCALS(), &_Py_ID(__annotations__)); if (ann_dict == NULL) { ERROR_IF(_PyErr_Occurred(tstate), error); /* ...if not, create a new one */ ann_dict = PyDict_New(); ERROR_IF(ann_dict == NULL, error); err = PyDict_SetItem(LOCALS(), &_Py_ID(__annotations__), ann_dict); Py_DECREF(ann_dict); ERROR_IF(err, error); } } else { /* do the same if locals() is not a dict */ ann_dict = PyObject_GetItem(LOCALS(), &_Py_ID(__annotations__)); if (ann_dict == NULL) { ERROR_IF(!_PyErr_ExceptionMatches(tstate, PyExc_KeyError), error); _PyErr_Clear(tstate); ann_dict = PyDict_New(); ERROR_IF(ann_dict == NULL, error); err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__), ann_dict); Py_DECREF(ann_dict); ERROR_IF(err, error); } else { Py_DECREF(ann_dict); } } } inst(BUILD_CONST_KEY_MAP, (values[oparg], keys -- map)) { if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, "bad BUILD_CONST_KEY_MAP keys argument"); goto error; // Pop the keys and values. } map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); DECREF_INPUTS(); ERROR_IF(map == NULL, error); } inst(DICT_UPDATE, (update --)) { PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { _PyErr_Format(tstate, PyExc_TypeError, "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } DECREF_INPUTS(); ERROR_IF(true, error); } DECREF_INPUTS(); } inst(DICT_MERGE, (update --)) { PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); DECREF_INPUTS(); ERROR_IF(true, error); } DECREF_INPUTS(); } inst(MAP_ADD, (key, value --)) { PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references ERROR_IF(_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0, error); } inst(INSTRUMENTED_LOAD_SUPER_ATTR, (unused/9, unused, unused, unused -- unused if (oparg & 1), unused)) { _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); } family(load_super_attr, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = { LOAD_SUPER_ATTR, LOAD_SUPER_ATTR_ATTR, LOAD_SUPER_ATTR_METHOD, }; inst(LOAD_SUPER_ATTR, (unused/1, global_super, class, self -- res2 if (oparg & 1), res)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_LoadSuperAttr(global_super, class, next_instr, load_method); DISPATCH_SAME_OPARG(); } STAT_INC(LOAD_SUPER_ATTR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, next_instr-1, global_super, arg); ERROR_IF(err, error); } // we make no attempt to optimize here; specializations should // handle any case whose performance we care about PyObject *stack[] = {class, self}; PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL); if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; if (super == NULL) { _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, frame, next_instr-1, global_super, arg); } else { int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_C_RETURN, frame, next_instr-1, global_super, arg); if (err < 0) { Py_CLEAR(super); } } } DECREF_INPUTS(); ERROR_IF(super == NULL, error); res = PyObject_GetAttr(super, name); Py_DECREF(super); ERROR_IF(res == NULL, error); } inst(LOAD_SUPER_ATTR_ATTR, (unused/1, global_super, class, self -- res2 if (oparg & 1), res)) { assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); DECREF_INPUTS(); ERROR_IF(res == NULL, error); } inst(LOAD_SUPER_ATTR_METHOD, (unused/1, global_super, class, self -- res2, res)) { assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); PyTypeObject *cls = (PyTypeObject *)class; int method_found = 0; res2 = _PySuper_Lookup(cls, self, name, cls->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); Py_DECREF(global_super); Py_DECREF(class); if (res2 == NULL) { Py_DECREF(self); ERROR_IF(true, error); } if (method_found) { res = self; // transfer ownership } else { Py_DECREF(self); res = res2; res2 = NULL; } } family(load_attr, INLINE_CACHE_ENTRIES_LOAD_ATTR) = { LOAD_ATTR, LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_MODULE, LOAD_ATTR_WITH_HINT, LOAD_ATTR_SLOT, LOAD_ATTR_CLASS, LOAD_ATTR_PROPERTY, LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, LOAD_ATTR_METHOD_WITH_VALUES, LOAD_ATTR_METHOD_NO_DICT, LOAD_ATTR_METHOD_LAZY_DICT, }; inst(LOAD_ATTR, (unused/9, owner -- res2 if (oparg & 1), res)) { #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); } STAT_INC(LOAD_ATTR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); if (oparg & 1) { /* Designed to work in tandem with CALL, pushes two values. */ PyObject* meth = NULL; if (_PyObject_GetMethod(owner, name, &meth)) { /* We can bypass temporary bound method object. meth is unbound method and obj is self. meth | self | arg1 | ... | argN */ assert(meth != NULL); // No errors on this branch res2 = meth; res = owner; // Transfer ownership } else { /* meth is not an unbound method (but a regular attr, or something was returned by a descriptor protocol). Set the second element of the stack to NULL, to signal CALL that it's not a method call. NULL | meth | arg1 | ... | argN */ DECREF_INPUTS(); ERROR_IF(meth == NULL, error); res2 = NULL; res = meth; } } else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); DECREF_INPUTS(); ERROR_IF(res == NULL, error); } } inst(LOAD_ATTR_INSTANCE_VALUE, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); assert(tp->tp_dictoffset < 0); assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); res = _PyDictOrValues_GetValues(dorv)->values[index]; DEOPT_IF(res == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; DECREF_INPUTS(); } inst(LOAD_ATTR_MODULE, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); DEOPT_IF(dict->ma_keys->dk_version != type_version, LOAD_ATTR); assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); assert(index < dict->ma_keys->dk_nentries); PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + index; res = ep->me_value; DEOPT_IF(res == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; DECREF_INPUTS(); } inst(LOAD_ATTR_WITH_HINT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(_PyDictOrValues_IsValues(dorv), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, LOAD_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); uint16_t hint = index; DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, LOAD_ATTR); if (DK_IS_UNICODE(dict->ma_keys)) { PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; DEOPT_IF(ep->me_key != name, LOAD_ATTR); res = ep->me_value; } else { PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint; DEOPT_IF(ep->me_key != name, LOAD_ATTR); res = ep->me_value; } DEOPT_IF(res == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; DECREF_INPUTS(); } inst(LOAD_ATTR_SLOT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); char *addr = (char *)owner + index; res = *(PyObject **)addr; DEOPT_IF(res == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; DECREF_INPUTS(); } inst(LOAD_ATTR_CLASS, (unused/1, type_version/2, unused/2, descr/4, cls -- res2 if (oparg & 1), res)) { DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, LOAD_ATTR); assert(type_version != 0); STAT_INC(LOAD_ATTR, hit); res2 = NULL; res = descr; assert(res != NULL); Py_INCREF(res); DECREF_INPUTS(); } inst(LOAD_ATTR_PROPERTY, (unused/1, type_version/2, func_version/2, fget/4, owner -- unused if (oparg & 1), unused)) { DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); assert(type_version != 0); assert(Py_IS_TYPE(fget, &PyFunction_Type)); PyFunctionObject *f = (PyFunctionObject *)fget; assert(func_version != 0); DEOPT_IF(f->func_version != func_version, LOAD_ATTR); PyCodeObject *code = (PyCodeObject *)f->func_code; assert(code->co_argcount == 1); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); Py_INCREF(fget); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 1); // Manipulate stack directly because we exit with DISPATCH_INLINED(). SET_TOP(NULL); int shrink_stack = !(oparg & 1); STACK_SHRINK(shrink_stack); new_frame->localsplus[0] = owner; JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); } inst(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, (unused/1, type_version/2, func_version/2, getattribute/4, owner -- unused if (oparg & 1), unused)) { DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); assert(type_version != 0); assert(Py_IS_TYPE(getattribute, &PyFunction_Type)); PyFunctionObject *f = (PyFunctionObject *)getattribute; assert(func_version != 0); DEOPT_IF(f->func_version != func_version, LOAD_ATTR); PyCodeObject *code = (PyCodeObject *)f->func_code; assert(code->co_argcount == 2); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); Py_INCREF(f); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2); // Manipulate stack directly because we exit with DISPATCH_INLINED(). SET_TOP(NULL); int shrink_stack = !(oparg & 1); STACK_SHRINK(shrink_stack); new_frame->localsplus[0] = owner; new_frame->localsplus[1] = Py_NewRef(name); JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); } inst(STORE_ATTR_INSTANCE_VALUE, (unused/1, type_version/2, index/1, value, owner --)) { PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR); STAT_INC(STORE_ATTR, hit); PyDictValues *values = _PyDictOrValues_GetValues(dorv); PyObject *old_value = values->values[index]; values->values[index] = value; if (old_value == NULL) { _PyDictValues_AddToInsertionOrder(values, index); } else { Py_DECREF(old_value); } Py_DECREF(owner); } inst(STORE_ATTR_WITH_HINT, (unused/1, type_version/2, hint/1, value, owner --)) { PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(_PyDictOrValues_IsValues(dorv), STORE_ATTR); PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, STORE_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); PyObject *name = GETITEM(frame->f_code->co_names, oparg); DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR); PyObject *old_value; uint64_t new_version; if (DK_IS_UNICODE(dict->ma_keys)) { PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; DEOPT_IF(ep->me_key != name, STORE_ATTR); old_value = ep->me_value; DEOPT_IF(old_value == NULL, STORE_ATTR); new_version = _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, value); ep->me_value = value; } else { PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint; DEOPT_IF(ep->me_key != name, STORE_ATTR); old_value = ep->me_value; DEOPT_IF(old_value == NULL, STORE_ATTR); new_version = _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, value); ep->me_value = value; } Py_DECREF(old_value); STAT_INC(STORE_ATTR, hit); /* Ensure dict is GC tracked if it needs to be */ if (!_PyObject_GC_IS_TRACKED(dict) && _PyObject_GC_MAY_BE_TRACKED(value)) { _PyObject_GC_TRACK(dict); } /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); } inst(STORE_ATTR_SLOT, (unused/1, type_version/2, index/1, value, owner --)) { PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); char *addr = (char *)owner + index; STAT_INC(STORE_ATTR, hit); PyObject *old_value = *(PyObject **)addr; *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); } family(compare_op, INLINE_CACHE_ENTRIES_COMPARE_OP) = { COMPARE_OP, COMPARE_OP_FLOAT, COMPARE_OP_INT, COMPARE_OP_STR, }; inst(COMPARE_OP, (unused/1, left, right -- res)) { #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_CompareOp(left, right, next_instr, oparg); DISPATCH_SAME_OPARG(); } STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); DECREF_INPUTS(); ERROR_IF(res == NULL, error); } inst(COMPARE_OP_FLOAT, (unused/1, left, right -- res)) { DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); double dleft = PyFloat_AS_DOUBLE(left); double dright = PyFloat_AS_DOUBLE(right); // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg int sign_ish = COMPARISON_BIT(dleft, dright); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; } // Similar to COMPARE_OP_FLOAT inst(COMPARE_OP_INT, (unused/1, left, right -- res)) { DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && _PyLong_DigitCount((PyLongObject *)right) <= 1); Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left); Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; } // Similar to COMPARE_OP_FLOAT, but for ==, != only inst(COMPARE_OP_STR, (unused/1, left, right -- res)) { DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); int eq = _PyUnicode_Equal(left, right); assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); assert(eq == 0 || eq == 1); assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; } inst(IS_OP, (left, right -- b)) { int res = Py_Is(left, right) ^ oparg; DECREF_INPUTS(); b = res ? Py_True : Py_False; } inst(CONTAINS_OP, (left, right -- b)) { int res = PySequence_Contains(right, left); DECREF_INPUTS(); ERROR_IF(res < 0, error); b = (res ^ oparg) ? Py_True : Py_False; } inst(CHECK_EG_MATCH, (exc_value, match_type -- rest, match)) { if (check_except_star_type_valid(tstate, match_type) < 0) { DECREF_INPUTS(); ERROR_IF(true, error); } match = NULL; rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); DECREF_INPUTS(); ERROR_IF(res < 0, error); assert((match == NULL) == (rest == NULL)); ERROR_IF(match == NULL, error); if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } } inst(CHECK_EXC_MATCH, (left, right -- left, b)) { assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { DECREF_INPUTS(); ERROR_IF(true, error); } int res = PyErr_GivenExceptionMatches(left, right); DECREF_INPUTS(); b = res ? Py_True : Py_False; } inst(IMPORT_NAME, (level, fromlist -- res)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); DECREF_INPUTS(); ERROR_IF(res == NULL, error); } inst(IMPORT_FROM, (from -- from, res)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); ERROR_IF(res == NULL, error); } inst(JUMP_FORWARD, (--)) { JUMPBY(oparg); } inst(JUMP_BACKWARD, (--)) { _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); JUMPBY(1-oparg); #if ENABLE_SPECIALIZATION here[1].cache += (1 << OPTIMIZER_BITS_IN_COUNTER); if (here[1].cache > tstate->interp->optimizer_backedge_threshold) { OBJECT_STAT_INC(optimization_attempts); frame = _PyOptimizer_BackEdge(frame, here, next_instr, stack_pointer); if (frame == NULL) { frame = cframe.current_frame; goto error; } here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) -1); goto resume_frame; } #endif /* ENABLE_SPECIALIZATION */ CHECK_EVAL_BREAKER(); } inst(ENTER_EXECUTOR, (--)) { _PyExecutorObject *executor = (_PyExecutorObject *)frame->f_code->co_executors->executors[oparg]; Py_INCREF(executor); frame = executor->execute(executor, frame, stack_pointer); if (frame == NULL) { frame = cframe.current_frame; goto error; } goto resume_frame; } inst(POP_JUMP_IF_FALSE, (cond -- )) { if (Py_IsFalse(cond)) { JUMPBY(oparg); } else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); DECREF_INPUTS(); if (err == 0) { JUMPBY(oparg); } else { ERROR_IF(err < 0, error); } } } inst(POP_JUMP_IF_TRUE, (cond -- )) { if (Py_IsTrue(cond)) { JUMPBY(oparg); } else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); DECREF_INPUTS(); if (err > 0) { JUMPBY(oparg); } else { ERROR_IF(err < 0, error); } } } inst(POP_JUMP_IF_NOT_NONE, (value -- )) { if (!Py_IsNone(value)) { DECREF_INPUTS(); JUMPBY(oparg); } } inst(POP_JUMP_IF_NONE, (value -- )) { if (Py_IsNone(value)) { JUMPBY(oparg); } else { DECREF_INPUTS(); } } inst(JUMP_BACKWARD_NO_INTERRUPT, (--)) { /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); } inst(GET_LEN, (obj -- obj, len_o)) { // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); ERROR_IF(len_i < 0, error); len_o = PyLong_FromSsize_t(len_i); ERROR_IF(len_o == NULL, error); } inst(MATCH_CLASS, (subject, type, names -- attrs)) { // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); DECREF_INPUTS(); if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } else { ERROR_IF(_PyErr_Occurred(tstate), error); // Error! attrs = Py_None; // Failure! } } inst(MATCH_MAPPING, (subject -- subject, res)) { int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; } inst(MATCH_SEQUENCE, (subject -- subject, res)) { int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; } inst(MATCH_KEYS, (subject, keys -- subject, keys, values_or_none)) { // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); ERROR_IF(values_or_none == NULL, error); } inst(GET_ITER, (iterable -- iter)) { /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); DECREF_INPUTS(); ERROR_IF(iter == NULL, error); } inst(GET_YIELD_FROM_ITER, (iterable -- iter)) { /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ if (!(frame->f_code->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) { /* and it is used in a 'yield from' expression of a regular generator. */ _PyErr_SetString(tstate, PyExc_TypeError, "cannot 'yield from' a coroutine object " "in a non-coroutine generator"); goto error; } iter = iterable; } else if (PyGen_CheckExact(iterable)) { iter = iterable; } else { /* `iterable` is not a generator. */ iter = PyObject_GetIter(iterable); if (iter == NULL) { goto error; } DECREF_INPUTS(); } } // Most members of this family are "secretly" super-instructions. // When the loop is exhausted, they jump, and the jump target is // always END_FOR, which pops two values off the stack. // This is optimized by skipping that instruction and combining // its effect (popping 'iter' instead of pushing 'next'.) family(for_iter, INLINE_CACHE_ENTRIES_FOR_ITER) = { FOR_ITER, FOR_ITER_LIST, FOR_ITER_TUPLE, FOR_ITER_RANGE, FOR_ITER_GEN, }; inst(FOR_ITER, (unused/1, iter -- iter, next)) { #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_ForIter(iter, next_instr, oparg); DISPATCH_SAME_OPARG(); } STAT_INC(FOR_ITER, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next == NULL) { if (_PyErr_Occurred(tstate)) { if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { goto error; } monitor_raise(tstate, frame, next_instr-1); _PyErr_Clear(tstate); } /* iterator ended normally */ assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR || next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == INSTRUMENTED_END_FOR); Py_DECREF(iter); STACK_SHRINK(1); /* Jump forward oparg, then skip following END_FOR instruction */ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); DISPATCH(); } // Common case: no jump, leave it to the code generator } inst(INSTRUMENTED_FOR_ITER, ( -- )) { _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next != NULL) { PUSH(next); target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER; } else { if (_PyErr_Occurred(tstate)) { if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { goto error; } monitor_raise(tstate, frame, here); _PyErr_Clear(tstate); } /* iterator ended normally */ assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR || next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == INSTRUMENTED_END_FOR); STACK_SHRINK(1); Py_DECREF(iter); /* Skip END_FOR */ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); } inst(FOR_ITER_LIST, (unused/1, iter -- iter, next)) { DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); PyListObject *seq = it->it_seq; if (seq) { if (it->it_index < PyList_GET_SIZE(seq)) { next = Py_NewRef(PyList_GET_ITEM(seq, it->it_index++)); goto end_for_iter_list; // End of this instruction } it->it_seq = NULL; Py_DECREF(seq); } Py_DECREF(iter); STACK_SHRINK(1); /* Jump forward oparg, then skip following END_FOR instruction */ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator } inst(FOR_ITER_TUPLE, (unused/1, iter -- iter, next)) { _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); PyTupleObject *seq = it->it_seq; if (seq) { if (it->it_index < PyTuple_GET_SIZE(seq)) { next = Py_NewRef(PyTuple_GET_ITEM(seq, it->it_index++)); goto end_for_iter_tuple; // End of this instruction } it->it_seq = NULL; Py_DECREF(seq); } Py_DECREF(iter); STACK_SHRINK(1); /* Jump forward oparg, then skip following END_FOR instruction */ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator } inst(FOR_ITER_RANGE, (unused/1, iter -- iter, next)) { _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); if (r->len <= 0) { STACK_SHRINK(1); Py_DECREF(r); // Jump over END_FOR instruction. JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); DISPATCH(); } long value = r->start; r->start = value + r->step; r->len--; next = PyLong_FromLong(value); if (next == NULL) { goto error; } } inst(FOR_ITER_GEN, (unused/1, iter -- iter, unused)) { DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); STAT_INC(FOR_ITER, hit); _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; frame->return_offset = oparg; _PyFrame_StackPush(gen_frame, Py_None); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); } inst(BEFORE_ASYNC_WITH, (mgr -- exit, res)) { PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_Format(tstate, PyExc_TypeError, "'%.200s' object does not support the " "asynchronous context manager protocol", Py_TYPE(mgr)->tp_name); } goto error; } exit = _PyObject_LookupSpecial(mgr, &_Py_ID(__aexit__)); if (exit == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_Format(tstate, PyExc_TypeError, "'%.200s' object does not support the " "asynchronous context manager protocol " "(missed __aexit__ method)", Py_TYPE(mgr)->tp_name); } Py_DECREF(enter); goto error; } DECREF_INPUTS(); res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); ERROR_IF(true, error); } } inst(BEFORE_WITH, (mgr -- exit, res)) { /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__enter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_Format(tstate, PyExc_TypeError, "'%.200s' object does not support the " "context manager protocol", Py_TYPE(mgr)->tp_name); } goto error; } exit = _PyObject_LookupSpecial(mgr, &_Py_ID(__exit__)); if (exit == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_Format(tstate, PyExc_TypeError, "'%.200s' object does not support the " "context manager protocol " "(missed __exit__ method)", Py_TYPE(mgr)->tp_name); } Py_DECREF(enter); goto error; } DECREF_INPUTS(); res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); ERROR_IF(true, error); } } inst(WITH_EXCEPT_START, (exit_func, lasti, unused, val -- exit_func, lasti, unused, val, res)) { /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception - lasti: THIRD = lasti of exception in exc_info() - exit_func: FOURTH = the context.__exit__ bound method We call FOURTH(type(TOP), TOP, GetTraceback(TOP)). Then we push the __exit__ return value. */ PyObject *exc, *tb; assert(val && PyExceptionInstance_Check(val)); exc = PyExceptionInstance_Class(val); tb = PyException_GetTraceback(val); Py_XDECREF(tb); assert(PyLong_Check(lasti)); (void)lasti; // Shut up compiler warning if asserts are off PyObject *stack[4] = {NULL, exc, val, tb}; res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); ERROR_IF(res == NULL, error); } inst(PUSH_EXC_INFO, (new_exc -- prev_exc, new_exc)) { _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; } else { prev_exc = Py_None; } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); } inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (oparg & 1), res)) { /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self); DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); res2 = Py_NewRef(descr); assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); } inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (oparg & 1), res)) { PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; assert(oparg & 1); } inst(LOAD_ATTR_METHOD_LAZY_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (oparg & 1), res)) { PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; assert(dictoffset > 0); PyObject *dict = *(PyObject **)((char *)self + dictoffset); /* This object has a __dict__, just not yet created */ DEOPT_IF(dict != NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; assert(oparg & 1); } inst(KW_NAMES, (--)) { assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); } inst(INSTRUMENTED_CALL, ( -- )) { int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING : PEEK(total_args); int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, next_instr-1, function, arg); ERROR_IF(err, error); _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); } // Cache layout: counter/1, func_version/2 // Neither CALL_INTRINSIC_1/2 nor CALL_FUNCTION_EX are members! family(call, INLINE_CACHE_ENTRIES_CALL) = { CALL, CALL_BOUND_METHOD_EXACT_ARGS, CALL_PY_EXACT_ARGS, CALL_PY_WITH_DEFAULTS, CALL_NO_KW_TYPE_1, CALL_NO_KW_STR_1, CALL_NO_KW_TUPLE_1, CALL_BUILTIN_CLASS, CALL_NO_KW_BUILTIN_O, CALL_NO_KW_BUILTIN_FAST, CALL_BUILTIN_FAST_WITH_KEYWORDS, CALL_NO_KW_LEN, CALL_NO_KW_ISINSTANCE, CALL_NO_KW_LIST_APPEND, CALL_NO_KW_METHOD_DESCRIPTOR_O, CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, CALL_NO_KW_METHOD_DESCRIPTOR_FAST, }; // On entry, the stack is either // [NULL, callable, arg1, arg2, ...] // or // [method, self, arg1, arg2, ...] // (Some args may be keywords, see KW_NAMES, which sets 'kwnames'.) // On exit, the stack is [result]. // When calling Python, inline the call using DISPATCH_INLINED(). inst(CALL, (unused/1, unused/2, method, callable, args[oparg] -- res)) { int is_meth = method != NULL; int total_args = oparg; if (is_meth) { callable = method; args--; total_args++; } #if ENABLE_SPECIALIZATION _PyCallCache *cache = (_PyCallCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_Call(callable, next_instr, total_args, kwnames); DISPATCH_SAME_OPARG(); } STAT_INC(CALL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ if (!is_meth && Py_TYPE(callable) == &PyMethod_Type) { is_meth = 1; // For consistenct; it's dead, though args--; total_args++; PyObject *self = ((PyMethodObject *)callable)->im_self; args[0] = Py_NewRef(self); method = ((PyMethodObject *)callable)->im_func; args[-1] = Py_NewRef(method); Py_DECREF(callable); callable = method; } int positional_args = total_args - KWNAMES_LEN(); // Check if the call can be inlined or not if (Py_TYPE(callable) == &PyFunction_Type && tstate->interp->eval_frame == NULL && ((PyFunctionObject *)callable)->vectorcall == _PyFunction_Vectorcall) { int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable)); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( tstate, (PyFunctionObject *)callable, locals, args, positional_args, kwnames ); kwnames = NULL; // Manipulate stack directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); // The frame has stolen all the arguments from the stack, // so there is no need to clean them up. if (new_frame == NULL) { goto error; } JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); } /* Callable is not a normal Python function */ res = PyObject_Vectorcall( callable, args, positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames); if (opcode == INSTRUMENTED_CALL) { PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING : PEEK(total_args); if (res == NULL) { _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, frame, next_instr-1, callable, arg); } else { int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_C_RETURN, frame, next_instr-1, callable, arg); if (err < 0) { Py_CLEAR(res); } } } kwnames = NULL; assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(callable); for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } ERROR_IF(res == NULL, error); CHECK_EVAL_BREAKER(); } // Start out with [NULL, bound_method, arg1, arg2, ...] // Transform to [callable, self, arg1, arg2, ...] // Then fall through to CALL_PY_EXACT_ARGS inst(CALL_BOUND_METHOD_EXACT_ARGS, (unused/1, unused/2, method, callable, unused[oparg] -- unused)) { DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); PyObject *self = ((PyMethodObject *)callable)->im_self; PEEK(oparg + 1) = Py_NewRef(self); // callable PyObject *meth = ((PyMethodObject *)callable)->im_func; PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); } inst(CALL_PY_EXACT_ARGS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) { assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; int argcount = oparg; if (is_meth) { callable = method; args--; argcount++; } DEOPT_IF(!PyFunction_Check(callable), CALL); PyFunctionObject *func = (PyFunctionObject *)callable; DEOPT_IF(func->func_version != func_version, CALL); PyCodeObject *code = (PyCodeObject *)func->func_code; DEOPT_IF(code->co_argcount != argcount, CALL); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); STAT_INC(CALL, hit); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, func, argcount); for (int i = 0; i < argcount; i++) { new_frame->localsplus[i] = args[i]; } // Manipulate stack directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); } inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) { assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; int argcount = oparg; if (is_meth) { callable = method; args--; argcount++; } DEOPT_IF(!PyFunction_Check(callable), CALL); PyFunctionObject *func = (PyFunctionObject *)callable; DEOPT_IF(func->func_version != func_version, CALL); PyCodeObject *code = (PyCodeObject *)func->func_code; assert(func->func_defaults); assert(PyTuple_CheckExact(func->func_defaults)); int defcount = (int)PyTuple_GET_SIZE(func->func_defaults); assert(defcount <= code->co_argcount); int min_args = code->co_argcount - defcount; DEOPT_IF(argcount > code->co_argcount, CALL); DEOPT_IF(argcount < min_args, CALL); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); STAT_INC(CALL, hit); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, func, code->co_argcount); for (int i = 0; i < argcount; i++) { new_frame->localsplus[i] = args[i]; } for (int i = argcount; i < code->co_argcount; i++) { PyObject *def = PyTuple_GET_ITEM(func->func_defaults, i - min_args); new_frame->localsplus[i] = Py_NewRef(def); } // Manipulate stack and cache directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); } inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) { assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); PyObject *obj = args[0]; DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL); STAT_INC(CALL, hit); res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable } inst(CALL_NO_KW_STR_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) { assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL); STAT_INC(CALL, hit); PyObject *arg = args[0]; res = PyObject_Str(arg); Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable ERROR_IF(res == NULL, error); CHECK_EVAL_BREAKER(); } inst(CALL_NO_KW_TUPLE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) { assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyTuple_Type, CALL); STAT_INC(CALL, hit); PyObject *arg = args[0]; res = PySequence_Tuple(arg); Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple ERROR_IF(res == NULL, error); CHECK_EVAL_BREAKER(); } inst(CALL_BUILTIN_CLASS, (unused/1, unused/2, method, callable, args[oparg] -- res)) { int is_meth = method != NULL; int total_args = oparg; if (is_meth) { callable = method; args--; total_args++; } int kwnames_len = KWNAMES_LEN(); DEOPT_IF(!PyType_Check(callable), CALL); PyTypeObject *tp = (PyTypeObject *)callable; DEOPT_IF(tp->tp_vectorcall == NULL, CALL); STAT_INC(CALL, hit); res = tp->tp_vectorcall((PyObject *)tp, args, total_args - kwnames_len, kwnames); kwnames = NULL; /* Free the arguments. */ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } Py_DECREF(tp); ERROR_IF(res == NULL, error); CHECK_EVAL_BREAKER(); } inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, method, callable, args[oparg] -- res)) { /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { callable = method; args--; total_args++; } DEOPT_IF(total_args != 1, CALL); DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, CALL); STAT_INC(CALL, hit); PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); // This is slower but CPython promises to check all non-vectorcall // function calls. if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) { goto error; } PyObject *arg = args[0]; res = _PyCFunction_TrampolineCall(cfunc, PyCFunction_GET_SELF(callable), arg); _Py_LeaveRecursiveCallTstate(tstate); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(arg); Py_DECREF(callable); ERROR_IF(res == NULL, error); CHECK_EVAL_BREAKER(); } inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, method, callable, args[oparg] -- res)) { /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { callable = method; args--; total_args++; } DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL, CALL); STAT_INC(CALL, hit); PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); /* res = func(self, args, nargs) */ res = ((_PyCFunctionFast)(void(*)(void))cfunc)( PyCFunction_GET_SELF(callable), args, total_args); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); /* Free the arguments. */ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } Py_DECREF(callable); ERROR_IF(res == NULL, error); /* Not deopting because this doesn't mean our optimization was wrong. `res` can be NULL for valid reasons. Eg. getattr(x, 'invalid'). In those cases an exception is set, so we must handle it. */ CHECK_EVAL_BREAKER(); } inst(CALL_BUILTIN_FAST_WITH_KEYWORDS, (unused/1, unused/2, method, callable, args[oparg] -- res)) { /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; if (is_meth) { callable = method; args--; total_args++; } DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); DEOPT_IF(PyCFunction_GET_FLAGS(callable) != (METH_FASTCALL | METH_KEYWORDS), CALL); STAT_INC(CALL, hit); /* res = func(self, args, nargs, kwnames) */ _PyCFunctionFastWithKeywords cfunc = (_PyCFunctionFastWithKeywords)(void(*)(void)) PyCFunction_GET_FUNCTION(callable); res = cfunc( PyCFunction_GET_SELF(callable), args, total_args - KWNAMES_LEN(), kwnames ); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); kwnames = NULL; /* Free the arguments. */ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } Py_DECREF(callable); ERROR_IF(res == NULL, error); CHECK_EVAL_BREAKER(); } inst(CALL_NO_KW_LEN, (unused/1, unused/2, method, callable, args[oparg] -- res)) { assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; int total_args = oparg; if (is_meth) { callable = method; args--; total_args++; } DEOPT_IF(total_args != 1, CALL); PyInterpreterState *interp = _PyInterpreterState_GET(); DEOPT_IF(callable != interp->callable_cache.len, CALL); STAT_INC(CALL, hit); PyObject *arg = args[0]; Py_ssize_t len_i = PyObject_Length(arg); if (len_i < 0) { goto error; } res = PyLong_FromSsize_t(len_i); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(callable); Py_DECREF(arg); ERROR_IF(res == NULL, error); } inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, method, callable, args[oparg] -- res)) { assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; int total_args = oparg; if (is_meth) { callable = method; args--; total_args++; } DEOPT_IF(total_args != 2, CALL); PyInterpreterState *interp = _PyInterpreterState_GET(); DEOPT_IF(callable != interp->callable_cache.isinstance, CALL); STAT_INC(CALL, hit); PyObject *cls = args[1]; PyObject *inst = args[0]; int retval = PyObject_IsInstance(inst, cls); if (retval < 0) { goto error; } res = PyBool_FromLong(retval); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(inst); Py_DECREF(cls); Py_DECREF(callable); ERROR_IF(res == NULL, error); } // This is secretly a super-instruction inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, method, self, args[oparg] -- unused)) { assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); PyInterpreterState *interp = _PyInterpreterState_GET(); DEOPT_IF(method != interp->callable_cache.list_append, CALL); DEOPT_IF(!PyList_Check(self), CALL); STAT_INC(CALL, hit); if (_PyList_AppendTakeRef((PyListObject *)self, args[0]) < 0) { goto pop_1_error; // Since arg is DECREF'ed already } Py_DECREF(self); Py_DECREF(method); STACK_SHRINK(3); // CALL + POP_TOP JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); } inst(CALL_NO_KW_METHOD_DESCRIPTOR_O, (unused/1, unused/2, method, unused, args[oparg] -- res)) { assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { args--; total_args++; } PyMethodDescrObject *callable = (PyMethodDescrObject *)PEEK(total_args + 1); DEOPT_IF(total_args != 2, CALL); DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); PyMethodDef *meth = callable->d_method; DEOPT_IF(meth->ml_flags != METH_O, CALL); PyObject *arg = args[1]; PyObject *self = args[0]; DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); STAT_INC(CALL, hit); PyCFunction cfunc = meth->ml_meth; // This is slower but CPython promises to check all non-vectorcall // function calls. if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) { goto error; } res = _PyCFunction_TrampolineCall(cfunc, self, arg); _Py_LeaveRecursiveCallTstate(tstate); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(self); Py_DECREF(arg); Py_DECREF(callable); ERROR_IF(res == NULL, error); CHECK_EVAL_BREAKER(); } inst(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, (unused/1, unused/2, method, unused, args[oparg] -- res)) { int is_meth = method != NULL; int total_args = oparg; if (is_meth) { args--; total_args++; } PyMethodDescrObject *callable = (PyMethodDescrObject *)PEEK(total_args + 1); DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); PyMethodDef *meth = callable->d_method; DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), CALL); PyTypeObject *d_type = callable->d_common.d_type; PyObject *self = args[0]; DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL); STAT_INC(CALL, hit); int nargs = total_args - 1; _PyCFunctionFastWithKeywords cfunc = (_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; res = cfunc(self, args + 1, nargs - KWNAMES_LEN(), kwnames); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); kwnames = NULL; /* Free the arguments. */ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } Py_DECREF(callable); ERROR_IF(res == NULL, error); CHECK_EVAL_BREAKER(); } inst(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, method, unused, args[oparg] -- res)) { assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { args--; total_args++; } DEOPT_IF(total_args != 1, CALL); PyMethodDescrObject *callable = (PyMethodDescrObject *)SECOND(); DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); PyMethodDef *meth = callable->d_method; PyObject *self = args[0]; DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL); STAT_INC(CALL, hit); PyCFunction cfunc = meth->ml_meth; // This is slower but CPython promises to check all non-vectorcall // function calls. if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) { goto error; } res = _PyCFunction_TrampolineCall(cfunc, self, NULL); _Py_LeaveRecursiveCallTstate(tstate); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(self); Py_DECREF(callable); ERROR_IF(res == NULL, error); CHECK_EVAL_BREAKER(); } inst(CALL_NO_KW_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, method, unused, args[oparg] -- res)) { assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { args--; total_args++; } PyMethodDescrObject *callable = (PyMethodDescrObject *)PEEK(total_args + 1); /* Builtin METH_FASTCALL methods, without keywords */ DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); PyMethodDef *meth = callable->d_method; DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL); PyObject *self = args[0]; DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); STAT_INC(CALL, hit); _PyCFunctionFast cfunc = (_PyCFunctionFast)(void(*)(void))meth->ml_meth; int nargs = total_args - 1; res = cfunc(self, args + 1, nargs); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); /* Clear the stack of the arguments. */ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } Py_DECREF(callable); ERROR_IF(res == NULL, error); CHECK_EVAL_BREAKER(); } inst(INSTRUMENTED_CALL_FUNCTION_EX, ( -- )) { GO_TO_INSTRUCTION(CALL_FUNCTION_EX); } inst(CALL_FUNCTION_EX, (unused, func, callargs, kwargs if (oparg & 1) -- result)) { // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); if (!PyTuple_CheckExact(callargs)) { if (check_args_iterable(tstate, func, callargs) < 0) { goto error; } PyObject *tuple = PySequence_Tuple(callargs); if (tuple == NULL) { goto error; } Py_SETREF(callargs, tuple); } assert(PyTuple_CheckExact(callargs)); EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); if (opcode == INSTRUMENTED_CALL_FUNCTION_EX && !PyFunction_Check(func) && !PyMethod_Check(func) ) { PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? PyTuple_GET_ITEM(callargs, 0) : Py_None; int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, next_instr-1, func, arg); if (err) goto error; result = PyObject_Call(func, callargs, kwargs); if (result == NULL) { _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, frame, next_instr-1, func, arg); } else { int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_C_RETURN, frame, next_instr-1, func, arg); if (err < 0) { Py_CLEAR(result); } } } else { if (Py_TYPE(func) == &PyFunction_Type && tstate->interp->eval_frame == NULL && ((PyFunctionObject *)func)->vectorcall == _PyFunction_Vectorcall) { assert(PyTuple_CheckExact(callargs)); Py_ssize_t nargs = PyTuple_GET_SIZE(callargs); int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func)); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex(tstate, (PyFunctionObject *)func, locals, nargs, callargs, kwargs); // Need to manually shrink the stack since we exit with DISPATCH_INLINED. STACK_SHRINK(oparg + 3); if (new_frame == NULL) { goto error; } frame->return_offset = 0; DISPATCH_INLINED(new_frame); } result = PyObject_Call(func, callargs, kwargs); } DECREF_INPUTS(); assert(PEEK(3 + (oparg & 1)) == NULL); ERROR_IF(result == NULL, error); CHECK_EVAL_BREAKER(); } inst(MAKE_FUNCTION, (defaults if (oparg & MAKE_FUNCTION_DEFAULTS), kwdefaults if (oparg & MAKE_FUNCTION_KWDEFAULTS), annotations if (oparg & MAKE_FUNCTION_ANNOTATIONS), closure if (oparg & MAKE_FUNCTION_CLOSURE), codeobj -- func)) { PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); Py_DECREF(codeobj); if (func_obj == NULL) { goto error; } if (oparg & MAKE_FUNCTION_CLOSURE) { assert(PyTuple_CheckExact(closure)); func_obj->func_closure = closure; } if (oparg & MAKE_FUNCTION_ANNOTATIONS) { assert(PyTuple_CheckExact(annotations)); func_obj->func_annotations = annotations; } if (oparg & MAKE_FUNCTION_KWDEFAULTS) { assert(PyDict_CheckExact(kwdefaults)); func_obj->func_kwdefaults = kwdefaults; } if (oparg & MAKE_FUNCTION_DEFAULTS) { assert(PyTuple_CheckExact(defaults)); func_obj->func_defaults = defaults; } func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; } inst(RETURN_GENERATOR, (--)) { assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); if (gen == NULL) { goto error; } assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; _PyFrame_Copy(frame, gen_frame); assert(frame->frame_obj == NULL); gen->gi_frame_state = FRAME_CREATED; gen_frame->owner = FRAME_OWNED_BY_GENERATOR; _Py_LeaveRecursiveCallPy(tstate); assert(frame != &entry_frame); _PyInterpreterFrame *prev = frame->previous; _PyThreadState_PopFrame(tstate, frame); frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; } inst(BUILD_SLICE, (start, stop, step if (oparg == 3) -- slice)) { slice = PySlice_New(start, stop, step); DECREF_INPUTS(); ERROR_IF(slice == NULL, error); } inst(FORMAT_VALUE, (value, fmt_spec if ((oparg & FVS_MASK) == FVS_HAVE_SPEC) -- result)) { /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; /* See if any conversion is specified. */ switch (which_conversion) { case FVC_NONE: conv_fn = NULL; break; case FVC_STR: conv_fn = PyObject_Str; break; case FVC_REPR: conv_fn = PyObject_Repr; break; case FVC_ASCII: conv_fn = PyObject_ASCII; break; default: _PyErr_Format(tstate, PyExc_SystemError, "unexpected conversion flag %d", which_conversion); goto error; } /* If there's a conversion function, call it and replace value with that result. Otherwise, just use value, without conversion. */ if (conv_fn != NULL) { result = conv_fn(value); Py_DECREF(value); if (result == NULL) { Py_XDECREF(fmt_spec); ERROR_IF(true, error); } value = result; } result = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_XDECREF(fmt_spec); ERROR_IF(result == NULL, error); } inst(COPY, (bottom, unused[oparg-1] -- bottom, unused[oparg-1], top)) { assert(oparg > 0); top = Py_NewRef(bottom); } inst(BINARY_OP, (unused/1, lhs, rhs -- res)) { #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, &GETLOCAL(0)); DISPATCH_SAME_OPARG(); } STAT_INC(BINARY_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ assert(0 <= oparg); assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); DECREF_INPUTS(); ERROR_IF(res == NULL, error); } inst(SWAP, (bottom, unused[oparg-2], top -- top, unused[oparg-2], bottom)) { assert(oparg >= 2); } inst(INSTRUMENTED_INSTRUCTION, ( -- )) { int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); ERROR_IF(next_opcode < 0, error); next_instr--; if (_PyOpcode_Caches[next_opcode]) { _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1); INCREMENT_ADAPTIVE_COUNTER(cache->counter); } assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); } inst(INSTRUMENTED_JUMP_FORWARD, ( -- )) { INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); } inst(INSTRUMENTED_JUMP_BACKWARD, ( -- )) { INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); CHECK_EVAL_BREAKER(); } inst(INSTRUMENTED_POP_JUMP_IF_TRUE, ( -- )) { PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); ERROR_IF(err < 0, error); _Py_CODEUNIT *here = next_instr-1; assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); } inst(INSTRUMENTED_POP_JUMP_IF_FALSE, ( -- )) { PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); ERROR_IF(err < 0, error); _Py_CODEUNIT *here = next_instr-1; assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); } inst(INSTRUMENTED_POP_JUMP_IF_NONE, ( -- )) { PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; if (Py_IsNone(value)) { offset = oparg; } else { Py_DECREF(value); offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); } inst(INSTRUMENTED_POP_JUMP_IF_NOT_NONE, ( -- )) { PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; if (Py_IsNone(value)) { offset = 0; } else { Py_DECREF(value); offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); } inst(EXTENDED_ARG, ( -- )) { assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); } inst(CACHE, (--)) { assert(0 && "Executing a cache."); Py_UNREACHABLE(); } inst(RESERVED, (--)) { assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); } // END BYTECODES // } dispatch_opcode: error: exception_unwind: exit_unwind: handle_eval_breaker: resume_frame: resume_with_error: start_frame: unbound_local_error: ; } // Future families go below this point // ================================================ FILE: CeVal.c ================================================ /* Execute compiled code */ #define _PY_INTERPRETER #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_call.h" // _PyObject_FastCallDictTstate() #include "pycore_ceval.h" // _PyEval_SignalAsyncExc() #include "pycore_code.h" #include "pycore_function.h" #include "pycore_intrinsics.h" #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_instruments.h" #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_moduleobject.h" // PyModuleObject #include "pycore_opcode.h" // EXTRA_CASES #include "pycore_opcode_utils.h" // MAKE_FUNCTION_* #include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_range.h" // _PyRangeIterObject #include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs #include "pycore_sysmodule.h" // _PySys_Audit() #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "pycore_typeobject.h" // _PySuper_Lookup() #include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS #include "pycore_dict.h" #include "dictobject.h" #include "pycore_frame.h" #include "frameobject.h" // _PyInterpreterFrame_GetLine #include "opcode.h" #include "pydtrace.h" #include "setobject.h" #include "structmember.h" // struct PyMemberDef, T_OFFSET_EX #include #include #ifdef Py_DEBUG /* For debugging the interpreter: */ # define LLTRACE 1 /* Low-level trace feature */ #endif #if !defined(Py_BUILD_CORE) # error "ceval.c must be build with Py_BUILD_CORE define for best performance" #endif #if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) // GH-89279: The MSVC compiler does not inline these static inline functions // in PGO build in _PyEval_EvalFrameDefault(), because this function is over // the limit of PGO, and that limit cannot be configured. // Define them as macros to make sure that they are always inlined by the // preprocessor. #undef Py_DECREF #define Py_DECREF(arg) \ do { \ PyObject *op = _PyObject_CAST(arg); \ if (_Py_IsImmortal(op)) { \ break; \ } \ _Py_DECREF_STAT_INC(); \ if (--op->ob_refcnt == 0) { \ destructor dealloc = Py_TYPE(op)->tp_dealloc; \ (*dealloc)(op); \ } \ } while (0) #undef Py_XDECREF #define Py_XDECREF(arg) \ do { \ PyObject *xop = _PyObject_CAST(arg); \ if (xop != NULL) { \ Py_DECREF(xop); \ } \ } while (0) #undef Py_IS_TYPE #define Py_IS_TYPE(ob, type) \ (_PyObject_CAST(ob)->ob_type == (type)) #undef _Py_DECREF_SPECIALIZED #define _Py_DECREF_SPECIALIZED(arg, dealloc) \ do { \ PyObject *op = _PyObject_CAST(arg); \ if (_Py_IsImmortal(op)) { \ break; \ } \ _Py_DECREF_STAT_INC(); \ if (--op->ob_refcnt == 0) { \ destructor d = (destructor)(dealloc); \ d(op); \ } \ } while (0) #endif // GH-89279: Similar to above, force inlining by using a macro. #if defined(_MSC_VER) && SIZEOF_INT == 4 #define _Py_atomic_load_relaxed_int32(ATOMIC_VAL) (assert(sizeof((ATOMIC_VAL)->_value) == 4), *((volatile int*)&((ATOMIC_VAL)->_value))) #else #define _Py_atomic_load_relaxed_int32(ATOMIC_VAL) _Py_atomic_load_relaxed(ATOMIC_VAL) #endif #ifdef LLTRACE static void dump_stack(_PyInterpreterFrame *frame, PyObject **stack_pointer) { PyObject **stack_base = _PyFrame_Stackbase(frame); PyObject *exc = PyErr_GetRaisedException(); printf(" stack=["); for (PyObject **ptr = stack_base; ptr < stack_pointer; ptr++) { if (ptr != stack_base) { printf(", "); } if (PyObject_Print(*ptr, stdout, 0) != 0) { PyErr_Clear(); printf("<%s object at %p>", Py_TYPE(*ptr)->tp_name, (void *)(*ptr)); } } printf("]\n"); fflush(stdout); PyErr_SetRaisedException(exc); } static void lltrace_instruction(_PyInterpreterFrame *frame, PyObject **stack_pointer, _Py_CODEUNIT *next_instr) { /* This dump_stack() operation is risky, since the repr() of some objects enters the interpreter recursively. It is also slow. So you might want to comment it out. */ dump_stack(frame, stack_pointer); int oparg = next_instr->op.arg; int opcode = next_instr->op.code; const char *opname = _PyOpcode_OpName[opcode]; assert(opname != NULL); int offset = (int)(next_instr - _PyCode_CODE(frame->f_code)); if (HAS_ARG((int)_PyOpcode_Deopt[opcode])) { printf("%d: %s %d\n", offset * 2, opname, oparg); } else { printf("%d: %s\n", offset * 2, opname); } fflush(stdout); } static void lltrace_resume_frame(_PyInterpreterFrame *frame) { PyObject *fobj = frame->f_funcobj; if (frame->owner == FRAME_OWNED_BY_CSTACK || fobj == NULL || !PyFunction_Check(fobj) ) { printf("\nResuming frame.\n"); return; } PyFunctionObject *f = (PyFunctionObject *)fobj; PyObject *exc = PyErr_GetRaisedException(); PyObject *name = f->func_qualname; if (name == NULL) { name = f->func_name; } printf("\nResuming frame"); if (name) { printf(" for "); if (PyObject_Print(name, stdout, 0) < 0) { PyErr_Clear(); } } if (f->func_module) { printf(" in module "); if (PyObject_Print(f->func_module, stdout, 0) < 0) { PyErr_Clear(); } } printf("\n"); fflush(stdout); PyErr_SetRaisedException(exc); } #endif static void monitor_raise(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); static int monitor_stop_iteration(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); static void monitor_unwind(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); static void monitor_handled(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *exc); static void monitor_throw(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); static PyObject * import_name(PyThreadState *, _PyInterpreterFrame *, PyObject *, PyObject *, PyObject *); static PyObject * import_from(PyThreadState *, PyObject *, PyObject *); static void format_exc_check_arg(PyThreadState *, PyObject *, const char *, PyObject *); static void format_exc_unbound(PyThreadState *tstate, PyCodeObject *co, int oparg); static int check_args_iterable(PyThreadState *, PyObject *func, PyObject *vararg); static int check_except_type_valid(PyThreadState *tstate, PyObject* right); static int check_except_star_type_valid(PyThreadState *tstate, PyObject* right); static void format_kwargs_error(PyThreadState *, PyObject *func, PyObject *kwargs); static void format_awaitable_error(PyThreadState *, PyTypeObject *, int); static int get_exception_handler(PyCodeObject *, int, int*, int*, int*); static _PyInterpreterFrame * _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func, PyObject *locals, PyObject* const* args, size_t argcount, PyObject *kwnames); static _PyInterpreterFrame * _PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func, PyObject *locals, Py_ssize_t nargs, PyObject *callargs, PyObject *kwargs); static void _PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame); #define UNBOUNDLOCAL_ERROR_MSG \ "cannot access local variable '%s' where it is not associated with a value" #define UNBOUNDFREE_ERROR_MSG \ "cannot access free variable '%s' where it is not associated with a" \ " value in enclosing scope" #ifdef HAVE_ERRNO_H #include #endif int Py_GetRecursionLimit(void) { PyInterpreterState *interp = _PyInterpreterState_GET(); return interp->ceval.recursion_limit; } void Py_SetRecursionLimit(int new_limit) { PyInterpreterState *interp = _PyInterpreterState_GET(); interp->ceval.recursion_limit = new_limit; for (PyThreadState *p = interp->threads.head; p != NULL; p = p->next) { int depth = p->py_recursion_limit - p->py_recursion_remaining; p->py_recursion_limit = new_limit; p->py_recursion_remaining = new_limit - depth; } } /* The function _Py_EnterRecursiveCallTstate() only calls _Py_CheckRecursiveCall() if the recursion_depth reaches recursion_limit. */ int _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where) { #ifdef USE_STACKCHECK if (PyOS_CheckStack()) { ++tstate->c_recursion_remaining; _PyErr_SetString(tstate, PyExc_MemoryError, "Stack overflow"); return -1; } #endif if (tstate->recursion_headroom) { if (tstate->c_recursion_remaining < -50) { /* Overflowing while handling an overflow. Give up. */ Py_FatalError("Cannot recover from stack overflow."); } } else { if (tstate->c_recursion_remaining <= 0) { tstate->recursion_headroom++; _PyErr_Format(tstate, PyExc_RecursionError, "maximum recursion depth exceeded%s", where); tstate->recursion_headroom--; ++tstate->c_recursion_remaining; return -1; } } return 0; } static const binaryfunc binary_ops[] = { [NB_ADD] = PyNumber_Add, [NB_AND] = PyNumber_And, [NB_FLOOR_DIVIDE] = PyNumber_FloorDivide, [NB_LSHIFT] = PyNumber_Lshift, [NB_MATRIX_MULTIPLY] = PyNumber_MatrixMultiply, [NB_MULTIPLY] = PyNumber_Multiply, [NB_REMAINDER] = PyNumber_Remainder, [NB_OR] = PyNumber_Or, [NB_POWER] = _PyNumber_PowerNoMod, [NB_RSHIFT] = PyNumber_Rshift, [NB_SUBTRACT] = PyNumber_Subtract, [NB_TRUE_DIVIDE] = PyNumber_TrueDivide, [NB_XOR] = PyNumber_Xor, [NB_INPLACE_ADD] = PyNumber_InPlaceAdd, [NB_INPLACE_AND] = PyNumber_InPlaceAnd, [NB_INPLACE_FLOOR_DIVIDE] = PyNumber_InPlaceFloorDivide, [NB_INPLACE_LSHIFT] = PyNumber_InPlaceLshift, [NB_INPLACE_MATRIX_MULTIPLY] = PyNumber_InPlaceMatrixMultiply, [NB_INPLACE_MULTIPLY] = PyNumber_InPlaceMultiply, [NB_INPLACE_REMAINDER] = PyNumber_InPlaceRemainder, [NB_INPLACE_OR] = PyNumber_InPlaceOr, [NB_INPLACE_POWER] = _PyNumber_InPlacePowerNoMod, [NB_INPLACE_RSHIFT] = PyNumber_InPlaceRshift, [NB_INPLACE_SUBTRACT] = PyNumber_InPlaceSubtract, [NB_INPLACE_TRUE_DIVIDE] = PyNumber_InPlaceTrueDivide, [NB_INPLACE_XOR] = PyNumber_InPlaceXor, }; // PEP 634: Structural Pattern Matching // Return a tuple of values corresponding to keys, with error checks for // duplicate/missing keys. static PyObject* match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys) { assert(PyTuple_CheckExact(keys)); Py_ssize_t nkeys = PyTuple_GET_SIZE(keys); if (!nkeys) { // No keys means no items. return PyTuple_New(0); } PyObject *seen = NULL; PyObject *dummy = NULL; PyObject *values = NULL; PyObject *get = NULL; // We use the two argument form of map.get(key, default) for two reasons: // - Atomically check for a key and get its value without error handling. // - Don't cause key creation or resizing in dict subclasses like // collections.defaultdict that define __missing__ (or similar). int meth_found = _PyObject_GetMethod(map, &_Py_ID(get), &get); if (get == NULL) { goto fail; } seen = PySet_New(NULL); if (seen == NULL) { goto fail; } // dummy = object() dummy = _PyObject_CallNoArgs((PyObject *)&PyBaseObject_Type); if (dummy == NULL) { goto fail; } values = PyTuple_New(nkeys); if (values == NULL) { goto fail; } for (Py_ssize_t i = 0; i < nkeys; i++) { PyObject *key = PyTuple_GET_ITEM(keys, i); if (PySet_Contains(seen, key) || PySet_Add(seen, key)) { if (!_PyErr_Occurred(tstate)) { // Seen it before! _PyErr_Format(tstate, PyExc_ValueError, "mapping pattern checks duplicate key (%R)", key); } goto fail; } PyObject *args[] = { map, key, dummy }; PyObject *value = NULL; if (meth_found) { value = PyObject_Vectorcall(get, args, 3, NULL); } else { value = PyObject_Vectorcall(get, &args[1], 2, NULL); } if (value == NULL) { goto fail; } if (value == dummy) { // key not in map! Py_DECREF(value); Py_DECREF(values); // Return None: values = Py_NewRef(Py_None); goto done; } PyTuple_SET_ITEM(values, i, value); } // Success: done: Py_DECREF(get); Py_DECREF(seen); Py_DECREF(dummy); return values; fail: Py_XDECREF(get); Py_XDECREF(seen); Py_XDECREF(dummy); Py_XDECREF(values); return NULL; } // Extract a named attribute from the subject, with additional bookkeeping to // raise TypeErrors for repeated lookups. On failure, return NULL (with no // error set). Use _PyErr_Occurred(tstate) to disambiguate. static PyObject* match_class_attr(PyThreadState *tstate, PyObject *subject, PyObject *type, PyObject *name, PyObject *seen) { assert(PyUnicode_CheckExact(name)); assert(PySet_CheckExact(seen)); if (PySet_Contains(seen, name) || PySet_Add(seen, name)) { if (!_PyErr_Occurred(tstate)) { // Seen it before! _PyErr_Format(tstate, PyExc_TypeError, "%s() got multiple sub-patterns for attribute %R", ((PyTypeObject*)type)->tp_name, name); } return NULL; } PyObject *attr = PyObject_GetAttr(subject, name); if (attr == NULL && _PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { _PyErr_Clear(tstate); } return attr; } // On success (match), return a tuple of extracted attributes. On failure (no // match), return NULL. Use _PyErr_Occurred(tstate) to disambiguate. static PyObject* match_class(PyThreadState *tstate, PyObject *subject, PyObject *type, Py_ssize_t nargs, PyObject *kwargs) { if (!PyType_Check(type)) { const char *e = "called match pattern must be a class"; _PyErr_Format(tstate, PyExc_TypeError, e); return NULL; } assert(PyTuple_CheckExact(kwargs)); // First, an isinstance check: if (PyObject_IsInstance(subject, type) <= 0) { return NULL; } // So far so good: PyObject *seen = PySet_New(NULL); if (seen == NULL) { return NULL; } PyObject *attrs = PyList_New(0); if (attrs == NULL) { Py_DECREF(seen); return NULL; } // NOTE: From this point on, goto fail on failure: PyObject *match_args = NULL; // First, the positional subpatterns: if (nargs) { int match_self = 0; match_args = PyObject_GetAttrString(type, "__match_args__"); if (match_args) { if (!PyTuple_CheckExact(match_args)) { const char *e = "%s.__match_args__ must be a tuple (got %s)"; _PyErr_Format(tstate, PyExc_TypeError, e, ((PyTypeObject *)type)->tp_name, Py_TYPE(match_args)->tp_name); goto fail; } } else if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { _PyErr_Clear(tstate); // _Py_TPFLAGS_MATCH_SELF is only acknowledged if the type does not // define __match_args__. This is natural behavior for subclasses: // it's as if __match_args__ is some "magic" value that is lost as // soon as they redefine it. match_args = PyTuple_New(0); match_self = PyType_HasFeature((PyTypeObject*)type, _Py_TPFLAGS_MATCH_SELF); } else { goto fail; } assert(PyTuple_CheckExact(match_args)); Py_ssize_t allowed = match_self ? 1 : PyTuple_GET_SIZE(match_args); if (allowed < nargs) { const char *plural = (allowed == 1) ? "" : "s"; _PyErr_Format(tstate, PyExc_TypeError, "%s() accepts %d positional sub-pattern%s (%d given)", ((PyTypeObject*)type)->tp_name, allowed, plural, nargs); goto fail; } if (match_self) { // Easy. Copy the subject itself, and move on to kwargs. PyList_Append(attrs, subject); } else { for (Py_ssize_t i = 0; i < nargs; i++) { PyObject *name = PyTuple_GET_ITEM(match_args, i); if (!PyUnicode_CheckExact(name)) { _PyErr_Format(tstate, PyExc_TypeError, "__match_args__ elements must be strings " "(got %s)", Py_TYPE(name)->tp_name); goto fail; } PyObject *attr = match_class_attr(tstate, subject, type, name, seen); if (attr == NULL) { goto fail; } PyList_Append(attrs, attr); Py_DECREF(attr); } } Py_CLEAR(match_args); } // Finally, the keyword subpatterns: for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(kwargs); i++) { PyObject *name = PyTuple_GET_ITEM(kwargs, i); PyObject *attr = match_class_attr(tstate, subject, type, name, seen); if (attr == NULL) { goto fail; } PyList_Append(attrs, attr); Py_DECREF(attr); } Py_SETREF(attrs, PyList_AsTuple(attrs)); Py_DECREF(seen); return attrs; fail: // We really don't care whether an error was raised or not... that's our // caller's problem. All we know is that the match failed. Py_XDECREF(match_args); Py_DECREF(seen); Py_DECREF(attrs); return NULL; } static int do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause); static int exception_group_match( PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest); static int unpack_iterable(PyThreadState *, PyObject *, int, int, PyObject **); PyObject * PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals) { PyThreadState *tstate = _PyThreadState_GET(); if (locals == NULL) { locals = globals; } PyObject *builtins = _PyEval_BuiltinsFromGlobals(tstate, globals); // borrowed ref if (builtins == NULL) { return NULL; } PyFrameConstructor desc = { .fc_globals = globals, .fc_builtins = builtins, .fc_name = ((PyCodeObject *)co)->co_name, .fc_qualname = ((PyCodeObject *)co)->co_name, .fc_code = co, .fc_defaults = NULL, .fc_kwdefaults = NULL, .fc_closure = NULL }; PyFunctionObject *func = _PyFunction_FromConstructor(&desc); if (func == NULL) { return NULL; } EVAL_CALL_STAT_INC(EVAL_CALL_LEGACY); PyObject *res = _PyEval_Vector(tstate, func, locals, NULL, 0, NULL); Py_DECREF(func); return res; } /* Interpreter main loop */ PyObject * PyEval_EvalFrame(PyFrameObject *f) { /* Function kept for backward compatibility */ PyThreadState *tstate = _PyThreadState_GET(); return _PyEval_EvalFrame(tstate, f->f_frame, 0); } PyObject * PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) { PyThreadState *tstate = _PyThreadState_GET(); return _PyEval_EvalFrame(tstate, f->f_frame, throwflag); } #include "ceval_macros.h" int _Py_CheckRecursiveCallPy( PyThreadState *tstate) { if (tstate->recursion_headroom) { if (tstate->py_recursion_remaining < -50) { /* Overflowing while handling an overflow. Give up. */ Py_FatalError("Cannot recover from Python stack overflow."); } } else { if (tstate->py_recursion_remaining <= 0) { tstate->recursion_headroom++; _PyErr_Format(tstate, PyExc_RecursionError, "maximum recursion depth exceeded"); tstate->recursion_headroom--; return -1; } } return 0; } static inline int _Py_EnterRecursivePy(PyThreadState *tstate) { return (tstate->py_recursion_remaining-- <= 0) && _Py_CheckRecursiveCallPy(tstate); } static inline void _Py_LeaveRecursiveCallPy(PyThreadState *tstate) { tstate->py_recursion_remaining++; } /* Disable unused label warnings. They are handy for debugging, even if computed gotos aren't used. */ /* TBD - what about other compilers? */ #if defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-label" #elif defined(_MSC_VER) /* MS_WINDOWS */ # pragma warning(push) # pragma warning(disable:4102) #endif PyObject* _Py_HOT_FUNCTION _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag) { _Py_EnsureTstateNotNULL(tstate); CALL_STAT_INC(pyeval_calls); #if USE_COMPUTED_GOTOS /* Import the static jump table */ #include "opcode_targets.h" #endif #ifdef Py_STATS int lastopcode = 0; #endif // opcode is an 8-bit value to improve the code generated by MSVC // for the big switch below (in combination with the EXTRA_CASES macro). uint8_t opcode; /* Current opcode */ int oparg; /* Current opcode argument, if any */ #ifdef LLTRACE int lltrace = 0; #endif _PyCFrame cframe; _PyInterpreterFrame entry_frame; PyObject *kwnames = NULL; // Borrowed reference. Reset by CALL instructions. /* WARNING: Because the _PyCFrame lives on the C stack, * but can be accessed from a heap allocated object (tstate) * strict stack discipline must be maintained. */ _PyCFrame *prev_cframe = tstate->cframe; cframe.previous = prev_cframe; tstate->cframe = &cframe; assert(tstate->interp->interpreter_trampoline != NULL); #ifdef Py_DEBUG /* Set these to invalid but identifiable values for debugging. */ entry_frame.f_funcobj = (PyObject*)0xaaa0; entry_frame.f_locals = (PyObject*)0xaaa1; entry_frame.frame_obj = (PyFrameObject*)0xaaa2; entry_frame.f_globals = (PyObject*)0xaaa3; entry_frame.f_builtins = (PyObject*)0xaaa4; #endif entry_frame.f_code = tstate->interp->interpreter_trampoline; entry_frame.prev_instr = _PyCode_CODE(tstate->interp->interpreter_trampoline); entry_frame.stacktop = 0; entry_frame.owner = FRAME_OWNED_BY_CSTACK; entry_frame.return_offset = 0; /* Push frame */ entry_frame.previous = prev_cframe->current_frame; frame->previous = &entry_frame; cframe.current_frame = frame; if (_Py_EnterRecursiveCallTstate(tstate, "")) { tstate->c_recursion_remaining--; tstate->py_recursion_remaining--; goto exit_unwind; } /* support for generator.throw() */ if (throwflag) { if (_Py_EnterRecursivePy(tstate)) { goto exit_unwind; } /* Because this avoids the RESUME, * we need to update instrumentation */ _Py_Instrument(frame->f_code, tstate->interp); monitor_throw(tstate, frame, frame->prev_instr); /* TO DO -- Monitor throw entry. */ goto resume_with_error; } /* Local "register" variables. * These are cached values from the frame and code object. */ _Py_CODEUNIT *next_instr; PyObject **stack_pointer; /* Sets the above local variables from the frame */ #define SET_LOCALS_FROM_FRAME() \ assert(_PyInterpreterFrame_LASTI(frame) >= -1); \ /* Jump back to the last instruction executed... */ \ next_instr = frame->prev_instr + 1; \ stack_pointer = _PyFrame_GetStackPointer(frame); start_frame: if (_Py_EnterRecursivePy(tstate)) { goto exit_unwind; } resume_frame: SET_LOCALS_FROM_FRAME(); #ifdef LLTRACE { if (frame != &entry_frame) { int r = PyDict_Contains(GLOBALS(), &_Py_ID(__lltrace__)); if (r < 0) { goto exit_unwind; } lltrace = r; } if (lltrace) { lltrace_resume_frame(frame); } } #endif #ifdef Py_DEBUG /* _PyEval_EvalFrameDefault() must not be called with an exception set, because it can clear it (directly or indirectly) and so the caller loses its exception */ assert(!_PyErr_Occurred(tstate)); #endif DISPATCH(); handle_eval_breaker: /* Do periodic things, like check for signals and async I/0. * We need to do reasonably frequently, but not too frequently. * All loops should include a check of the eval breaker. * We also check on return from any builtin function. */ if (_Py_HandlePending(tstate) != 0) { goto error; } DISPATCH(); { /* Start instructions */ #if !USE_COMPUTED_GOTOS dispatch_opcode: switch (opcode) #endif { #include "generated_cases.c.h" /* INSTRUMENTED_LINE has to be here, rather than in bytecodes.c, * because it needs to capture frame->prev_instr before it is updated, * as happens in the standard instruction prologue. */ #if USE_COMPUTED_GOTOS TARGET_INSTRUMENTED_LINE: #else case INSTRUMENTED_LINE: #endif { _Py_CODEUNIT *prev = frame->prev_instr; _Py_CODEUNIT *here = frame->prev_instr = next_instr; _PyFrame_SetStackPointer(frame, stack_pointer); int original_opcode = _Py_call_instrumentation_line( tstate, frame, here, prev); stack_pointer = _PyFrame_GetStackPointer(frame); if (original_opcode < 0) { next_instr = here+1; goto error; } next_instr = frame->prev_instr; if (next_instr != here) { DISPATCH(); } if (_PyOpcode_Caches[original_opcode]) { _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1); /* Prevent the underlying instruction from specializing * and overwriting the instrumentation. */ INCREMENT_ADAPTIVE_COUNTER(cache->counter); } opcode = original_opcode; DISPATCH_GOTO(); } #if USE_COMPUTED_GOTOS _unknown_opcode: #else EXTRA_CASES // From opcode.h, a 'case' for each unused opcode #endif /* Tell C compilers not to hold the opcode variable in the loop. next_instr points the current instruction without TARGET(). */ opcode = next_instr->op.code; _PyErr_Format(tstate, PyExc_SystemError, "%U:%d: unknown opcode %d", frame->f_code->co_filename, PyUnstable_InterpreterFrame_GetLine(frame), opcode); goto error; } /* End instructions */ /* This should never be reached. Every opcode should end with DISPATCH() or goto error. */ Py_UNREACHABLE(); unbound_local_error: { format_exc_check_arg(tstate, PyExc_UnboundLocalError, UNBOUNDLOCAL_ERROR_MSG, PyTuple_GetItem(frame->f_code->co_localsplusnames, oparg) ); goto error; } pop_4_error: STACK_SHRINK(1); pop_3_error: STACK_SHRINK(1); pop_2_error: STACK_SHRINK(1); pop_1_error: STACK_SHRINK(1); error: kwnames = NULL; /* Double-check exception status. */ #ifdef NDEBUG if (!_PyErr_Occurred(tstate)) { _PyErr_SetString(tstate, PyExc_SystemError, "error return without exception set"); } #else assert(_PyErr_Occurred(tstate)); #endif /* Log traceback info. */ assert(frame != &entry_frame); if (!_PyFrame_IsIncomplete(frame)) { PyFrameObject *f = _PyFrame_GetFrameObject(frame); if (f != NULL) { PyTraceBack_Here(f); } } monitor_raise(tstate, frame, next_instr-1); exception_unwind: { /* We can't use frame->f_lasti here, as RERAISE may have set it */ int offset = INSTR_OFFSET()-1; int level, handler, lasti; if (get_exception_handler(frame->f_code, offset, &level, &handler, &lasti) == 0) { // No handlers, so exit. assert(_PyErr_Occurred(tstate)); /* Pop remaining stack entries. */ PyObject **stackbase = _PyFrame_Stackbase(frame); while (stack_pointer > stackbase) { PyObject *o = POP(); Py_XDECREF(o); } assert(STACK_LEVEL() == 0); _PyFrame_SetStackPointer(frame, stack_pointer); monitor_unwind(tstate, frame, next_instr-1); goto exit_unwind; } assert(STACK_LEVEL() >= level); PyObject **new_top = _PyFrame_Stackbase(frame) + level; while (stack_pointer > new_top) { PyObject *v = POP(); Py_XDECREF(v); } if (lasti) { int frame_lasti = _PyInterpreterFrame_LASTI(frame); PyObject *lasti = PyLong_FromLong(frame_lasti); if (lasti == NULL) { goto exception_unwind; } PUSH(lasti); } /* Make the raw exception data available to the handler, so a program can emulate the Python main loop. */ PyObject *exc = _PyErr_GetRaisedException(tstate); PUSH(exc); JUMPTO(handler); monitor_handled(tstate, frame, next_instr, exc); /* Resume normal execution */ DISPATCH(); } } exit_unwind: assert(_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallPy(tstate); assert(frame != &entry_frame); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); frame->return_offset = 0; if (frame == &entry_frame) { /* Restore previous cframe and exit */ tstate->cframe = cframe.previous; assert(tstate->cframe->current_frame == frame->previous); _Py_LeaveRecursiveCallTstate(tstate); return NULL; } resume_with_error: SET_LOCALS_FROM_FRAME(); goto error; } #if defined(__GNUC__) # pragma GCC diagnostic pop #elif defined(_MSC_VER) /* MS_WINDOWS */ # pragma warning(pop) #endif static void format_missing(PyThreadState *tstate, const char *kind, PyCodeObject *co, PyObject *names, PyObject *qualname) { int err; Py_ssize_t len = PyList_GET_SIZE(names); PyObject *name_str, *comma, *tail, *tmp; assert(PyList_CheckExact(names)); assert(len >= 1); /* Deal with the joys of natural language. */ switch (len) { case 1: name_str = PyList_GET_ITEM(names, 0); Py_INCREF(name_str); break; case 2: name_str = PyUnicode_FromFormat("%U and %U", PyList_GET_ITEM(names, len - 2), PyList_GET_ITEM(names, len - 1)); break; default: tail = PyUnicode_FromFormat(", %U, and %U", PyList_GET_ITEM(names, len - 2), PyList_GET_ITEM(names, len - 1)); if (tail == NULL) return; /* Chop off the last two objects in the list. This shouldn't actually fail, but we can't be too careful. */ err = PyList_SetSlice(names, len - 2, len, NULL); if (err == -1) { Py_DECREF(tail); return; } /* Stitch everything up into a nice comma-separated list. */ comma = PyUnicode_FromString(", "); if (comma == NULL) { Py_DECREF(tail); return; } tmp = PyUnicode_Join(comma, names); Py_DECREF(comma); if (tmp == NULL) { Py_DECREF(tail); return; } name_str = PyUnicode_Concat(tmp, tail); Py_DECREF(tmp); Py_DECREF(tail); break; } if (name_str == NULL) return; _PyErr_Format(tstate, PyExc_TypeError, "%U() missing %i required %s argument%s: %U", qualname, len, kind, len == 1 ? "" : "s", name_str); Py_DECREF(name_str); } static void missing_arguments(PyThreadState *tstate, PyCodeObject *co, Py_ssize_t missing, Py_ssize_t defcount, PyObject **localsplus, PyObject *qualname) { Py_ssize_t i, j = 0; Py_ssize_t start, end; int positional = (defcount != -1); const char *kind = positional ? "positional" : "keyword-only"; PyObject *missing_names; /* Compute the names of the arguments that are missing. */ missing_names = PyList_New(missing); if (missing_names == NULL) return; if (positional) { start = 0; end = co->co_argcount - defcount; } else { start = co->co_argcount; end = start + co->co_kwonlyargcount; } for (i = start; i < end; i++) { if (localsplus[i] == NULL) { PyObject *raw = PyTuple_GET_ITEM(co->co_localsplusnames, i); PyObject *name = PyObject_Repr(raw); if (name == NULL) { Py_DECREF(missing_names); return; } PyList_SET_ITEM(missing_names, j++, name); } } assert(j == missing); format_missing(tstate, kind, co, missing_names, qualname); Py_DECREF(missing_names); } static void too_many_positional(PyThreadState *tstate, PyCodeObject *co, Py_ssize_t given, PyObject *defaults, PyObject **localsplus, PyObject *qualname) { int plural; Py_ssize_t kwonly_given = 0; Py_ssize_t i; PyObject *sig, *kwonly_sig; Py_ssize_t co_argcount = co->co_argcount; assert((co->co_flags & CO_VARARGS) == 0); /* Count missing keyword-only args. */ for (i = co_argcount; i < co_argcount + co->co_kwonlyargcount; i++) { if (localsplus[i] != NULL) { kwonly_given++; } } Py_ssize_t defcount = defaults == NULL ? 0 : PyTuple_GET_SIZE(defaults); if (defcount) { Py_ssize_t atleast = co_argcount - defcount; plural = 1; sig = PyUnicode_FromFormat("from %zd to %zd", atleast, co_argcount); } else { plural = (co_argcount != 1); sig = PyUnicode_FromFormat("%zd", co_argcount); } if (sig == NULL) return; if (kwonly_given) { const char *format = " positional argument%s (and %zd keyword-only argument%s)"; kwonly_sig = PyUnicode_FromFormat(format, given != 1 ? "s" : "", kwonly_given, kwonly_given != 1 ? "s" : ""); if (kwonly_sig == NULL) { Py_DECREF(sig); return; } } else { /* This will not fail. */ kwonly_sig = PyUnicode_FromString(""); assert(kwonly_sig != NULL); } _PyErr_Format(tstate, PyExc_TypeError, "%U() takes %U positional argument%s but %zd%U %s given", qualname, sig, plural ? "s" : "", given, kwonly_sig, given == 1 && !kwonly_given ? "was" : "were"); Py_DECREF(sig); Py_DECREF(kwonly_sig); } static int positional_only_passed_as_keyword(PyThreadState *tstate, PyCodeObject *co, Py_ssize_t kwcount, PyObject* kwnames, PyObject *qualname) { int posonly_conflicts = 0; PyObject* posonly_names = PyList_New(0); if (posonly_names == NULL) { goto fail; } for(int k=0; k < co->co_posonlyargcount; k++){ PyObject* posonly_name = PyTuple_GET_ITEM(co->co_localsplusnames, k); for (int k2=0; k2 0) { if(PyList_Append(posonly_names, kwname) != 0) { goto fail; } posonly_conflicts++; } else if (cmp < 0) { goto fail; } } } if (posonly_conflicts) { PyObject* comma = PyUnicode_FromString(", "); if (comma == NULL) { goto fail; } PyObject* error_names = PyUnicode_Join(comma, posonly_names); Py_DECREF(comma); if (error_names == NULL) { goto fail; } _PyErr_Format(tstate, PyExc_TypeError, "%U() got some positional-only arguments passed" " as keyword arguments: '%U'", qualname, error_names); Py_DECREF(error_names); goto fail; } Py_DECREF(posonly_names); return 0; fail: Py_XDECREF(posonly_names); return 1; } static inline unsigned char * scan_back_to_entry_start(unsigned char *p) { for (; (p[0]&128) == 0; p--); return p; } static inline unsigned char * skip_to_next_entry(unsigned char *p, unsigned char *end) { while (p < end && ((p[0] & 128) == 0)) { p++; } return p; } #define MAX_LINEAR_SEARCH 40 static int get_exception_handler(PyCodeObject *code, int index, int *level, int *handler, int *lasti) { unsigned char *start = (unsigned char *)PyBytes_AS_STRING(code->co_exceptiontable); unsigned char *end = start + PyBytes_GET_SIZE(code->co_exceptiontable); /* Invariants: * start_table == end_table OR * start_table points to a legal entry and end_table points * beyond the table or to a legal entry that is after index. */ if (end - start > MAX_LINEAR_SEARCH) { int offset; parse_varint(start, &offset); if (offset > index) { return 0; } do { unsigned char * mid = start + ((end-start)>>1); mid = scan_back_to_entry_start(mid); parse_varint(mid, &offset); if (offset > index) { end = mid; } else { start = mid; } } while (end - start > MAX_LINEAR_SEARCH); } unsigned char *scan = start; while (scan < end) { int start_offset, size; scan = parse_varint(scan, &start_offset); if (start_offset > index) { break; } scan = parse_varint(scan, &size); if (start_offset + size > index) { scan = parse_varint(scan, handler); int depth_and_lasti; parse_varint(scan, &depth_and_lasti); *level = depth_and_lasti >> 1; *lasti = depth_and_lasti & 1; return 1; } scan = skip_to_next_entry(scan, end); } return 0; } static int initialize_locals(PyThreadState *tstate, PyFunctionObject *func, PyObject **localsplus, PyObject *const *args, Py_ssize_t argcount, PyObject *kwnames) { PyCodeObject *co = (PyCodeObject*)func->func_code; const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount; /* Create a dictionary for keyword parameters (**kwags) */ PyObject *kwdict; Py_ssize_t i; if (co->co_flags & CO_VARKEYWORDS) { kwdict = PyDict_New(); if (kwdict == NULL) { goto fail_pre_positional; } i = total_args; if (co->co_flags & CO_VARARGS) { i++; } assert(localsplus[i] == NULL); localsplus[i] = kwdict; } else { kwdict = NULL; } /* Copy all positional arguments into local variables */ Py_ssize_t j, n; if (argcount > co->co_argcount) { n = co->co_argcount; } else { n = argcount; } for (j = 0; j < n; j++) { PyObject *x = args[j]; assert(localsplus[j] == NULL); localsplus[j] = x; } /* Pack other positional arguments into the *args argument */ if (co->co_flags & CO_VARARGS) { PyObject *u = NULL; if (argcount == n) { u = Py_NewRef(&_Py_SINGLETON(tuple_empty)); } else { assert(args != NULL); u = _PyTuple_FromArraySteal(args + n, argcount - n); } if (u == NULL) { goto fail_post_positional; } assert(localsplus[total_args] == NULL); localsplus[total_args] = u; } else if (argcount > n) { /* Too many postional args. Error is reported later */ for (j = n; j < argcount; j++) { Py_DECREF(args[j]); } } /* Handle keyword arguments */ if (kwnames != NULL) { Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames); for (i = 0; i < kwcount; i++) { PyObject **co_varnames; PyObject *keyword = PyTuple_GET_ITEM(kwnames, i); PyObject *value = args[i+argcount]; Py_ssize_t j; if (keyword == NULL || !PyUnicode_Check(keyword)) { _PyErr_Format(tstate, PyExc_TypeError, "%U() keywords must be strings", func->func_qualname); goto kw_fail; } /* Speed hack: do raw pointer compares. As names are normally interned this should almost always hit. */ co_varnames = ((PyTupleObject *)(co->co_localsplusnames))->ob_item; for (j = co->co_posonlyargcount; j < total_args; j++) { PyObject *varname = co_varnames[j]; if (varname == keyword) { goto kw_found; } } /* Slow fallback, just in case */ for (j = co->co_posonlyargcount; j < total_args; j++) { PyObject *varname = co_varnames[j]; int cmp = PyObject_RichCompareBool( keyword, varname, Py_EQ); if (cmp > 0) { goto kw_found; } else if (cmp < 0) { goto kw_fail; } } assert(j >= total_args); if (kwdict == NULL) { if (co->co_posonlyargcount && positional_only_passed_as_keyword(tstate, co, kwcount, kwnames, func->func_qualname)) { goto kw_fail; } _PyErr_Format(tstate, PyExc_TypeError, "%U() got an unexpected keyword argument '%S'", func->func_qualname, keyword); goto kw_fail; } if (PyDict_SetItem(kwdict, keyword, value) == -1) { goto kw_fail; } Py_DECREF(value); continue; kw_fail: for (;i < kwcount; i++) { PyObject *value = args[i+argcount]; Py_DECREF(value); } goto fail_post_args; kw_found: if (localsplus[j] != NULL) { _PyErr_Format(tstate, PyExc_TypeError, "%U() got multiple values for argument '%S'", func->func_qualname, keyword); goto kw_fail; } localsplus[j] = value; } } /* Check the number of positional arguments */ if ((argcount > co->co_argcount) && !(co->co_flags & CO_VARARGS)) { too_many_positional(tstate, co, argcount, func->func_defaults, localsplus, func->func_qualname); goto fail_post_args; } /* Add missing positional arguments (copy default values from defs) */ if (argcount < co->co_argcount) { Py_ssize_t defcount = func->func_defaults == NULL ? 0 : PyTuple_GET_SIZE(func->func_defaults); Py_ssize_t m = co->co_argcount - defcount; Py_ssize_t missing = 0; for (i = argcount; i < m; i++) { if (localsplus[i] == NULL) { missing++; } } if (missing) { missing_arguments(tstate, co, missing, defcount, localsplus, func->func_qualname); goto fail_post_args; } if (n > m) i = n - m; else i = 0; if (defcount) { PyObject **defs = &PyTuple_GET_ITEM(func->func_defaults, 0); for (; i < defcount; i++) { if (localsplus[m+i] == NULL) { PyObject *def = defs[i]; localsplus[m+i] = Py_NewRef(def); } } } } /* Add missing keyword arguments (copy default values from kwdefs) */ if (co->co_kwonlyargcount > 0) { Py_ssize_t missing = 0; for (i = co->co_argcount; i < total_args; i++) { if (localsplus[i] != NULL) continue; PyObject *varname = PyTuple_GET_ITEM(co->co_localsplusnames, i); if (func->func_kwdefaults != NULL) { PyObject *def = PyDict_GetItemWithError(func->func_kwdefaults, varname); if (def) { localsplus[i] = Py_NewRef(def); continue; } else if (_PyErr_Occurred(tstate)) { goto fail_post_args; } } missing++; } if (missing) { missing_arguments(tstate, co, missing, -1, localsplus, func->func_qualname); goto fail_post_args; } } return 0; fail_pre_positional: for (j = 0; j < argcount; j++) { Py_DECREF(args[j]); } /* fall through */ fail_post_positional: if (kwnames) { Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames); for (j = argcount; j < argcount+kwcount; j++) { Py_DECREF(args[j]); } } /* fall through */ fail_post_args: return -1; } static void clear_thread_frame(PyThreadState *tstate, _PyInterpreterFrame * frame) { assert(frame->owner == FRAME_OWNED_BY_THREAD); // Make sure that this is, indeed, the top frame. We can't check this in // _PyThreadState_PopFrame, since f_code is already cleared at that point: assert((PyObject **)frame + frame->f_code->co_framesize == tstate->datastack_top); tstate->c_recursion_remaining--; assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame); _PyFrame_ClearExceptCode(frame); Py_DECREF(frame->f_code); tstate->c_recursion_remaining++; _PyThreadState_PopFrame(tstate, frame); } static void clear_gen_frame(PyThreadState *tstate, _PyInterpreterFrame * frame) { assert(frame->owner == FRAME_OWNED_BY_GENERATOR); PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_CLEARED; assert(tstate->exc_info == &gen->gi_exc_state); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; tstate->c_recursion_remaining--; assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame); _PyFrame_ClearExceptCode(frame); tstate->c_recursion_remaining++; frame->previous = NULL; } static void _PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame * frame) { if (frame->owner == FRAME_OWNED_BY_THREAD) { clear_thread_frame(tstate, frame); } else { clear_gen_frame(tstate, frame); } } /* Consumes references to func, locals and all the args */ static _PyInterpreterFrame * _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func, PyObject *locals, PyObject* const* args, size_t argcount, PyObject *kwnames) { PyCodeObject * code = (PyCodeObject *)func->func_code; CALL_STAT_INC(frames_pushed); _PyInterpreterFrame *frame = _PyThreadState_PushFrame(tstate, code->co_framesize); if (frame == NULL) { goto fail; } _PyFrame_Initialize(frame, func, locals, code, 0); if (initialize_locals(tstate, func, frame->localsplus, args, argcount, kwnames)) { assert(frame->owner == FRAME_OWNED_BY_THREAD); clear_thread_frame(tstate, frame); return NULL; } return frame; fail: /* Consume the references */ for (size_t i = 0; i < argcount; i++) { Py_DECREF(args[i]); } if (kwnames) { Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames); for (Py_ssize_t i = 0; i < kwcount; i++) { Py_DECREF(args[i+argcount]); } } PyErr_NoMemory(); return NULL; } /* Same as _PyEvalFramePushAndInit but takes an args tuple and kwargs dict. Steals references to func, callargs and kwargs. */ static _PyInterpreterFrame * _PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func, PyObject *locals, Py_ssize_t nargs, PyObject *callargs, PyObject *kwargs) { bool has_dict = (kwargs != NULL && PyDict_GET_SIZE(kwargs) > 0); PyObject *kwnames = NULL; PyObject *const *newargs; if (has_dict) { newargs = _PyStack_UnpackDict(tstate, _PyTuple_ITEMS(callargs), nargs, kwargs, &kwnames); if (newargs == NULL) { Py_DECREF(func); goto error; } } else { newargs = &PyTuple_GET_ITEM(callargs, 0); /* We need to incref all our args since the new frame steals the references. */ for (Py_ssize_t i = 0; i < nargs; ++i) { Py_INCREF(PyTuple_GET_ITEM(callargs, i)); } } _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( tstate, (PyFunctionObject *)func, locals, newargs, nargs, kwnames ); if (has_dict) { _PyStack_UnpackDict_FreeNoDecRef(newargs, kwnames); } /* No need to decref func here because the reference has been stolen by _PyEvalFramePushAndInit. */ Py_DECREF(callargs); Py_XDECREF(kwargs); return new_frame; error: Py_DECREF(callargs); Py_XDECREF(kwargs); return NULL; } PyObject * _PyEval_Vector(PyThreadState *tstate, PyFunctionObject *func, PyObject *locals, PyObject* const* args, size_t argcount, PyObject *kwnames) { /* _PyEvalFramePushAndInit consumes the references * to func, locals and all its arguments */ Py_INCREF(func); Py_XINCREF(locals); for (size_t i = 0; i < argcount; i++) { Py_INCREF(args[i]); } if (kwnames) { Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames); for (Py_ssize_t i = 0; i < kwcount; i++) { Py_INCREF(args[i+argcount]); } } _PyInterpreterFrame *frame = _PyEvalFramePushAndInit( tstate, func, locals, args, argcount, kwnames); if (frame == NULL) { return NULL; } EVAL_CALL_STAT_INC(EVAL_CALL_VECTOR); return _PyEval_EvalFrame(tstate, frame, 0); } /* Legacy API */ PyObject * PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals, PyObject *const *args, int argcount, PyObject *const *kws, int kwcount, PyObject *const *defs, int defcount, PyObject *kwdefs, PyObject *closure) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *res = NULL; PyObject *defaults = _PyTuple_FromArray(defs, defcount); if (defaults == NULL) { return NULL; } PyObject *builtins = _PyEval_BuiltinsFromGlobals(tstate, globals); // borrowed ref if (builtins == NULL) { Py_DECREF(defaults); return NULL; } if (locals == NULL) { locals = globals; } PyObject *kwnames = NULL; PyObject *const *allargs; PyObject **newargs = NULL; PyFunctionObject *func = NULL; if (kwcount == 0) { allargs = args; } else { kwnames = PyTuple_New(kwcount); if (kwnames == NULL) { goto fail; } newargs = PyMem_Malloc(sizeof(PyObject *)*(kwcount+argcount)); if (newargs == NULL) { goto fail; } for (int i = 0; i < argcount; i++) { newargs[i] = args[i]; } for (int i = 0; i < kwcount; i++) { PyTuple_SET_ITEM(kwnames, i, Py_NewRef(kws[2*i])); newargs[argcount+i] = kws[2*i+1]; } allargs = newargs; } PyFrameConstructor constr = { .fc_globals = globals, .fc_builtins = builtins, .fc_name = ((PyCodeObject *)_co)->co_name, .fc_qualname = ((PyCodeObject *)_co)->co_name, .fc_code = _co, .fc_defaults = defaults, .fc_kwdefaults = kwdefs, .fc_closure = closure }; func = _PyFunction_FromConstructor(&constr); if (func == NULL) { goto fail; } EVAL_CALL_STAT_INC(EVAL_CALL_LEGACY); res = _PyEval_Vector(tstate, func, locals, allargs, argcount, kwnames); fail: Py_XDECREF(func); Py_XDECREF(kwnames); PyMem_Free(newargs); Py_DECREF(defaults); return res; } /* Logic for the raise statement (too complicated for inlining). This *consumes* a reference count to each of its arguments. */ static int do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause) { PyObject *type = NULL, *value = NULL; if (exc == NULL) { /* Reraise */ _PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate); exc = exc_info->exc_value; if (Py_IsNone(exc) || exc == NULL) { _PyErr_SetString(tstate, PyExc_RuntimeError, "No active exception to reraise"); return 0; } Py_INCREF(exc); assert(PyExceptionInstance_Check(exc)); _PyErr_SetRaisedException(tstate, exc); return 1; } /* We support the following forms of raise: raise raise raise */ if (PyExceptionClass_Check(exc)) { type = exc; value = _PyObject_CallNoArgs(exc); if (value == NULL) goto raise_error; if (!PyExceptionInstance_Check(value)) { _PyErr_Format(tstate, PyExc_TypeError, "calling %R should have returned an instance of " "BaseException, not %R", type, Py_TYPE(value)); goto raise_error; } } else if (PyExceptionInstance_Check(exc)) { value = exc; type = PyExceptionInstance_Class(exc); Py_INCREF(type); } else { /* Not something you can raise. You get an exception anyway, just not what you specified :-) */ Py_DECREF(exc); _PyErr_SetString(tstate, PyExc_TypeError, "exceptions must derive from BaseException"); goto raise_error; } assert(type != NULL); assert(value != NULL); if (cause) { PyObject *fixed_cause; if (PyExceptionClass_Check(cause)) { fixed_cause = _PyObject_CallNoArgs(cause); if (fixed_cause == NULL) goto raise_error; Py_DECREF(cause); } else if (PyExceptionInstance_Check(cause)) { fixed_cause = cause; } else if (Py_IsNone(cause)) { Py_DECREF(cause); fixed_cause = NULL; } else { _PyErr_SetString(tstate, PyExc_TypeError, "exception causes must derive from " "BaseException"); goto raise_error; } PyException_SetCause(value, fixed_cause); } _PyErr_SetObject(tstate, type, value); /* _PyErr_SetObject incref's its arguments */ Py_DECREF(value); Py_DECREF(type); return 0; raise_error: Py_XDECREF(value); Py_XDECREF(type); Py_XDECREF(cause); return 0; } /* Logic for matching an exception in an except* clause (too complicated for inlining). */ static int exception_group_match(PyObject* exc_value, PyObject *match_type, PyObject **match, PyObject **rest) { if (Py_IsNone(exc_value)) { *match = Py_NewRef(Py_None); *rest = Py_NewRef(Py_None); return 0; } assert(PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, match_type)) { /* Full match of exc itself */ bool is_eg = _PyBaseExceptionGroup_Check(exc_value); if (is_eg) { *match = Py_NewRef(exc_value); } else { /* naked exception - wrap it */ PyObject *excs = PyTuple_Pack(1, exc_value); if (excs == NULL) { return -1; } PyObject *wrapped = _PyExc_CreateExceptionGroup("", excs); Py_DECREF(excs); if (wrapped == NULL) { return -1; } *match = wrapped; } *rest = Py_NewRef(Py_None); return 0; } /* exc_value does not match match_type. * Check for partial match if it's an exception group. */ if (_PyBaseExceptionGroup_Check(exc_value)) { PyObject *pair = PyObject_CallMethod(exc_value, "split", "(O)", match_type); if (pair == NULL) { return -1; } assert(PyTuple_CheckExact(pair)); assert(PyTuple_GET_SIZE(pair) == 2); *match = Py_NewRef(PyTuple_GET_ITEM(pair, 0)); *rest = Py_NewRef(PyTuple_GET_ITEM(pair, 1)); Py_DECREF(pair); return 0; } /* no match */ *match = Py_NewRef(Py_None); *rest = Py_NewRef(exc_value); return 0; } /* Iterate v argcnt times and store the results on the stack (via decreasing sp). Return 1 for success, 0 if error. If argcntafter == -1, do a simple unpack. If it is >= 0, do an unpack with a variable target. */ static int unpack_iterable(PyThreadState *tstate, PyObject *v, int argcnt, int argcntafter, PyObject **sp) { int i = 0, j = 0; Py_ssize_t ll = 0; PyObject *it; /* iter(v) */ PyObject *w; PyObject *l = NULL; /* variable list */ assert(v != NULL); it = PyObject_GetIter(v); if (it == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && Py_TYPE(v)->tp_iter == NULL && !PySequence_Check(v)) { _PyErr_Format(tstate, PyExc_TypeError, "cannot unpack non-iterable %.200s object", Py_TYPE(v)->tp_name); } return 0; } for (; i < argcnt; i++) { w = PyIter_Next(it); if (w == NULL) { /* Iterator done, via error or exhaustion. */ if (!_PyErr_Occurred(tstate)) { if (argcntafter == -1) { _PyErr_Format(tstate, PyExc_ValueError, "not enough values to unpack " "(expected %d, got %d)", argcnt, i); } else { _PyErr_Format(tstate, PyExc_ValueError, "not enough values to unpack " "(expected at least %d, got %d)", argcnt + argcntafter, i); } } goto Error; } *--sp = w; } if (argcntafter == -1) { /* We better have exhausted the iterator now. */ w = PyIter_Next(it); if (w == NULL) { if (_PyErr_Occurred(tstate)) goto Error; Py_DECREF(it); return 1; } Py_DECREF(w); _PyErr_Format(tstate, PyExc_ValueError, "too many values to unpack (expected %d)", argcnt); goto Error; } l = PySequence_List(it); if (l == NULL) goto Error; *--sp = l; i++; ll = PyList_GET_SIZE(l); if (ll < argcntafter) { _PyErr_Format(tstate, PyExc_ValueError, "not enough values to unpack (expected at least %d, got %zd)", argcnt + argcntafter, argcnt + ll); goto Error; } /* Pop the "after-variable" args off the list. */ for (j = argcntafter; j > 0; j--, i++) { *--sp = PyList_GET_ITEM(l, ll - j); } /* Resize the list. */ Py_SET_SIZE(l, ll - argcntafter); Py_DECREF(it); return 1; Error: for (; i > 0; i--, sp++) Py_DECREF(*sp); Py_XDECREF(it); return 0; } static int do_monitor_exc(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, int event) { assert(event < PY_MONITORING_UNGROUPED_EVENTS); PyObject *exc = PyErr_GetRaisedException(); assert(exc != NULL); int err = _Py_call_instrumentation_arg(tstate, event, frame, instr, exc); if (err == 0) { PyErr_SetRaisedException(exc); } else { Py_DECREF(exc); } return err; } static inline int no_tools_for_event(PyThreadState *tstate, _PyInterpreterFrame *frame, int event) { _PyCoMonitoringData *data = frame->f_code->_co_monitoring; if (data) { if (data->active_monitors.tools[event] == 0) { return 1; } } else { if (tstate->interp->monitors.tools[event] == 0) { return 1; } } return 0; } static void monitor_raise(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) { if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_RAISE)) { return; } do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_RAISE); } static int monitor_stop_iteration(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) { if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_STOP_ITERATION)) { return 0; } return do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_STOP_ITERATION); } static void monitor_unwind(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) { if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_PY_UNWIND)) { return; } _Py_call_instrumentation_exc0(tstate, PY_MONITORING_EVENT_PY_UNWIND, frame, instr); } static void monitor_handled(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *exc) { if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_EXCEPTION_HANDLED)) { return; } _Py_call_instrumentation_arg(tstate, PY_MONITORING_EVENT_EXCEPTION_HANDLED, frame, instr, exc); } static void monitor_throw(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) { if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_PY_THROW)) { return; } _Py_call_instrumentation_exc0(tstate, PY_MONITORING_EVENT_PY_THROW, frame, instr); } void PyThreadState_EnterTracing(PyThreadState *tstate) { assert(tstate->tracing >= 0); tstate->tracing++; } void PyThreadState_LeaveTracing(PyThreadState *tstate) { assert(tstate->tracing > 0); tstate->tracing--; } PyObject* _PyEval_CallTracing(PyObject *func, PyObject *args) { // Save and disable tracing PyThreadState *tstate = _PyThreadState_GET(); int save_tracing = tstate->tracing; tstate->tracing = 0; // Call the tracing function PyObject *result = PyObject_Call(func, args, NULL); // Restore tracing tstate->tracing = save_tracing; return result; } void PyEval_SetProfile(Py_tracefunc func, PyObject *arg) { PyThreadState *tstate = _PyThreadState_GET(); if (_PyEval_SetProfile(tstate, func, arg) < 0) { /* Log _PySys_Audit() error */ _PyErr_WriteUnraisableMsg("in PyEval_SetProfile", NULL); } } void PyEval_SetProfileAllThreads(Py_tracefunc func, PyObject *arg) { PyThreadState *this_tstate = _PyThreadState_GET(); PyInterpreterState* interp = this_tstate->interp; _PyRuntimeState *runtime = &_PyRuntime; HEAD_LOCK(runtime); PyThreadState* ts = PyInterpreterState_ThreadHead(interp); HEAD_UNLOCK(runtime); while (ts) { if (_PyEval_SetProfile(ts, func, arg) < 0) { _PyErr_WriteUnraisableMsg("in PyEval_SetProfileAllThreads", NULL); } HEAD_LOCK(runtime); ts = PyThreadState_Next(ts); HEAD_UNLOCK(runtime); } } void PyEval_SetTrace(Py_tracefunc func, PyObject *arg) { PyThreadState *tstate = _PyThreadState_GET(); if (_PyEval_SetTrace(tstate, func, arg) < 0) { /* Log _PySys_Audit() error */ _PyErr_WriteUnraisableMsg("in PyEval_SetTrace", NULL); } } void PyEval_SetTraceAllThreads(Py_tracefunc func, PyObject *arg) { PyThreadState *this_tstate = _PyThreadState_GET(); PyInterpreterState* interp = this_tstate->interp; _PyRuntimeState *runtime = &_PyRuntime; HEAD_LOCK(runtime); PyThreadState* ts = PyInterpreterState_ThreadHead(interp); HEAD_UNLOCK(runtime); while (ts) { if (_PyEval_SetTrace(ts, func, arg) < 0) { _PyErr_WriteUnraisableMsg("in PyEval_SetTraceAllThreads", NULL); } HEAD_LOCK(runtime); ts = PyThreadState_Next(ts); HEAD_UNLOCK(runtime); } } int _PyEval_SetCoroutineOriginTrackingDepth(int depth) { PyThreadState *tstate = _PyThreadState_GET(); if (depth < 0) { _PyErr_SetString(tstate, PyExc_ValueError, "depth must be >= 0"); return -1; } tstate->coroutine_origin_tracking_depth = depth; return 0; } int _PyEval_GetCoroutineOriginTrackingDepth(void) { PyThreadState *tstate = _PyThreadState_GET(); return tstate->coroutine_origin_tracking_depth; } int _PyEval_SetAsyncGenFirstiter(PyObject *firstiter) { PyThreadState *tstate = _PyThreadState_GET(); if (_PySys_Audit(tstate, "sys.set_asyncgen_hook_firstiter", NULL) < 0) { return -1; } Py_XSETREF(tstate->async_gen_firstiter, Py_XNewRef(firstiter)); return 0; } PyObject * _PyEval_GetAsyncGenFirstiter(void) { PyThreadState *tstate = _PyThreadState_GET(); return tstate->async_gen_firstiter; } int _PyEval_SetAsyncGenFinalizer(PyObject *finalizer) { PyThreadState *tstate = _PyThreadState_GET(); if (_PySys_Audit(tstate, "sys.set_asyncgen_hook_finalizer", NULL) < 0) { return -1; } Py_XSETREF(tstate->async_gen_finalizer, Py_XNewRef(finalizer)); return 0; } PyObject * _PyEval_GetAsyncGenFinalizer(void) { PyThreadState *tstate = _PyThreadState_GET(); return tstate->async_gen_finalizer; } _PyInterpreterFrame * _PyEval_GetFrame(void) { PyThreadState *tstate = _PyThreadState_GET(); return _PyThreadState_GetFrame(tstate); } PyFrameObject * PyEval_GetFrame(void) { _PyInterpreterFrame *frame = _PyEval_GetFrame(); if (frame == NULL) { return NULL; } PyFrameObject *f = _PyFrame_GetFrameObject(frame); if (f == NULL) { PyErr_Clear(); } return f; } PyObject * _PyEval_GetBuiltins(PyThreadState *tstate) { _PyInterpreterFrame *frame = _PyThreadState_GetFrame(tstate); if (frame != NULL) { return frame->f_builtins; } return tstate->interp->builtins; } PyObject * PyEval_GetBuiltins(void) { PyThreadState *tstate = _PyThreadState_GET(); return _PyEval_GetBuiltins(tstate); } /* Convenience function to get a builtin from its name */ PyObject * _PyEval_GetBuiltin(PyObject *name) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *attr = PyDict_GetItemWithError(PyEval_GetBuiltins(), name); if (attr) { Py_INCREF(attr); } else if (!_PyErr_Occurred(tstate)) { _PyErr_SetObject(tstate, PyExc_AttributeError, name); } return attr; } PyObject * _PyEval_GetBuiltinId(_Py_Identifier *name) { return _PyEval_GetBuiltin(_PyUnicode_FromId(name)); } PyObject * PyEval_GetLocals(void) { PyThreadState *tstate = _PyThreadState_GET(); _PyInterpreterFrame *current_frame = _PyThreadState_GetFrame(tstate); if (current_frame == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, "frame does not exist"); return NULL; } if (_PyFrame_FastToLocalsWithError(current_frame) < 0) { return NULL; } PyObject *locals = current_frame->f_locals; assert(locals != NULL); return locals; } PyObject * PyEval_GetGlobals(void) { PyThreadState *tstate = _PyThreadState_GET(); _PyInterpreterFrame *current_frame = _PyThreadState_GetFrame(tstate); if (current_frame == NULL) { return NULL; } return current_frame->f_globals; } int PyEval_MergeCompilerFlags(PyCompilerFlags *cf) { PyThreadState *tstate = _PyThreadState_GET(); _PyInterpreterFrame *current_frame = tstate->cframe->current_frame; int result = cf->cf_flags != 0; if (current_frame != NULL) { const int codeflags = current_frame->f_code->co_flags; const int compilerflags = codeflags & PyCF_MASK; if (compilerflags) { result = 1; cf->cf_flags |= compilerflags; } } return result; } const char * PyEval_GetFuncName(PyObject *func) { if (PyMethod_Check(func)) return PyEval_GetFuncName(PyMethod_GET_FUNCTION(func)); else if (PyFunction_Check(func)) return PyUnicode_AsUTF8(((PyFunctionObject*)func)->func_name); else if (PyCFunction_Check(func)) return ((PyCFunctionObject*)func)->m_ml->ml_name; else return Py_TYPE(func)->tp_name; } const char * PyEval_GetFuncDesc(PyObject *func) { if (PyMethod_Check(func)) return "()"; else if (PyFunction_Check(func)) return "()"; else if (PyCFunction_Check(func)) return "()"; else return " object"; } /* Extract a slice index from a PyLong or an object with the nb_index slot defined, and store in *pi. Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX, and silently boost values less than PY_SSIZE_T_MIN to PY_SSIZE_T_MIN. Return 0 on error, 1 on success. */ int _PyEval_SliceIndex(PyObject *v, Py_ssize_t *pi) { PyThreadState *tstate = _PyThreadState_GET(); if (!Py_IsNone(v)) { Py_ssize_t x; if (_PyIndex_Check(v)) { x = PyNumber_AsSsize_t(v, NULL); if (x == -1 && _PyErr_Occurred(tstate)) return 0; } else { _PyErr_SetString(tstate, PyExc_TypeError, "slice indices must be integers or " "None or have an __index__ method"); return 0; } *pi = x; } return 1; } int _PyEval_SliceIndexNotNone(PyObject *v, Py_ssize_t *pi) { PyThreadState *tstate = _PyThreadState_GET(); Py_ssize_t x; if (_PyIndex_Check(v)) { x = PyNumber_AsSsize_t(v, NULL); if (x == -1 && _PyErr_Occurred(tstate)) return 0; } else { _PyErr_SetString(tstate, PyExc_TypeError, "slice indices must be integers or " "have an __index__ method"); return 0; } *pi = x; return 1; } static PyObject * import_name(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *name, PyObject *fromlist, PyObject *level) { PyObject *import_func, *res; PyObject* stack[5]; import_func = _PyDict_GetItemWithError(frame->f_builtins, &_Py_ID(__import__)); if (import_func == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_SetString(tstate, PyExc_ImportError, "__import__ not found"); } return NULL; } PyObject *locals = frame->f_locals; /* Fast path for not overloaded __import__. */ if (_PyImport_IsDefaultImportFunc(tstate->interp, import_func)) { int ilevel = _PyLong_AsInt(level); if (ilevel == -1 && _PyErr_Occurred(tstate)) { return NULL; } res = PyImport_ImportModuleLevelObject( name, frame->f_globals, locals == NULL ? Py_None :locals, fromlist, ilevel); return res; } Py_INCREF(import_func); stack[0] = name; stack[1] = frame->f_globals; stack[2] = locals == NULL ? Py_None : locals; stack[3] = fromlist; stack[4] = level; res = _PyObject_FastCall(import_func, stack, 5); Py_DECREF(import_func); return res; } static PyObject * import_from(PyThreadState *tstate, PyObject *v, PyObject *name) { PyObject *x; PyObject *fullmodname, *pkgname, *pkgpath, *pkgname_or_unknown, *errmsg; if (_PyObject_LookupAttr(v, name, &x) != 0) { return x; } /* Issue #17636: in case this failed because of a circular relative import, try to fallback on reading the module directly from sys.modules. */ pkgname = PyObject_GetAttr(v, &_Py_ID(__name__)); if (pkgname == NULL) { goto error; } if (!PyUnicode_Check(pkgname)) { Py_CLEAR(pkgname); goto error; } fullmodname = PyUnicode_FromFormat("%U.%U", pkgname, name); if (fullmodname == NULL) { Py_DECREF(pkgname); return NULL; } x = PyImport_GetModule(fullmodname); Py_DECREF(fullmodname); if (x == NULL && !_PyErr_Occurred(tstate)) { goto error; } Py_DECREF(pkgname); return x; error: pkgpath = PyModule_GetFilenameObject(v); if (pkgname == NULL) { pkgname_or_unknown = PyUnicode_FromString(""); if (pkgname_or_unknown == NULL) { Py_XDECREF(pkgpath); return NULL; } } else { pkgname_or_unknown = pkgname; } if (pkgpath == NULL || !PyUnicode_Check(pkgpath)) { _PyErr_Clear(tstate); errmsg = PyUnicode_FromFormat( "cannot import name %R from %R (unknown location)", name, pkgname_or_unknown ); /* NULL checks for errmsg and pkgname done by PyErr_SetImportError. */ _PyErr_SetImportErrorWithNameFrom(errmsg, pkgname, NULL, name); } else { PyObject *spec = PyObject_GetAttr(v, &_Py_ID(__spec__)); const char *fmt = _PyModuleSpec_IsInitializing(spec) ? "cannot import name %R from partially initialized module %R " "(most likely due to a circular import) (%S)" : "cannot import name %R from %R (%S)"; Py_XDECREF(spec); errmsg = PyUnicode_FromFormat(fmt, name, pkgname_or_unknown, pkgpath); /* NULL checks for errmsg and pkgname done by PyErr_SetImportError. */ _PyErr_SetImportErrorWithNameFrom(errmsg, pkgname, pkgpath, name); } Py_XDECREF(errmsg); Py_XDECREF(pkgname_or_unknown); Py_XDECREF(pkgpath); return NULL; } #define CANNOT_CATCH_MSG "catching classes that do not inherit from "\ "BaseException is not allowed" #define CANNOT_EXCEPT_STAR_EG "catching ExceptionGroup with except* "\ "is not allowed. Use except instead." static int check_except_type_valid(PyThreadState *tstate, PyObject* right) { if (PyTuple_Check(right)) { Py_ssize_t i, length; length = PyTuple_GET_SIZE(right); for (i = 0; i < length; i++) { PyObject *exc = PyTuple_GET_ITEM(right, i); if (!PyExceptionClass_Check(exc)) { _PyErr_SetString(tstate, PyExc_TypeError, CANNOT_CATCH_MSG); return -1; } } } else { if (!PyExceptionClass_Check(right)) { _PyErr_SetString(tstate, PyExc_TypeError, CANNOT_CATCH_MSG); return -1; } } return 0; } static int check_except_star_type_valid(PyThreadState *tstate, PyObject* right) { if (check_except_type_valid(tstate, right) < 0) { return -1; } /* reject except *ExceptionGroup */ int is_subclass = 0; if (PyTuple_Check(right)) { Py_ssize_t length = PyTuple_GET_SIZE(right); for (Py_ssize_t i = 0; i < length; i++) { PyObject *exc = PyTuple_GET_ITEM(right, i); is_subclass = PyObject_IsSubclass(exc, PyExc_BaseExceptionGroup); if (is_subclass < 0) { return -1; } if (is_subclass) { break; } } } else { is_subclass = PyObject_IsSubclass(right, PyExc_BaseExceptionGroup); if (is_subclass < 0) { return -1; } } if (is_subclass) { _PyErr_SetString(tstate, PyExc_TypeError, CANNOT_EXCEPT_STAR_EG); return -1; } return 0; } static int check_args_iterable(PyThreadState *tstate, PyObject *func, PyObject *args) { if (Py_TYPE(args)->tp_iter == NULL && !PySequence_Check(args)) { /* check_args_iterable() may be called with a live exception: * clear it to prevent calling _PyObject_FunctionStr() with an * exception set. */ _PyErr_Clear(tstate); PyObject *funcstr = _PyObject_FunctionStr(func); if (funcstr != NULL) { _PyErr_Format(tstate, PyExc_TypeError, "%U argument after * must be an iterable, not %.200s", funcstr, Py_TYPE(args)->tp_name); Py_DECREF(funcstr); } return -1; } return 0; } static void format_kwargs_error(PyThreadState *tstate, PyObject *func, PyObject *kwargs) { /* _PyDict_MergeEx raises attribute * error (percolated from an attempt * to get 'keys' attribute) instead of * a type error if its second argument * is not a mapping. */ if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { _PyErr_Clear(tstate); PyObject *funcstr = _PyObject_FunctionStr(func); if (funcstr != NULL) { _PyErr_Format( tstate, PyExc_TypeError, "%U argument after ** must be a mapping, not %.200s", funcstr, Py_TYPE(kwargs)->tp_name); Py_DECREF(funcstr); } } else if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { PyObject *exc = _PyErr_GetRaisedException(tstate); PyObject *args = ((PyBaseExceptionObject *)exc)->args; if (exc && PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1) { _PyErr_Clear(tstate); PyObject *funcstr = _PyObject_FunctionStr(func); if (funcstr != NULL) { PyObject *key = PyTuple_GET_ITEM(args, 0); _PyErr_Format( tstate, PyExc_TypeError, "%U got multiple values for keyword argument '%S'", funcstr, key); Py_DECREF(funcstr); } Py_XDECREF(exc); } else { _PyErr_SetRaisedException(tstate, exc); } } } static void format_exc_check_arg(PyThreadState *tstate, PyObject *exc, const char *format_str, PyObject *obj) { const char *obj_str; if (!obj) return; obj_str = PyUnicode_AsUTF8(obj); if (!obj_str) return; _PyErr_Format(tstate, exc, format_str, obj_str); if (exc == PyExc_NameError) { // Include the name in the NameError exceptions to offer suggestions later. PyObject *exc = PyErr_GetRaisedException(); if (PyErr_GivenExceptionMatches(exc, PyExc_NameError)) { if (((PyNameErrorObject*)exc)->name == NULL) { // We do not care if this fails because we are going to restore the // NameError anyway. (void)PyObject_SetAttr(exc, &_Py_ID(name), obj); } } PyErr_SetRaisedException(exc); } } static void format_exc_unbound(PyThreadState *tstate, PyCodeObject *co, int oparg) { PyObject *name; /* Don't stomp existing exception */ if (_PyErr_Occurred(tstate)) return; name = PyTuple_GET_ITEM(co->co_localsplusnames, oparg); if (oparg < PyCode_GetFirstFree(co)) { format_exc_check_arg(tstate, PyExc_UnboundLocalError, UNBOUNDLOCAL_ERROR_MSG, name); } else { format_exc_check_arg(tstate, PyExc_NameError, UNBOUNDFREE_ERROR_MSG, name); } } static void format_awaitable_error(PyThreadState *tstate, PyTypeObject *type, int oparg) { if (type->tp_as_async == NULL || type->tp_as_async->am_await == NULL) { if (oparg == 1) { _PyErr_Format(tstate, PyExc_TypeError, "'async with' received an object from __aenter__ " "that does not implement __await__: %.100s", type->tp_name); } else if (oparg == 2) { _PyErr_Format(tstate, PyExc_TypeError, "'async with' received an object from __aexit__ " "that does not implement __await__: %.100s", type->tp_name); } } } Py_ssize_t PyUnstable_Eval_RequestCodeExtraIndex(freefunc free) { PyInterpreterState *interp = _PyInterpreterState_GET(); Py_ssize_t new_index; if (interp->co_extra_user_count == MAX_CO_EXTRA_USERS - 1) { return -1; } new_index = interp->co_extra_user_count++; interp->co_extra_freefuncs[new_index] = free; return new_index; } /* Implement Py_EnterRecursiveCall() and Py_LeaveRecursiveCall() as functions for the limited API. */ int Py_EnterRecursiveCall(const char *where) { return _Py_EnterRecursiveCall(where); } void Py_LeaveRecursiveCall(void) { _Py_LeaveRecursiveCall(); } ================================================ FILE: Ceval_Gil.c ================================================ #include "Python.h" #include "pycore_atomic.h" // _Py_atomic_int #include "pycore_ceval.h" // _PyEval_SignalReceived() #include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pylifecycle.h" // _PyErr_Print() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_interp.h" // _Py_RunGC() #include "pycore_pymem.h" // _PyMem_IsPtrFreed() /* Notes about the implementation: - The GIL is just a boolean variable (locked) whose access is protected by a mutex (gil_mutex), and whose changes are signalled by a condition variable (gil_cond). gil_mutex is taken for short periods of time, and therefore mostly uncontended. - In the GIL-holding thread, the main loop (PyEval_EvalFrameEx) must be able to release the GIL on demand by another thread. A volatile boolean variable (gil_drop_request) is used for that purpose, which is checked at every turn of the eval loop. That variable is set after a wait of `interval` microseconds on `gil_cond` has timed out. [Actually, another volatile boolean variable (eval_breaker) is used which ORs several conditions into one. Volatile booleans are sufficient as inter-thread signalling means since Python is run on cache-coherent architectures only.] - A thread wanting to take the GIL will first let pass a given amount of time (`interval` microseconds) before setting gil_drop_request. This encourages a defined switching period, but doesn't enforce it since opcodes can take an arbitrary time to execute. The `interval` value is available for the user to read and modify using the Python API `sys.{get,set}switchinterval()`. - When a thread releases the GIL and gil_drop_request is set, that thread ensures that another GIL-awaiting thread gets scheduled. It does so by waiting on a condition variable (switch_cond) until the value of last_holder is changed to something else than its own thread state pointer, indicating that another thread was able to take the GIL. This is meant to prohibit the latency-adverse behaviour on multi-core machines where one thread would speculatively release the GIL, but still run and end up being the first to re-acquire it, making the "timeslices" much longer than expected. (Note: this mechanism is enabled with FORCE_SWITCHING above) */ // GH-89279: Force inlining by using a macro. #if defined(_MSC_VER) && SIZEOF_INT == 4 #define _Py_atomic_load_relaxed_int32(ATOMIC_VAL) (assert(sizeof((ATOMIC_VAL)->_value) == 4), *((volatile int*)&((ATOMIC_VAL)->_value))) #else #define _Py_atomic_load_relaxed_int32(ATOMIC_VAL) _Py_atomic_load_relaxed(ATOMIC_VAL) #endif /* This can set eval_breaker to 0 even though gil_drop_request became 1. We believe this is all right because the eval loop will release the GIL eventually anyway. */ static inline void COMPUTE_EVAL_BREAKER(PyInterpreterState *interp, struct _ceval_runtime_state *ceval, struct _ceval_state *ceval2) { _Py_atomic_store_relaxed(&ceval2->eval_breaker, _Py_atomic_load_relaxed_int32(&ceval2->gil_drop_request) | (_Py_atomic_load_relaxed_int32(&ceval->signals_pending) && _Py_ThreadCanHandleSignals(interp)) | (_Py_atomic_load_relaxed_int32(&ceval2->pending.calls_to_do) && _Py_ThreadCanHandlePendingCalls()) | ceval2->pending.async_exc | _Py_atomic_load_relaxed_int32(&ceval2->gc_scheduled)); } static inline void SET_GIL_DROP_REQUEST(PyInterpreterState *interp) { struct _ceval_state *ceval2 = &interp->ceval; _Py_atomic_store_relaxed(&ceval2->gil_drop_request, 1); _Py_atomic_store_relaxed(&ceval2->eval_breaker, 1); } static inline void RESET_GIL_DROP_REQUEST(PyInterpreterState *interp) { struct _ceval_runtime_state *ceval = &interp->runtime->ceval; struct _ceval_state *ceval2 = &interp->ceval; _Py_atomic_store_relaxed(&ceval2->gil_drop_request, 0); COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); } static inline void SIGNAL_PENDING_CALLS(PyInterpreterState *interp) { struct _ceval_runtime_state *ceval = &interp->runtime->ceval; struct _ceval_state *ceval2 = &interp->ceval; _Py_atomic_store_relaxed(&ceval2->pending.calls_to_do, 1); COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); } static inline void UNSIGNAL_PENDING_CALLS(PyInterpreterState *interp) { struct _ceval_runtime_state *ceval = &interp->runtime->ceval; struct _ceval_state *ceval2 = &interp->ceval; _Py_atomic_store_relaxed(&ceval2->pending.calls_to_do, 0); COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); } static inline void SIGNAL_PENDING_SIGNALS(PyInterpreterState *interp, int force) { struct _ceval_runtime_state *ceval = &interp->runtime->ceval; struct _ceval_state *ceval2 = &interp->ceval; _Py_atomic_store_relaxed(&ceval->signals_pending, 1); if (force) { _Py_atomic_store_relaxed(&ceval2->eval_breaker, 1); } else { /* eval_breaker is not set to 1 if thread_can_handle_signals() is false */ COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); } } static inline void UNSIGNAL_PENDING_SIGNALS(PyInterpreterState *interp) { struct _ceval_runtime_state *ceval = &interp->runtime->ceval; struct _ceval_state *ceval2 = &interp->ceval; _Py_atomic_store_relaxed(&ceval->signals_pending, 0); COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); } static inline void SIGNAL_ASYNC_EXC(PyInterpreterState *interp) { struct _ceval_state *ceval2 = &interp->ceval; ceval2->pending.async_exc = 1; _Py_atomic_store_relaxed(&ceval2->eval_breaker, 1); } static inline void UNSIGNAL_ASYNC_EXC(PyInterpreterState *interp) { struct _ceval_runtime_state *ceval = &interp->runtime->ceval; struct _ceval_state *ceval2 = &interp->ceval; ceval2->pending.async_exc = 0; COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); } #ifndef NDEBUG /* Ensure that tstate is valid */ static int is_tstate_valid(PyThreadState *tstate) { assert(!_PyMem_IsPtrFreed(tstate)); assert(!_PyMem_IsPtrFreed(tstate->interp)); return 1; } #endif /* * Implementation of the Global Interpreter Lock (GIL). */ #include #include #include "pycore_atomic.h" #include "condvar.h" #define MUTEX_INIT(mut) \ if (PyMUTEX_INIT(&(mut))) { \ Py_FatalError("PyMUTEX_INIT(" #mut ") failed"); }; #define MUTEX_FINI(mut) \ if (PyMUTEX_FINI(&(mut))) { \ Py_FatalError("PyMUTEX_FINI(" #mut ") failed"); }; #define MUTEX_LOCK(mut) \ if (PyMUTEX_LOCK(&(mut))) { \ Py_FatalError("PyMUTEX_LOCK(" #mut ") failed"); }; #define MUTEX_UNLOCK(mut) \ if (PyMUTEX_UNLOCK(&(mut))) { \ Py_FatalError("PyMUTEX_UNLOCK(" #mut ") failed"); }; #define COND_INIT(cond) \ if (PyCOND_INIT(&(cond))) { \ Py_FatalError("PyCOND_INIT(" #cond ") failed"); }; #define COND_FINI(cond) \ if (PyCOND_FINI(&(cond))) { \ Py_FatalError("PyCOND_FINI(" #cond ") failed"); }; #define COND_SIGNAL(cond) \ if (PyCOND_SIGNAL(&(cond))) { \ Py_FatalError("PyCOND_SIGNAL(" #cond ") failed"); }; #define COND_WAIT(cond, mut) \ if (PyCOND_WAIT(&(cond), &(mut))) { \ Py_FatalError("PyCOND_WAIT(" #cond ") failed"); }; #define COND_TIMED_WAIT(cond, mut, microseconds, timeout_result) \ { \ int r = PyCOND_TIMEDWAIT(&(cond), &(mut), (microseconds)); \ if (r < 0) \ Py_FatalError("PyCOND_WAIT(" #cond ") failed"); \ if (r) /* 1 == timeout, 2 == impl. can't say, so assume timeout */ \ timeout_result = 1; \ else \ timeout_result = 0; \ } \ #define DEFAULT_INTERVAL 5000 static void _gil_initialize(struct _gil_runtime_state *gil) { _Py_atomic_int uninitialized = {-1}; gil->locked = uninitialized; gil->interval = DEFAULT_INTERVAL; } static int gil_created(struct _gil_runtime_state *gil) { if (gil == NULL) { return 0; } return (_Py_atomic_load_explicit(&gil->locked, _Py_memory_order_acquire) >= 0); } static void create_gil(struct _gil_runtime_state *gil) { MUTEX_INIT(gil->mutex); #ifdef FORCE_SWITCHING MUTEX_INIT(gil->switch_mutex); #endif COND_INIT(gil->cond); #ifdef FORCE_SWITCHING COND_INIT(gil->switch_cond); #endif _Py_atomic_store_relaxed(&gil->last_holder, 0); _Py_ANNOTATE_RWLOCK_CREATE(&gil->locked); _Py_atomic_store_explicit(&gil->locked, 0, _Py_memory_order_release); } static void destroy_gil(struct _gil_runtime_state *gil) { /* some pthread-like implementations tie the mutex to the cond * and must have the cond destroyed first. */ COND_FINI(gil->cond); MUTEX_FINI(gil->mutex); #ifdef FORCE_SWITCHING COND_FINI(gil->switch_cond); MUTEX_FINI(gil->switch_mutex); #endif _Py_atomic_store_explicit(&gil->locked, -1, _Py_memory_order_release); _Py_ANNOTATE_RWLOCK_DESTROY(&gil->locked); } #ifdef HAVE_FORK static void recreate_gil(struct _gil_runtime_state *gil) { _Py_ANNOTATE_RWLOCK_DESTROY(&gil->locked); /* XXX should we destroy the old OS resources here? */ create_gil(gil); } #endif static void drop_gil(struct _ceval_state *ceval, PyThreadState *tstate) { /* If tstate is NULL, the caller is indicating that we're releasing the GIL for the last time in this thread. This is particularly relevant when the current thread state is finalizing or its interpreter is finalizing (either may be in an inconsistent state). In that case the current thread will definitely never try to acquire the GIL again. */ // XXX It may be more correct to check tstate->_status.finalizing. // XXX assert(tstate == NULL || !tstate->_status.cleared); struct _gil_runtime_state *gil = ceval->gil; if (!_Py_atomic_load_relaxed(&gil->locked)) { Py_FatalError("drop_gil: GIL is not locked"); } /* tstate is allowed to be NULL (early interpreter init) */ if (tstate != NULL) { /* Sub-interpreter support: threads might have been switched under our feet using PyThreadState_Swap(). Fix the GIL last holder variable so that our heuristics work. */ _Py_atomic_store_relaxed(&gil->last_holder, (uintptr_t)tstate); } MUTEX_LOCK(gil->mutex); _Py_ANNOTATE_RWLOCK_RELEASED(&gil->locked, /*is_write=*/1); _Py_atomic_store_relaxed(&gil->locked, 0); COND_SIGNAL(gil->cond); MUTEX_UNLOCK(gil->mutex); #ifdef FORCE_SWITCHING /* We check tstate first in case we might be releasing the GIL for the last time in this thread. In that case there's a possible race with tstate->interp getting deleted after gil->mutex is unlocked and before the following code runs, leading to a crash. We can use (tstate == NULL) to indicate the thread is done with the GIL, and that's the only time we might delete the interpreter, so checking tstate first prevents the crash. See https://github.com/python/cpython/issues/104341. */ if (tstate != NULL && _Py_atomic_load_relaxed(&ceval->gil_drop_request)) { MUTEX_LOCK(gil->switch_mutex); /* Not switched yet => wait */ if (((PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) == tstate) { assert(is_tstate_valid(tstate)); RESET_GIL_DROP_REQUEST(tstate->interp); /* NOTE: if COND_WAIT does not atomically start waiting when releasing the mutex, another thread can run through, take the GIL and drop it again, and reset the condition before we even had a chance to wait for it. */ COND_WAIT(gil->switch_cond, gil->switch_mutex); } MUTEX_UNLOCK(gil->switch_mutex); } #endif } /* Check if a Python thread must exit immediately, rather than taking the GIL if Py_Finalize() has been called. When this function is called by a daemon thread after Py_Finalize() has been called, the GIL does no longer exist. tstate must be non-NULL. */ static inline int tstate_must_exit(PyThreadState *tstate) { /* bpo-39877: Access _PyRuntime directly rather than using tstate->interp->runtime to support calls from Python daemon threads. After Py_Finalize() has been called, tstate can be a dangling pointer: point to PyThreadState freed memory. */ PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(&_PyRuntime); if (finalizing == NULL) { finalizing = _PyInterpreterState_GetFinalizing(tstate->interp); } return (finalizing != NULL && finalizing != tstate); } /* Take the GIL. The function saves errno at entry and restores its value at exit. tstate must be non-NULL. */ static void take_gil(PyThreadState *tstate) { int err = errno; assert(tstate != NULL); /* We shouldn't be using a thread state that isn't viable any more. */ // XXX It may be more correct to check tstate->_status.finalizing. // XXX assert(!tstate->_status.cleared); if (tstate_must_exit(tstate)) { /* bpo-39877: If Py_Finalize() has been called and tstate is not the thread which called Py_Finalize(), exit immediately the thread. This code path can be reached by a daemon thread after Py_Finalize() completes. In this case, tstate is a dangling pointer: points to PyThreadState freed memory. */ PyThread_exit_thread(); } assert(is_tstate_valid(tstate)); PyInterpreterState *interp = tstate->interp; struct _ceval_state *ceval = &interp->ceval; struct _gil_runtime_state *gil = ceval->gil; /* Check that _PyEval_InitThreads() was called to create the lock */ assert(gil_created(gil)); MUTEX_LOCK(gil->mutex); if (!_Py_atomic_load_relaxed(&gil->locked)) { goto _ready; } int drop_requested = 0; while (_Py_atomic_load_relaxed(&gil->locked)) { unsigned long saved_switchnum = gil->switch_number; unsigned long interval = (gil->interval >= 1 ? gil->interval : 1); int timed_out = 0; COND_TIMED_WAIT(gil->cond, gil->mutex, interval, timed_out); /* If we timed out and no switch occurred in the meantime, it is time to ask the GIL-holding thread to drop it. */ if (timed_out && _Py_atomic_load_relaxed(&gil->locked) && gil->switch_number == saved_switchnum) { if (tstate_must_exit(tstate)) { MUTEX_UNLOCK(gil->mutex); // gh-96387: If the loop requested a drop request in a previous // iteration, reset the request. Otherwise, drop_gil() can // block forever waiting for the thread which exited. Drop // requests made by other threads are also reset: these threads // may have to request again a drop request (iterate one more // time). if (drop_requested) { RESET_GIL_DROP_REQUEST(interp); } PyThread_exit_thread(); } assert(is_tstate_valid(tstate)); SET_GIL_DROP_REQUEST(interp); drop_requested = 1; } } _ready: #ifdef FORCE_SWITCHING /* This mutex must be taken before modifying gil->last_holder: see drop_gil(). */ MUTEX_LOCK(gil->switch_mutex); #endif /* We now hold the GIL */ _Py_atomic_store_relaxed(&gil->locked, 1); _Py_ANNOTATE_RWLOCK_ACQUIRED(&gil->locked, /*is_write=*/1); if (tstate != (PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) { _Py_atomic_store_relaxed(&gil->last_holder, (uintptr_t)tstate); ++gil->switch_number; } #ifdef FORCE_SWITCHING COND_SIGNAL(gil->switch_cond); MUTEX_UNLOCK(gil->switch_mutex); #endif if (tstate_must_exit(tstate)) { /* bpo-36475: If Py_Finalize() has been called and tstate is not the thread which called Py_Finalize(), exit immediately the thread. This code path can be reached by a daemon thread which was waiting in take_gil() while the main thread called wait_for_thread_shutdown() from Py_Finalize(). */ MUTEX_UNLOCK(gil->mutex); drop_gil(ceval, tstate); PyThread_exit_thread(); } assert(is_tstate_valid(tstate)); if (_Py_atomic_load_relaxed(&ceval->gil_drop_request)) { RESET_GIL_DROP_REQUEST(interp); } else { /* bpo-40010: eval_breaker should be recomputed to be set to 1 if there is a pending signal: signal received by another thread which cannot handle signals. Note: RESET_GIL_DROP_REQUEST() calls COMPUTE_EVAL_BREAKER(). */ COMPUTE_EVAL_BREAKER(interp, &_PyRuntime.ceval, ceval); } /* Don't access tstate if the thread must exit */ if (tstate->async_exc != NULL) { _PyEval_SignalAsyncExc(tstate->interp); } MUTEX_UNLOCK(gil->mutex); errno = err; } void _PyEval_SetSwitchInterval(unsigned long microseconds) { PyInterpreterState *interp = _PyInterpreterState_Get(); struct _gil_runtime_state *gil = interp->ceval.gil; assert(gil != NULL); gil->interval = microseconds; } unsigned long _PyEval_GetSwitchInterval(void) { PyInterpreterState *interp = _PyInterpreterState_Get(); struct _gil_runtime_state *gil = interp->ceval.gil; assert(gil != NULL); return gil->interval; } int _PyEval_ThreadsInitialized(void) { /* XXX This is only needed for an assert in PyGILState_Ensure(), * which currently does not work with subinterpreters. * Thus we only use the main interpreter. */ PyInterpreterState *interp = _PyInterpreterState_Main(); if (interp == NULL) { return 0; } struct _gil_runtime_state *gil = interp->ceval.gil; return gil_created(gil); } // Function removed in the Python 3.13 API but kept in the stable ABI. PyAPI_FUNC(int) PyEval_ThreadsInitialized(void) { return _PyEval_ThreadsInitialized(); } static inline int current_thread_holds_gil(struct _gil_runtime_state *gil, PyThreadState *tstate) { if (((PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) != tstate) { return 0; } return _Py_atomic_load_relaxed(&gil->locked); } static void init_shared_gil(PyInterpreterState *interp, struct _gil_runtime_state *gil) { assert(gil_created(gil)); interp->ceval.gil = gil; interp->ceval.own_gil = 0; } static void init_own_gil(PyInterpreterState *interp, struct _gil_runtime_state *gil) { assert(!gil_created(gil)); create_gil(gil); assert(gil_created(gil)); interp->ceval.gil = gil; interp->ceval.own_gil = 1; } PyStatus _PyEval_InitGIL(PyThreadState *tstate, int own_gil) { assert(tstate->interp->ceval.gil == NULL); int locked; if (!own_gil) { /* The interpreter will share the main interpreter's instead. */ PyInterpreterState *main_interp = _PyInterpreterState_Main(); assert(tstate->interp != main_interp); struct _gil_runtime_state *gil = main_interp->ceval.gil; init_shared_gil(tstate->interp, gil); locked = current_thread_holds_gil(gil, tstate); } else { PyThread_init_thread(); init_own_gil(tstate->interp, &tstate->interp->_gil); locked = 0; } if (!locked) { take_gil(tstate); } return _PyStatus_OK(); } void _PyEval_FiniGIL(PyInterpreterState *interp) { struct _gil_runtime_state *gil = interp->ceval.gil; if (gil == NULL) { /* It was already finalized (or hasn't been initialized yet). */ assert(!interp->ceval.own_gil); return; } else if (!interp->ceval.own_gil) { #ifdef Py_DEBUG PyInterpreterState *main_interp = _PyInterpreterState_Main(); assert(main_interp != NULL && interp != main_interp); assert(interp->ceval.gil == main_interp->ceval.gil); #endif interp->ceval.gil = NULL; return; } if (!gil_created(gil)) { /* First Py_InitializeFromConfig() call: the GIL doesn't exist yet: do nothing. */ return; } destroy_gil(gil); assert(!gil_created(gil)); interp->ceval.gil = NULL; } // Function removed in the Python 3.13 API but kept in the stable ABI. PyAPI_FUNC(void) PyEval_InitThreads(void) { /* Do nothing: kept for backward compatibility */ } void _PyEval_Fini(void) { #ifdef Py_STATS _Py_PrintSpecializationStats(1); #endif } // Function removed in the Python 3.13 API but kept in the stable ABI. PyAPI_FUNC(void) PyEval_AcquireLock(void) { PyThreadState *tstate = _PyThreadState_GET(); _Py_EnsureTstateNotNULL(tstate); take_gil(tstate); } // Function removed in the Python 3.13 API but kept in the stable ABI. PyAPI_FUNC(void) PyEval_ReleaseLock(void) { PyThreadState *tstate = _PyThreadState_GET(); /* This function must succeed when the current thread state is NULL. We therefore avoid PyThreadState_Get() which dumps a fatal error in debug mode. */ struct _ceval_state *ceval = &tstate->interp->ceval; drop_gil(ceval, tstate); } void _PyEval_AcquireLock(PyThreadState *tstate) { _Py_EnsureTstateNotNULL(tstate); take_gil(tstate); } void _PyEval_ReleaseLock(PyInterpreterState *interp, PyThreadState *tstate) { /* If tstate is NULL then we do not expect the current thread to acquire the GIL ever again. */ assert(tstate == NULL || tstate->interp == interp); struct _ceval_state *ceval = &interp->ceval; drop_gil(ceval, tstate); } void PyEval_AcquireThread(PyThreadState *tstate) { _Py_EnsureTstateNotNULL(tstate); take_gil(tstate); if (_PyThreadState_SwapNoGIL(tstate) != NULL) { Py_FatalError("non-NULL old thread state"); } } void PyEval_ReleaseThread(PyThreadState *tstate) { assert(is_tstate_valid(tstate)); PyThreadState *new_tstate = _PyThreadState_SwapNoGIL(NULL); if (new_tstate != tstate) { Py_FatalError("wrong thread state"); } struct _ceval_state *ceval = &tstate->interp->ceval; drop_gil(ceval, tstate); } #ifdef HAVE_FORK /* This function is called from PyOS_AfterFork_Child to destroy all threads which are not running in the child process, and clear internal locks which might be held by those threads. */ PyStatus _PyEval_ReInitThreads(PyThreadState *tstate) { assert(tstate->interp == _PyInterpreterState_Main()); struct _gil_runtime_state *gil = tstate->interp->ceval.gil; if (!gil_created(gil)) { return _PyStatus_OK(); } recreate_gil(gil); take_gil(tstate); struct _pending_calls *pending = &tstate->interp->ceval.pending; if (_PyThread_at_fork_reinit(&pending->lock) < 0) { return _PyStatus_ERR("Can't reinitialize pending calls lock"); } /* Destroy all threads except the current one */ _PyThreadState_DeleteExcept(tstate); return _PyStatus_OK(); } #endif /* This function is used to signal that async exceptions are waiting to be raised. */ void _PyEval_SignalAsyncExc(PyInterpreterState *interp) { SIGNAL_ASYNC_EXC(interp); } PyThreadState * PyEval_SaveThread(void) { PyThreadState *tstate = _PyThreadState_SwapNoGIL(NULL); _Py_EnsureTstateNotNULL(tstate); struct _ceval_state *ceval = &tstate->interp->ceval; assert(gil_created(ceval->gil)); drop_gil(ceval, tstate); return tstate; } void PyEval_RestoreThread(PyThreadState *tstate) { _Py_EnsureTstateNotNULL(tstate); take_gil(tstate); _PyThreadState_SwapNoGIL(tstate); } /* Mechanism whereby asynchronously executing callbacks (e.g. UNIX signal handlers or Mac I/O completion routines) can schedule calls to a function to be called synchronously. The synchronous function is called with one void* argument. It should return 0 for success or -1 for failure -- failure should be accompanied by an exception. If registry succeeds, the registry function returns 0; if it fails (e.g. due to too many pending calls) it returns -1 (without setting an exception condition). Note that because registry may occur from within signal handlers, or other asynchronous events, calling malloc() is unsafe! Any thread can schedule pending calls, but only the main thread will execute them. There is no facility to schedule calls to a particular thread, but that should be easy to change, should that ever be required. In that case, the static variables here should go into the python threadstate. */ void _PyEval_SignalReceived(PyInterpreterState *interp) { #ifdef MS_WINDOWS // bpo-42296: On Windows, _PyEval_SignalReceived() is called from a signal // handler which can run in a thread different than the Python thread, in // which case _Py_ThreadCanHandleSignals() is wrong. Ignore // _Py_ThreadCanHandleSignals() and always set eval_breaker to 1. // // The next eval_frame_handle_pending() call will call // _Py_ThreadCanHandleSignals() to recompute eval_breaker. int force = 1; #else int force = 0; #endif /* bpo-30703: Function called when the C signal handler of Python gets a signal. We cannot queue a callback using _PyEval_AddPendingCall() since that function is not async-signal-safe. */ SIGNAL_PENDING_SIGNALS(interp, force); } /* Push one item onto the queue while holding the lock. */ static int _push_pending_call(struct _pending_calls *pending, int (*func)(void *), void *arg) { int i = pending->last; int j = (i + 1) % NPENDINGCALLS; if (j == pending->first) { return -1; /* Queue full */ } pending->calls[i].func = func; pending->calls[i].arg = arg; pending->last = j; return 0; } /* Pop one item off the queue while holding the lock. */ static void _pop_pending_call(struct _pending_calls *pending, int (**func)(void *), void **arg) { int i = pending->first; if (i == pending->last) { return; /* Queue empty */ } *func = pending->calls[i].func; *arg = pending->calls[i].arg; pending->first = (i + 1) % NPENDINGCALLS; } /* This implementation is thread-safe. It allows scheduling to be made from any thread, and even from an executing callback. */ int _PyEval_AddPendingCall(PyInterpreterState *interp, int (*func)(void *), void *arg) { struct _pending_calls *pending = &interp->ceval.pending; /* Ensure that _PyEval_InitState() was called and that _PyEval_FiniState() is not called yet. */ assert(pending->lock != NULL); PyThread_acquire_lock(pending->lock, WAIT_LOCK); int result = _push_pending_call(pending, func, arg); PyThread_release_lock(pending->lock); /* signal main loop */ SIGNAL_PENDING_CALLS(interp); return result; } int Py_AddPendingCall(int (*func)(void *), void *arg) { /* Best-effort to support subinterpreters and calls with the GIL released. First attempt _PyThreadState_GET() since it supports subinterpreters. If the GIL is released, _PyThreadState_GET() returns NULL . In this case, use PyGILState_GetThisThreadState() which works even if the GIL is released. Sadly, PyGILState_GetThisThreadState() doesn't support subinterpreters: see bpo-10915 and bpo-15751. Py_AddPendingCall() doesn't require the caller to hold the GIL. */ PyThreadState *tstate = _PyThreadState_GET(); if (tstate == NULL) { tstate = PyGILState_GetThisThreadState(); } PyInterpreterState *interp; if (tstate != NULL) { interp = tstate->interp; } else { /* Last resort: use the main interpreter */ interp = _PyInterpreterState_Main(); } return _PyEval_AddPendingCall(interp, func, arg); } static int handle_signals(PyThreadState *tstate) { assert(is_tstate_valid(tstate)); if (!_Py_ThreadCanHandleSignals(tstate->interp)) { return 0; } UNSIGNAL_PENDING_SIGNALS(tstate->interp); if (_PyErr_CheckSignalsTstate(tstate) < 0) { /* On failure, re-schedule a call to handle_signals(). */ SIGNAL_PENDING_SIGNALS(tstate->interp, 0); return -1; } return 0; } static int make_pending_calls(PyInterpreterState *interp) { /* only execute pending calls on main thread */ if (!_Py_ThreadCanHandlePendingCalls()) { return 0; } /* don't perform recursive pending calls */ if (interp->ceval.pending.busy) { return 0; } interp->ceval.pending.busy = 1; /* unsignal before starting to call callbacks, so that any callback added in-between re-signals */ UNSIGNAL_PENDING_CALLS(interp); int res = 0; /* perform a bounded number of calls, in case of recursion */ struct _pending_calls *pending = &interp->ceval.pending; for (int i=0; ilock, WAIT_LOCK); _pop_pending_call(pending, &func, &arg); PyThread_release_lock(pending->lock); /* having released the lock, perform the callback */ if (func == NULL) { break; } res = func(arg); if (res) { goto error; } } interp->ceval.pending.busy = 0; return res; error: interp->ceval.pending.busy = 0; SIGNAL_PENDING_CALLS(interp); return res; } void _Py_FinishPendingCalls(PyThreadState *tstate) { assert(PyGILState_Check()); assert(is_tstate_valid(tstate)); struct _pending_calls *pending = &tstate->interp->ceval.pending; if (!_Py_atomic_load_relaxed_int32(&(pending->calls_to_do))) { return; } if (make_pending_calls(tstate->interp) < 0) { PyObject *exc = _PyErr_GetRaisedException(tstate); PyErr_BadInternalCall(); _PyErr_ChainExceptions1(exc); _PyErr_Print(tstate); } } /* Py_MakePendingCalls() is a simple wrapper for the sake of backward-compatibility. */ int Py_MakePendingCalls(void) { assert(PyGILState_Check()); PyThreadState *tstate = _PyThreadState_GET(); assert(is_tstate_valid(tstate)); /* Python signal handler doesn't really queue a callback: it only signals that a signal was received, see _PyEval_SignalReceived(). */ int res = handle_signals(tstate); if (res != 0) { return res; } res = make_pending_calls(tstate->interp); if (res != 0) { return res; } return 0; } void _PyEval_InitState(PyInterpreterState *interp, PyThread_type_lock pending_lock) { _gil_initialize(&interp->_gil); struct _pending_calls *pending = &interp->ceval.pending; assert(pending->lock == NULL); pending->lock = pending_lock; } void _PyEval_FiniState(struct _ceval_state *ceval) { struct _pending_calls *pending = &ceval->pending; if (pending->lock != NULL) { PyThread_free_lock(pending->lock); pending->lock = NULL; } } /* Handle signals, pending calls, GIL drop request and asynchronous exception */ int _Py_HandlePending(PyThreadState *tstate) { _PyRuntimeState * const runtime = &_PyRuntime; struct _ceval_runtime_state *ceval = &runtime->ceval; struct _ceval_state *interp_ceval_state = &tstate->interp->ceval; /* Pending signals */ if (_Py_atomic_load_relaxed_int32(&ceval->signals_pending)) { if (handle_signals(tstate) != 0) { return -1; } } /* Pending calls */ if (_Py_atomic_load_relaxed_int32(&interp_ceval_state->pending.calls_to_do)) { if (make_pending_calls(tstate->interp) != 0) { return -1; } } /* GC scheduled to run */ if (_Py_atomic_load_relaxed_int32(&interp_ceval_state->gc_scheduled)) { _Py_atomic_store_relaxed(&interp_ceval_state->gc_scheduled, 0); COMPUTE_EVAL_BREAKER(tstate->interp, ceval, interp_ceval_state); _Py_RunGC(tstate); } /* GIL drop request */ if (_Py_atomic_load_relaxed_int32(&interp_ceval_state->gil_drop_request)) { /* Give another thread a chance */ if (_PyThreadState_SwapNoGIL(NULL) != tstate) { Py_FatalError("tstate mix-up"); } drop_gil(interp_ceval_state, tstate); /* Other threads may run now */ take_gil(tstate); if (_PyThreadState_SwapNoGIL(tstate) != NULL) { Py_FatalError("orphan tstate"); } } /* Check for asynchronous exception. */ if (tstate->async_exc != NULL) { PyObject *exc = tstate->async_exc; tstate->async_exc = NULL; UNSIGNAL_ASYNC_EXC(tstate->interp); _PyErr_SetNone(tstate, exc); Py_DECREF(exc); return -1; } // It is possible that some of the conditions that trigger the eval breaker // are called in a different thread than the Python thread. An example of // this is bpo-42296: On Windows, _PyEval_SignalReceived() can be called in // a different thread than the Python thread, in which case // _Py_ThreadCanHandleSignals() is wrong. Recompute eval_breaker in the // current Python thread with the correct _Py_ThreadCanHandleSignals() // value. It prevents to interrupt the eval loop at every instruction if // the current Python thread cannot handle signals (if // _Py_ThreadCanHandleSignals() is false). COMPUTE_EVAL_BREAKER(tstate->interp, ceval, interp_ceval_state); return 0; } ================================================ FILE: Ceval_Macros.h ================================================ // Macros needed by ceval.c and bytecodes.c /* Computed GOTOs, or the-optimization-commonly-but-improperly-known-as-"threaded code" using gcc's labels-as-values extension (http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html). The traditional bytecode evaluation loop uses a "switch" statement, which decent compilers will optimize as a single indirect branch instruction combined with a lookup table of jump addresses. However, since the indirect jump instruction is shared by all opcodes, the CPU will have a hard time making the right prediction for where to jump next (actually, it will be always wrong except in the uncommon case of a sequence of several identical opcodes). "Threaded code" in contrast, uses an explicit jump table and an explicit indirect jump instruction at the end of each opcode. Since the jump instruction is at a different address for each opcode, the CPU will make a separate prediction for each of these instructions, which is equivalent to predicting the second opcode of each opcode pair. These predictions have a much better chance to turn out valid, especially in small bytecode loops. A mispredicted branch on a modern CPU flushes the whole pipeline and can cost several CPU cycles (depending on the pipeline depth), and potentially many more instructions (depending on the pipeline width). A correctly predicted branch, however, is nearly free. At the time of this writing, the "threaded code" version is up to 15-20% faster than the normal "switch" version, depending on the compiler and the CPU architecture. NOTE: care must be taken that the compiler doesn't try to "optimize" the indirect jumps by sharing them between all opcodes. Such optimizations can be disabled on gcc by using the -fno-gcse flag (or possibly -fno-crossjumping). */ /* Use macros rather than inline functions, to make it as clear as possible * to the C compiler that the tracing check is a simple test then branch. * We want to be sure that the compiler knows this before it generates * the CFG. */ #ifdef WITH_DTRACE #define OR_DTRACE_LINE | (PyDTrace_LINE_ENABLED() ? 255 : 0) #else #define OR_DTRACE_LINE #endif #ifdef HAVE_COMPUTED_GOTOS #ifndef USE_COMPUTED_GOTOS #define USE_COMPUTED_GOTOS 1 #endif #else #if defined(USE_COMPUTED_GOTOS) && USE_COMPUTED_GOTOS #error "Computed gotos are not supported on this compiler." #endif #undef USE_COMPUTED_GOTOS #define USE_COMPUTED_GOTOS 0 #endif #ifdef Py_STATS #define INSTRUCTION_START(op) \ do { \ frame->prev_instr = next_instr++; \ OPCODE_EXE_INC(op); \ if (_py_stats) _py_stats->opcode_stats[lastopcode].pair_count[op]++; \ lastopcode = op; \ } while (0) #else #define INSTRUCTION_START(op) (frame->prev_instr = next_instr++) #endif #if USE_COMPUTED_GOTOS # define TARGET(op) TARGET_##op: INSTRUCTION_START(op); # define DISPATCH_GOTO() goto *opcode_targets[opcode] #else # define TARGET(op) case op: TARGET_##op: INSTRUCTION_START(op); # define DISPATCH_GOTO() goto dispatch_opcode #endif /* PRE_DISPATCH_GOTO() does lltrace if enabled. Normally a no-op */ #ifdef LLTRACE #define PRE_DISPATCH_GOTO() if (lltrace) { \ lltrace_instruction(frame, stack_pointer, next_instr); } #else #define PRE_DISPATCH_GOTO() ((void)0) #endif /* Do interpreter dispatch accounting for tracing and instrumentation */ #define DISPATCH() \ { \ NEXTOPARG(); \ PRE_DISPATCH_GOTO(); \ DISPATCH_GOTO(); \ } #define DISPATCH_SAME_OPARG() \ { \ opcode = next_instr->op.code; \ PRE_DISPATCH_GOTO(); \ DISPATCH_GOTO(); \ } #define DISPATCH_INLINED(NEW_FRAME) \ do { \ assert(tstate->interp->eval_frame == NULL); \ _PyFrame_SetStackPointer(frame, stack_pointer); \ frame->prev_instr = next_instr - 1; \ (NEW_FRAME)->previous = frame; \ frame = cframe.current_frame = (NEW_FRAME); \ CALL_STAT_INC(inlined_py_calls); \ goto start_frame; \ } while (0) #define CHECK_EVAL_BREAKER() \ _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); \ if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker)) { \ goto handle_eval_breaker; \ } /* Tuple access macros */ #ifndef Py_DEBUG #define GETITEM(v, i) PyTuple_GET_ITEM((v), (i)) #else static inline PyObject * GETITEM(PyObject *v, Py_ssize_t i) { assert(PyTuple_Check(v)); assert(i >= 0); assert(i < PyTuple_GET_SIZE(v)); return PyTuple_GET_ITEM(v, i); } #endif /* Code access macros */ /* The integer overflow is checked by an assertion below. */ #define INSTR_OFFSET() ((int)(next_instr - _PyCode_CODE(frame->f_code))) #define NEXTOPARG() do { \ _Py_CODEUNIT word = *next_instr; \ opcode = word.op.code; \ oparg = word.op.arg; \ } while (0) #define JUMPTO(x) (next_instr = _PyCode_CODE(frame->f_code) + (x)) #define JUMPBY(x) (next_instr += (x)) /* OpCode prediction macros Some opcodes tend to come in pairs thus making it possible to predict the second code when the first is run. For example, COMPARE_OP is often followed by POP_JUMP_IF_FALSE or POP_JUMP_IF_TRUE. Verifying the prediction costs a single high-speed test of a register variable against a constant. If the pairing was good, then the processor's own internal branch predication has a high likelihood of success, resulting in a nearly zero-overhead transition to the next opcode. A successful prediction saves a trip through the eval-loop including its unpredictable switch-case branch. Combined with the processor's internal branch prediction, a successful PREDICT has the effect of making the two opcodes run as if they were a single new opcode with the bodies combined. If collecting opcode statistics, your choices are to either keep the predictions turned-on and interpret the results as if some opcodes had been combined or turn-off predictions so that the opcode frequency counter updates for both opcodes. Opcode prediction is disabled with threaded code, since the latter allows the CPU to record separate branch prediction information for each opcode. */ #define PREDICT_ID(op) PRED_##op #define PREDICTED(op) PREDICT_ID(op): /* Stack manipulation macros */ /* The stack can grow at most MAXINT deep, as co_nlocals and co_stacksize are ints. */ #define STACK_LEVEL() ((int)(stack_pointer - _PyFrame_Stackbase(frame))) #define STACK_SIZE() (frame->f_code->co_stacksize) #define EMPTY() (STACK_LEVEL() == 0) #define TOP() (stack_pointer[-1]) #define SECOND() (stack_pointer[-2]) #define THIRD() (stack_pointer[-3]) #define FOURTH() (stack_pointer[-4]) #define PEEK(n) (stack_pointer[-(n)]) #define POKE(n, v) (stack_pointer[-(n)] = (v)) #define SET_TOP(v) (stack_pointer[-1] = (v)) #define SET_SECOND(v) (stack_pointer[-2] = (v)) #define BASIC_STACKADJ(n) (stack_pointer += n) #define BASIC_PUSH(v) (*stack_pointer++ = (v)) #define BASIC_POP() (*--stack_pointer) #ifdef Py_DEBUG #define PUSH(v) do { \ BASIC_PUSH(v); \ assert(STACK_LEVEL() <= STACK_SIZE()); \ } while (0) #define POP() (assert(STACK_LEVEL() > 0), BASIC_POP()) #define STACK_GROW(n) do { \ assert(n >= 0); \ BASIC_STACKADJ(n); \ assert(STACK_LEVEL() <= STACK_SIZE()); \ } while (0) #define STACK_SHRINK(n) do { \ assert(n >= 0); \ assert(STACK_LEVEL() >= n); \ BASIC_STACKADJ(-(n)); \ } while (0) #else #define PUSH(v) BASIC_PUSH(v) #define POP() BASIC_POP() #define STACK_GROW(n) BASIC_STACKADJ(n) #define STACK_SHRINK(n) BASIC_STACKADJ(-(n)) #endif /* Local variable macros */ #define GETLOCAL(i) (frame->localsplus[i]) /* The SETLOCAL() macro must not DECREF the local variable in-place and then store the new value; it must copy the old value to a temporary value, then store the new value, and then DECREF the temporary value. This is because it is possible that during the DECREF the frame is accessed by other code (e.g. a __del__ method or gc.collect()) and the variable would be pointing to already-freed memory. */ #define SETLOCAL(i, value) do { PyObject *tmp = GETLOCAL(i); \ GETLOCAL(i) = value; \ Py_XDECREF(tmp); } while (0) #define GO_TO_INSTRUCTION(op) goto PREDICT_ID(op) #ifdef Py_STATS #define UPDATE_MISS_STATS(INSTNAME) \ do { \ STAT_INC(opcode, miss); \ STAT_INC((INSTNAME), miss); \ /* The counter is always the first cache entry: */ \ if (ADAPTIVE_COUNTER_IS_ZERO(next_instr->cache)) { \ STAT_INC((INSTNAME), deopt); \ } \ else { \ /* This is about to be (incorrectly) incremented: */ \ STAT_DEC((INSTNAME), deferred); \ } \ } while (0) #else #define UPDATE_MISS_STATS(INSTNAME) ((void)0) #endif #define DEOPT_IF(COND, INSTNAME) \ if ((COND)) { \ /* This is only a single jump on release builds! */ \ UPDATE_MISS_STATS((INSTNAME)); \ assert(_PyOpcode_Deopt[opcode] == (INSTNAME)); \ GO_TO_INSTRUCTION(INSTNAME); \ } #define GLOBALS() frame->f_globals #define BUILTINS() frame->f_builtins #define LOCALS() frame->f_locals #define DTRACE_FUNCTION_ENTRY() \ if (PyDTrace_FUNCTION_ENTRY_ENABLED()) { \ dtrace_function_entry(frame); \ } #define ADAPTIVE_COUNTER_IS_ZERO(COUNTER) \ (((COUNTER) >> ADAPTIVE_BACKOFF_BITS) == 0) #define ADAPTIVE_COUNTER_IS_MAX(COUNTER) \ (((COUNTER) >> ADAPTIVE_BACKOFF_BITS) == ((1 << MAX_BACKOFF_VALUE) - 1)) #define DECREMENT_ADAPTIVE_COUNTER(COUNTER) \ do { \ assert(!ADAPTIVE_COUNTER_IS_ZERO((COUNTER))); \ (COUNTER) -= (1 << ADAPTIVE_BACKOFF_BITS); \ } while (0); #define INCREMENT_ADAPTIVE_COUNTER(COUNTER) \ do { \ (COUNTER) += (1 << ADAPTIVE_BACKOFF_BITS); \ } while (0); #define NAME_ERROR_MSG "name '%.200s' is not defined" #define KWNAMES_LEN() \ (kwnames == NULL ? 0 : ((int)PyTuple_GET_SIZE(kwnames))) #define DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dval, result) \ do { \ if (Py_REFCNT(left) == 1) { \ ((PyFloatObject *)left)->ob_fval = (dval); \ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);\ result = (left); \ } \ else if (Py_REFCNT(right) == 1) {\ ((PyFloatObject *)right)->ob_fval = (dval); \ _Py_DECREF_NO_DEALLOC(left); \ result = (right); \ }\ else { \ result = PyFloat_FromDouble(dval); \ if ((result) == NULL) goto error; \ _Py_DECREF_NO_DEALLOC(left); \ _Py_DECREF_NO_DEALLOC(right); \ } \ } while (0) // If a trace function sets a new f_lineno and // *then* raises, we use the destination when searching // for an exception handler, displaying the traceback, and so on #define INSTRUMENTED_JUMP(src, dest, event) \ do { \ _PyFrame_SetStackPointer(frame, stack_pointer); \ next_instr = _Py_call_instrumentation_jump(tstate, event, frame, src, dest); \ stack_pointer = _PyFrame_GetStackPointer(frame); \ if (next_instr == NULL) { \ next_instr = (dest)+1; \ goto error; \ } \ } while (0); ================================================ FILE: Clinic/Python-tokenize.c.h ================================================ /*[clinic input] preserve [clinic start generated code]*/ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif static PyObject * tokenizeriter_new_impl(PyTypeObject *type, PyObject *readline, int extra_tokens, const char *encoding); static PyObject * tokenizeriter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 2 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(extra_tokens), &_Py_ID(encoding), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"", "extra_tokens", "encoding", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "tokenizeriter", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[3]; PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 2; PyObject *readline; int extra_tokens; const char *encoding = NULL; fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 1, argsbuf); if (!fastargs) { goto exit; } readline = fastargs[0]; extra_tokens = PyObject_IsTrue(fastargs[1]); if (extra_tokens < 0) { goto exit; } if (!noptargs) { goto skip_optional_kwonly; } if (!PyUnicode_Check(fastargs[2])) { _PyArg_BadArgument("tokenizeriter", "argument 'encoding'", "str", fastargs[2]); goto exit; } Py_ssize_t encoding_length; encoding = PyUnicode_AsUTF8AndSize(fastargs[2], &encoding_length); if (encoding == NULL) { goto exit; } if (strlen(encoding) != (size_t)encoding_length) { PyErr_SetString(PyExc_ValueError, "embedded null character"); goto exit; } skip_optional_kwonly: return_value = tokenizeriter_new_impl(type, readline, extra_tokens, encoding); exit: return return_value; } /*[clinic end generated code: output=48be65a2808bdfa6 input=a9049054013a1b77]*/ ================================================ FILE: Clinic/_warnings.c.h ================================================ /*[clinic input] preserve [clinic start generated code]*/ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif PyDoc_STRVAR(warnings_warn__doc__, "warn($module, /, message, category=None, stacklevel=1, source=None, *,\n" " skip_file_prefixes=)\n" "--\n" "\n" "Issue a warning, or maybe ignore it or raise an exception.\n" "\n" " message\n" " Text of the warning message.\n" " category\n" " The Warning category subclass. Defaults to UserWarning.\n" " stacklevel\n" " How far up the call stack to make this warning appear. A value of 2 for\n" " example attributes the warning to the caller of the code calling warn().\n" " source\n" " If supplied, the destroyed object which emitted a ResourceWarning\n" " skip_file_prefixes\n" " An optional tuple of module filename prefixes indicating frames to skip\n" " during stacklevel computations for stack frame attribution."); #define WARNINGS_WARN_METHODDEF \ {"warn", _PyCFunction_CAST(warnings_warn), METH_FASTCALL|METH_KEYWORDS, warnings_warn__doc__}, static PyObject * warnings_warn_impl(PyObject *module, PyObject *message, PyObject *category, Py_ssize_t stacklevel, PyObject *source, PyTupleObject *skip_file_prefixes); static PyObject * warnings_warn(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 5 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(message), &_Py_ID(category), &_Py_ID(stacklevel), &_Py_ID(source), &_Py_ID(skip_file_prefixes), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"message", "category", "stacklevel", "source", "skip_file_prefixes", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "warn", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[5]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *message; PyObject *category = Py_None; Py_ssize_t stacklevel = 1; PyObject *source = Py_None; PyTupleObject *skip_file_prefixes = NULL; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 4, 0, argsbuf); if (!args) { goto exit; } message = args[0]; if (!noptargs) { goto skip_optional_pos; } if (args[1]) { category = args[1]; if (!--noptargs) { goto skip_optional_pos; } } if (args[2]) { { Py_ssize_t ival = -1; PyObject *iobj = _PyNumber_Index(args[2]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); } if (ival == -1 && PyErr_Occurred()) { goto exit; } stacklevel = ival; } if (!--noptargs) { goto skip_optional_pos; } } if (args[3]) { source = args[3]; if (!--noptargs) { goto skip_optional_pos; } } skip_optional_pos: if (!noptargs) { goto skip_optional_kwonly; } if (!PyTuple_Check(args[4])) { _PyArg_BadArgument("warn", "argument 'skip_file_prefixes'", "tuple", args[4]); goto exit; } skip_file_prefixes = (PyTupleObject *)args[4]; skip_optional_kwonly: return_value = warnings_warn_impl(module, message, category, stacklevel, source, skip_file_prefixes); exit: return return_value; } PyDoc_STRVAR(warnings_warn_explicit__doc__, "warn_explicit($module, /, message, category, filename, lineno,\n" " module=, registry=None,\n" " module_globals=None, source=None)\n" "--\n" "\n" "Issue a warning, or maybe ignore it or raise an exception."); #define WARNINGS_WARN_EXPLICIT_METHODDEF \ {"warn_explicit", _PyCFunction_CAST(warnings_warn_explicit), METH_FASTCALL|METH_KEYWORDS, warnings_warn_explicit__doc__}, static PyObject * warnings_warn_explicit_impl(PyObject *module, PyObject *message, PyObject *category, PyObject *filename, int lineno, PyObject *mod, PyObject *registry, PyObject *module_globals, PyObject *sourceobj); static PyObject * warnings_warn_explicit(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 8 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(message), &_Py_ID(category), &_Py_ID(filename), &_Py_ID(lineno), &_Py_ID(module), &_Py_ID(registry), &_Py_ID(module_globals), &_Py_ID(source), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"message", "category", "filename", "lineno", "module", "registry", "module_globals", "source", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "warn_explicit", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[8]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 4; PyObject *message; PyObject *category; PyObject *filename; int lineno; PyObject *mod = NULL; PyObject *registry = Py_None; PyObject *module_globals = Py_None; PyObject *sourceobj = Py_None; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 4, 8, 0, argsbuf); if (!args) { goto exit; } message = args[0]; category = args[1]; if (!PyUnicode_Check(args[2])) { _PyArg_BadArgument("warn_explicit", "argument 'filename'", "str", args[2]); goto exit; } filename = args[2]; lineno = _PyLong_AsInt(args[3]); if (lineno == -1 && PyErr_Occurred()) { goto exit; } if (!noptargs) { goto skip_optional_pos; } if (args[4]) { mod = args[4]; if (!--noptargs) { goto skip_optional_pos; } } if (args[5]) { registry = args[5]; if (!--noptargs) { goto skip_optional_pos; } } if (args[6]) { module_globals = args[6]; if (!--noptargs) { goto skip_optional_pos; } } sourceobj = args[7]; skip_optional_pos: return_value = warnings_warn_explicit_impl(module, message, category, filename, lineno, mod, registry, module_globals, sourceobj); exit: return return_value; } PyDoc_STRVAR(warnings_filters_mutated__doc__, "_filters_mutated($module, /)\n" "--\n" "\n"); #define WARNINGS_FILTERS_MUTATED_METHODDEF \ {"_filters_mutated", (PyCFunction)warnings_filters_mutated, METH_NOARGS, warnings_filters_mutated__doc__}, static PyObject * warnings_filters_mutated_impl(PyObject *module); static PyObject * warnings_filters_mutated(PyObject *module, PyObject *Py_UNUSED(ignored)) { return warnings_filters_mutated_impl(module); } /*[clinic end generated code: output=f8d67e0f75771c36 input=a9049054013a1b77]*/ ================================================ FILE: Clinic/bltinmodule.c.h ================================================ /*[clinic input] preserve [clinic start generated code]*/ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif PyDoc_STRVAR(builtin___import____doc__, "__import__($module, /, name, globals=None, locals=None, fromlist=(),\n" " level=0)\n" "--\n" "\n" "Import a module.\n" "\n" "Because this function is meant for use by the Python\n" "interpreter and not for general use, it is better to use\n" "importlib.import_module() to programmatically import a module.\n" "\n" "The globals argument is only used to determine the context;\n" "they are not modified. The locals argument is unused. The fromlist\n" "should be a list of names to emulate ``from name import ...``, or an\n" "empty list to emulate ``import name``.\n" "When importing a module from a package, note that __import__(\'A.B\', ...)\n" "returns package A when fromlist is empty, but its submodule B when\n" "fromlist is not empty. The level argument is used to determine whether to\n" "perform absolute or relative imports: 0 is absolute, while a positive number\n" "is the number of parent directories to search relative to the current module."); #define BUILTIN___IMPORT___METHODDEF \ {"__import__", _PyCFunction_CAST(builtin___import__), METH_FASTCALL|METH_KEYWORDS, builtin___import____doc__}, static PyObject * builtin___import___impl(PyObject *module, PyObject *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level); static PyObject * builtin___import__(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 5 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(name), &_Py_ID(globals), &_Py_ID(locals), &_Py_ID(fromlist), &_Py_ID(level), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"name", "globals", "locals", "fromlist", "level", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "__import__", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[5]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *name; PyObject *globals = NULL; PyObject *locals = NULL; PyObject *fromlist = NULL; int level = 0; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 5, 0, argsbuf); if (!args) { goto exit; } name = args[0]; if (!noptargs) { goto skip_optional_pos; } if (args[1]) { globals = args[1]; if (!--noptargs) { goto skip_optional_pos; } } if (args[2]) { locals = args[2]; if (!--noptargs) { goto skip_optional_pos; } } if (args[3]) { fromlist = args[3]; if (!--noptargs) { goto skip_optional_pos; } } level = _PyLong_AsInt(args[4]); if (level == -1 && PyErr_Occurred()) { goto exit; } skip_optional_pos: return_value = builtin___import___impl(module, name, globals, locals, fromlist, level); exit: return return_value; } PyDoc_STRVAR(builtin_abs__doc__, "abs($module, x, /)\n" "--\n" "\n" "Return the absolute value of the argument."); #define BUILTIN_ABS_METHODDEF \ {"abs", (PyCFunction)builtin_abs, METH_O, builtin_abs__doc__}, PyDoc_STRVAR(builtin_all__doc__, "all($module, iterable, /)\n" "--\n" "\n" "Return True if bool(x) is True for all values x in the iterable.\n" "\n" "If the iterable is empty, return True."); #define BUILTIN_ALL_METHODDEF \ {"all", (PyCFunction)builtin_all, METH_O, builtin_all__doc__}, PyDoc_STRVAR(builtin_any__doc__, "any($module, iterable, /)\n" "--\n" "\n" "Return True if bool(x) is True for any x in the iterable.\n" "\n" "If the iterable is empty, return False."); #define BUILTIN_ANY_METHODDEF \ {"any", (PyCFunction)builtin_any, METH_O, builtin_any__doc__}, PyDoc_STRVAR(builtin_ascii__doc__, "ascii($module, obj, /)\n" "--\n" "\n" "Return an ASCII-only representation of an object.\n" "\n" "As repr(), return a string containing a printable representation of an\n" "object, but escape the non-ASCII characters in the string returned by\n" "repr() using \\\\x, \\\\u or \\\\U escapes. This generates a string similar\n" "to that returned by repr() in Python 2."); #define BUILTIN_ASCII_METHODDEF \ {"ascii", (PyCFunction)builtin_ascii, METH_O, builtin_ascii__doc__}, PyDoc_STRVAR(builtin_bin__doc__, "bin($module, number, /)\n" "--\n" "\n" "Return the binary representation of an integer.\n" "\n" " >>> bin(2796202)\n" " \'0b1010101010101010101010\'"); #define BUILTIN_BIN_METHODDEF \ {"bin", (PyCFunction)builtin_bin, METH_O, builtin_bin__doc__}, PyDoc_STRVAR(builtin_callable__doc__, "callable($module, obj, /)\n" "--\n" "\n" "Return whether the object is callable (i.e., some kind of function).\n" "\n" "Note that classes are callable, as are instances of classes with a\n" "__call__() method."); #define BUILTIN_CALLABLE_METHODDEF \ {"callable", (PyCFunction)builtin_callable, METH_O, builtin_callable__doc__}, PyDoc_STRVAR(builtin_format__doc__, "format($module, value, format_spec=\'\', /)\n" "--\n" "\n" "Return type(value).__format__(value, format_spec)\n" "\n" "Many built-in types implement format_spec according to the\n" "Format Specification Mini-language. See help(\'FORMATTING\').\n" "\n" "If type(value) does not supply a method named __format__\n" "and format_spec is empty, then str(value) is returned.\n" "See also help(\'SPECIALMETHODS\')."); #define BUILTIN_FORMAT_METHODDEF \ {"format", _PyCFunction_CAST(builtin_format), METH_FASTCALL, builtin_format__doc__}, static PyObject * builtin_format_impl(PyObject *module, PyObject *value, PyObject *format_spec); static PyObject * builtin_format(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *value; PyObject *format_spec = NULL; if (!_PyArg_CheckPositional("format", nargs, 1, 2)) { goto exit; } value = args[0]; if (nargs < 2) { goto skip_optional; } if (!PyUnicode_Check(args[1])) { _PyArg_BadArgument("format", "argument 2", "str", args[1]); goto exit; } format_spec = args[1]; skip_optional: return_value = builtin_format_impl(module, value, format_spec); exit: return return_value; } PyDoc_STRVAR(builtin_chr__doc__, "chr($module, i, /)\n" "--\n" "\n" "Return a Unicode string of one character with ordinal i; 0 <= i <= 0x10ffff."); #define BUILTIN_CHR_METHODDEF \ {"chr", (PyCFunction)builtin_chr, METH_O, builtin_chr__doc__}, static PyObject * builtin_chr_impl(PyObject *module, int i); static PyObject * builtin_chr(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; int i; i = _PyLong_AsInt(arg); if (i == -1 && PyErr_Occurred()) { goto exit; } return_value = builtin_chr_impl(module, i); exit: return return_value; } PyDoc_STRVAR(builtin_compile__doc__, "compile($module, /, source, filename, mode, flags=0,\n" " dont_inherit=False, optimize=-1, *, _feature_version=-1)\n" "--\n" "\n" "Compile source into a code object that can be executed by exec() or eval().\n" "\n" "The source code may represent a Python module, statement or expression.\n" "The filename will be used for run-time error messages.\n" "The mode must be \'exec\' to compile a module, \'single\' to compile a\n" "single (interactive) statement, or \'eval\' to compile an expression.\n" "The flags argument, if present, controls which future statements influence\n" "the compilation of the code.\n" "The dont_inherit argument, if true, stops the compilation inheriting\n" "the effects of any future statements in effect in the code calling\n" "compile; if absent or false these statements do influence the compilation,\n" "in addition to any features explicitly specified."); #define BUILTIN_COMPILE_METHODDEF \ {"compile", _PyCFunction_CAST(builtin_compile), METH_FASTCALL|METH_KEYWORDS, builtin_compile__doc__}, static PyObject * builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename, const char *mode, int flags, int dont_inherit, int optimize, int feature_version); static PyObject * builtin_compile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 7 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(source), &_Py_ID(filename), &_Py_ID(mode), &_Py_ID(flags), &_Py_ID(dont_inherit), &_Py_ID(optimize), &_Py_ID(_feature_version), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"source", "filename", "mode", "flags", "dont_inherit", "optimize", "_feature_version", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "compile", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[7]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3; PyObject *source; PyObject *filename; const char *mode; int flags = 0; int dont_inherit = 0; int optimize = -1; int feature_version = -1; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 6, 0, argsbuf); if (!args) { goto exit; } source = args[0]; if (!PyUnicode_FSDecoder(args[1], &filename)) { goto exit; } if (!PyUnicode_Check(args[2])) { _PyArg_BadArgument("compile", "argument 'mode'", "str", args[2]); goto exit; } Py_ssize_t mode_length; mode = PyUnicode_AsUTF8AndSize(args[2], &mode_length); if (mode == NULL) { goto exit; } if (strlen(mode) != (size_t)mode_length) { PyErr_SetString(PyExc_ValueError, "embedded null character"); goto exit; } if (!noptargs) { goto skip_optional_pos; } if (args[3]) { flags = _PyLong_AsInt(args[3]); if (flags == -1 && PyErr_Occurred()) { goto exit; } if (!--noptargs) { goto skip_optional_pos; } } if (args[4]) { dont_inherit = PyObject_IsTrue(args[4]); if (dont_inherit < 0) { goto exit; } if (!--noptargs) { goto skip_optional_pos; } } if (args[5]) { optimize = _PyLong_AsInt(args[5]); if (optimize == -1 && PyErr_Occurred()) { goto exit; } if (!--noptargs) { goto skip_optional_pos; } } skip_optional_pos: if (!noptargs) { goto skip_optional_kwonly; } feature_version = _PyLong_AsInt(args[6]); if (feature_version == -1 && PyErr_Occurred()) { goto exit; } skip_optional_kwonly: return_value = builtin_compile_impl(module, source, filename, mode, flags, dont_inherit, optimize, feature_version); exit: return return_value; } PyDoc_STRVAR(builtin_dir__doc__, "dir($module, arg=, /)\n" "--\n" "\n" "Show attributes of an object.\n" "\n" "If called without an argument, return the names in the current scope.\n" "Else, return an alphabetized list of names comprising (some of) the attributes\n" "of the given object, and of attributes reachable from it.\n" "If the object supplies a method named __dir__, it will be used; otherwise\n" "the default dir() logic is used and returns:\n" " for a module object: the module\'s attributes.\n" " for a class object: its attributes, and recursively the attributes\n" " of its bases.\n" " for any other object: its attributes, its class\'s attributes, and\n" " recursively the attributes of its class\'s base classes."); #define BUILTIN_DIR_METHODDEF \ {"dir", _PyCFunction_CAST(builtin_dir), METH_FASTCALL, builtin_dir__doc__}, static PyObject * builtin_dir_impl(PyObject *module, PyObject *arg); static PyObject * builtin_dir(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *arg = NULL; if (!_PyArg_CheckPositional("dir", nargs, 0, 1)) { goto exit; } if (nargs < 1) { goto skip_optional; } arg = args[0]; skip_optional: return_value = builtin_dir_impl(module, arg); exit: return return_value; } PyDoc_STRVAR(builtin_divmod__doc__, "divmod($module, x, y, /)\n" "--\n" "\n" "Return the tuple (x//y, x%y). Invariant: div*y + mod == x."); #define BUILTIN_DIVMOD_METHODDEF \ {"divmod", _PyCFunction_CAST(builtin_divmod), METH_FASTCALL, builtin_divmod__doc__}, static PyObject * builtin_divmod_impl(PyObject *module, PyObject *x, PyObject *y); static PyObject * builtin_divmod(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *x; PyObject *y; if (!_PyArg_CheckPositional("divmod", nargs, 2, 2)) { goto exit; } x = args[0]; y = args[1]; return_value = builtin_divmod_impl(module, x, y); exit: return return_value; } PyDoc_STRVAR(builtin_eval__doc__, "eval($module, source, globals=None, locals=None, /)\n" "--\n" "\n" "Evaluate the given source in the context of globals and locals.\n" "\n" "The source may be a string representing a Python expression\n" "or a code object as returned by compile().\n" "The globals must be a dictionary and locals can be any mapping,\n" "defaulting to the current globals and locals.\n" "If only globals is given, locals defaults to it."); #define BUILTIN_EVAL_METHODDEF \ {"eval", _PyCFunction_CAST(builtin_eval), METH_FASTCALL, builtin_eval__doc__}, static PyObject * builtin_eval_impl(PyObject *module, PyObject *source, PyObject *globals, PyObject *locals); static PyObject * builtin_eval(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *source; PyObject *globals = Py_None; PyObject *locals = Py_None; if (!_PyArg_CheckPositional("eval", nargs, 1, 3)) { goto exit; } source = args[0]; if (nargs < 2) { goto skip_optional; } globals = args[1]; if (nargs < 3) { goto skip_optional; } locals = args[2]; skip_optional: return_value = builtin_eval_impl(module, source, globals, locals); exit: return return_value; } PyDoc_STRVAR(builtin_exec__doc__, "exec($module, source, globals=None, locals=None, /, *, closure=None)\n" "--\n" "\n" "Execute the given source in the context of globals and locals.\n" "\n" "The source may be a string representing one or more Python statements\n" "or a code object as returned by compile().\n" "The globals must be a dictionary and locals can be any mapping,\n" "defaulting to the current globals and locals.\n" "If only globals is given, locals defaults to it.\n" "The closure must be a tuple of cellvars, and can only be used\n" "when source is a code object requiring exactly that many cellvars."); #define BUILTIN_EXEC_METHODDEF \ {"exec", _PyCFunction_CAST(builtin_exec), METH_FASTCALL|METH_KEYWORDS, builtin_exec__doc__}, static PyObject * builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, PyObject *locals, PyObject *closure); static PyObject * builtin_exec(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 1 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(closure), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"", "", "", "closure", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "exec", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[4]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *source; PyObject *globals = Py_None; PyObject *locals = Py_None; PyObject *closure = NULL; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 3, 0, argsbuf); if (!args) { goto exit; } source = args[0]; if (nargs < 2) { goto skip_optional_posonly; } noptargs--; globals = args[1]; if (nargs < 3) { goto skip_optional_posonly; } noptargs--; locals = args[2]; skip_optional_posonly: if (!noptargs) { goto skip_optional_kwonly; } closure = args[3]; skip_optional_kwonly: return_value = builtin_exec_impl(module, source, globals, locals, closure); exit: return return_value; } PyDoc_STRVAR(builtin_getattr__doc__, "getattr($module, object, name, default=, /)\n" "--\n" "\n" "Get a named attribute from an object.\n" "\n" "getattr(x, \'y\') is equivalent to x.y\n" "When a default argument is given, it is returned when the attribute doesn\'t\n" "exist; without it, an exception is raised in that case."); #define BUILTIN_GETATTR_METHODDEF \ {"getattr", _PyCFunction_CAST(builtin_getattr), METH_FASTCALL, builtin_getattr__doc__}, static PyObject * builtin_getattr_impl(PyObject *module, PyObject *object, PyObject *name, PyObject *default_value); static PyObject * builtin_getattr(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *object; PyObject *name; PyObject *default_value = NULL; if (!_PyArg_CheckPositional("getattr", nargs, 2, 3)) { goto exit; } object = args[0]; name = args[1]; if (nargs < 3) { goto skip_optional; } default_value = args[2]; skip_optional: return_value = builtin_getattr_impl(module, object, name, default_value); exit: return return_value; } PyDoc_STRVAR(builtin_globals__doc__, "globals($module, /)\n" "--\n" "\n" "Return the dictionary containing the current scope\'s global variables.\n" "\n" "NOTE: Updates to this dictionary *will* affect name lookups in the current\n" "global scope and vice-versa."); #define BUILTIN_GLOBALS_METHODDEF \ {"globals", (PyCFunction)builtin_globals, METH_NOARGS, builtin_globals__doc__}, static PyObject * builtin_globals_impl(PyObject *module); static PyObject * builtin_globals(PyObject *module, PyObject *Py_UNUSED(ignored)) { return builtin_globals_impl(module); } PyDoc_STRVAR(builtin_hasattr__doc__, "hasattr($module, obj, name, /)\n" "--\n" "\n" "Return whether the object has an attribute with the given name.\n" "\n" "This is done by calling getattr(obj, name) and catching AttributeError."); #define BUILTIN_HASATTR_METHODDEF \ {"hasattr", _PyCFunction_CAST(builtin_hasattr), METH_FASTCALL, builtin_hasattr__doc__}, static PyObject * builtin_hasattr_impl(PyObject *module, PyObject *obj, PyObject *name); static PyObject * builtin_hasattr(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *obj; PyObject *name; if (!_PyArg_CheckPositional("hasattr", nargs, 2, 2)) { goto exit; } obj = args[0]; name = args[1]; return_value = builtin_hasattr_impl(module, obj, name); exit: return return_value; } PyDoc_STRVAR(builtin_id__doc__, "id($module, obj, /)\n" "--\n" "\n" "Return the identity of an object.\n" "\n" "This is guaranteed to be unique among simultaneously existing objects.\n" "(CPython uses the object\'s memory address.)"); #define BUILTIN_ID_METHODDEF \ {"id", (PyCFunction)builtin_id, METH_O, builtin_id__doc__}, PyDoc_STRVAR(builtin_next__doc__, "next($module, iterator, default=, /)\n" "--\n" "\n" "Return the next item from the iterator.\n" "\n" "If default is given and the iterator is exhausted,\n" "it is returned instead of raising StopIteration."); #define BUILTIN_NEXT_METHODDEF \ {"next", _PyCFunction_CAST(builtin_next), METH_FASTCALL, builtin_next__doc__}, static PyObject * builtin_next_impl(PyObject *module, PyObject *iterator, PyObject *default_value); static PyObject * builtin_next(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *iterator; PyObject *default_value = NULL; if (!_PyArg_CheckPositional("next", nargs, 1, 2)) { goto exit; } iterator = args[0]; if (nargs < 2) { goto skip_optional; } default_value = args[1]; skip_optional: return_value = builtin_next_impl(module, iterator, default_value); exit: return return_value; } PyDoc_STRVAR(builtin_setattr__doc__, "setattr($module, obj, name, value, /)\n" "--\n" "\n" "Sets the named attribute on the given object to the specified value.\n" "\n" "setattr(x, \'y\', v) is equivalent to ``x.y = v``"); #define BUILTIN_SETATTR_METHODDEF \ {"setattr", _PyCFunction_CAST(builtin_setattr), METH_FASTCALL, builtin_setattr__doc__}, static PyObject * builtin_setattr_impl(PyObject *module, PyObject *obj, PyObject *name, PyObject *value); static PyObject * builtin_setattr(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *obj; PyObject *name; PyObject *value; if (!_PyArg_CheckPositional("setattr", nargs, 3, 3)) { goto exit; } obj = args[0]; name = args[1]; value = args[2]; return_value = builtin_setattr_impl(module, obj, name, value); exit: return return_value; } PyDoc_STRVAR(builtin_delattr__doc__, "delattr($module, obj, name, /)\n" "--\n" "\n" "Deletes the named attribute from the given object.\n" "\n" "delattr(x, \'y\') is equivalent to ``del x.y``"); #define BUILTIN_DELATTR_METHODDEF \ {"delattr", _PyCFunction_CAST(builtin_delattr), METH_FASTCALL, builtin_delattr__doc__}, static PyObject * builtin_delattr_impl(PyObject *module, PyObject *obj, PyObject *name); static PyObject * builtin_delattr(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *obj; PyObject *name; if (!_PyArg_CheckPositional("delattr", nargs, 2, 2)) { goto exit; } obj = args[0]; name = args[1]; return_value = builtin_delattr_impl(module, obj, name); exit: return return_value; } PyDoc_STRVAR(builtin_hash__doc__, "hash($module, obj, /)\n" "--\n" "\n" "Return the hash value for the given object.\n" "\n" "Two objects that compare equal must also have the same hash value, but the\n" "reverse is not necessarily true."); #define BUILTIN_HASH_METHODDEF \ {"hash", (PyCFunction)builtin_hash, METH_O, builtin_hash__doc__}, PyDoc_STRVAR(builtin_hex__doc__, "hex($module, number, /)\n" "--\n" "\n" "Return the hexadecimal representation of an integer.\n" "\n" " >>> hex(12648430)\n" " \'0xc0ffee\'"); #define BUILTIN_HEX_METHODDEF \ {"hex", (PyCFunction)builtin_hex, METH_O, builtin_hex__doc__}, PyDoc_STRVAR(builtin_iter__doc__, "iter($module, object, sentinel=, /)\n" "--\n" "\n" "Get an iterator from an object.\n" "\n" "In the first form, the argument must supply its own iterator, or be a sequence.\n" "In the second form, the callable is called until it returns the sentinel."); #define BUILTIN_ITER_METHODDEF \ {"iter", _PyCFunction_CAST(builtin_iter), METH_FASTCALL, builtin_iter__doc__}, static PyObject * builtin_iter_impl(PyObject *module, PyObject *object, PyObject *sentinel); static PyObject * builtin_iter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *object; PyObject *sentinel = NULL; if (!_PyArg_CheckPositional("iter", nargs, 1, 2)) { goto exit; } object = args[0]; if (nargs < 2) { goto skip_optional; } sentinel = args[1]; skip_optional: return_value = builtin_iter_impl(module, object, sentinel); exit: return return_value; } PyDoc_STRVAR(builtin_aiter__doc__, "aiter($module, async_iterable, /)\n" "--\n" "\n" "Return an AsyncIterator for an AsyncIterable object."); #define BUILTIN_AITER_METHODDEF \ {"aiter", (PyCFunction)builtin_aiter, METH_O, builtin_aiter__doc__}, PyDoc_STRVAR(builtin_anext__doc__, "anext($module, aiterator, default=, /)\n" "--\n" "\n" "async anext(aiterator[, default])\n" "\n" "Return the next item from the async iterator. If default is given and the async\n" "iterator is exhausted, it is returned instead of raising StopAsyncIteration."); #define BUILTIN_ANEXT_METHODDEF \ {"anext", _PyCFunction_CAST(builtin_anext), METH_FASTCALL, builtin_anext__doc__}, static PyObject * builtin_anext_impl(PyObject *module, PyObject *aiterator, PyObject *default_value); static PyObject * builtin_anext(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *aiterator; PyObject *default_value = NULL; if (!_PyArg_CheckPositional("anext", nargs, 1, 2)) { goto exit; } aiterator = args[0]; if (nargs < 2) { goto skip_optional; } default_value = args[1]; skip_optional: return_value = builtin_anext_impl(module, aiterator, default_value); exit: return return_value; } PyDoc_STRVAR(builtin_len__doc__, "len($module, obj, /)\n" "--\n" "\n" "Return the number of items in a container."); #define BUILTIN_LEN_METHODDEF \ {"len", (PyCFunction)builtin_len, METH_O, builtin_len__doc__}, PyDoc_STRVAR(builtin_locals__doc__, "locals($module, /)\n" "--\n" "\n" "Return a dictionary containing the current scope\'s local variables.\n" "\n" "NOTE: Whether or not updates to this dictionary will affect name lookups in\n" "the local scope and vice-versa is *implementation dependent* and not\n" "covered by any backwards compatibility guarantees."); #define BUILTIN_LOCALS_METHODDEF \ {"locals", (PyCFunction)builtin_locals, METH_NOARGS, builtin_locals__doc__}, static PyObject * builtin_locals_impl(PyObject *module); static PyObject * builtin_locals(PyObject *module, PyObject *Py_UNUSED(ignored)) { return builtin_locals_impl(module); } PyDoc_STRVAR(builtin_oct__doc__, "oct($module, number, /)\n" "--\n" "\n" "Return the octal representation of an integer.\n" "\n" " >>> oct(342391)\n" " \'0o1234567\'"); #define BUILTIN_OCT_METHODDEF \ {"oct", (PyCFunction)builtin_oct, METH_O, builtin_oct__doc__}, PyDoc_STRVAR(builtin_ord__doc__, "ord($module, c, /)\n" "--\n" "\n" "Return the Unicode code point for a one-character string."); #define BUILTIN_ORD_METHODDEF \ {"ord", (PyCFunction)builtin_ord, METH_O, builtin_ord__doc__}, PyDoc_STRVAR(builtin_pow__doc__, "pow($module, /, base, exp, mod=None)\n" "--\n" "\n" "Equivalent to base**exp with 2 arguments or base**exp % mod with 3 arguments\n" "\n" "Some types, such as ints, are able to use a more efficient algorithm when\n" "invoked using the three argument form."); #define BUILTIN_POW_METHODDEF \ {"pow", _PyCFunction_CAST(builtin_pow), METH_FASTCALL|METH_KEYWORDS, builtin_pow__doc__}, static PyObject * builtin_pow_impl(PyObject *module, PyObject *base, PyObject *exp, PyObject *mod); static PyObject * builtin_pow(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 3 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(base), &_Py_ID(exp), &_Py_ID(mod), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"base", "exp", "mod", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "pow", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[3]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; PyObject *base; PyObject *exp; PyObject *mod = Py_None; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 3, 0, argsbuf); if (!args) { goto exit; } base = args[0]; exp = args[1]; if (!noptargs) { goto skip_optional_pos; } mod = args[2]; skip_optional_pos: return_value = builtin_pow_impl(module, base, exp, mod); exit: return return_value; } PyDoc_STRVAR(builtin_print__doc__, "print($module, /, *args, sep=\' \', end=\'\\n\', file=None, flush=False)\n" "--\n" "\n" "Prints the values to a stream, or to sys.stdout by default.\n" "\n" " sep\n" " string inserted between values, default a space.\n" " end\n" " string appended after the last value, default a newline.\n" " file\n" " a file-like object (stream); defaults to the current sys.stdout.\n" " flush\n" " whether to forcibly flush the stream."); #define BUILTIN_PRINT_METHODDEF \ {"print", _PyCFunction_CAST(builtin_print), METH_FASTCALL|METH_KEYWORDS, builtin_print__doc__}, static PyObject * builtin_print_impl(PyObject *module, PyObject *args, PyObject *sep, PyObject *end, PyObject *file, int flush); static PyObject * builtin_print(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 4 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(sep), &_Py_ID(end), &_Py_ID(file), &_Py_ID(flush), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"sep", "end", "file", "flush", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "print", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[5]; Py_ssize_t noptargs = 0 + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; PyObject *__clinic_args = NULL; PyObject *sep = Py_None; PyObject *end = Py_None; PyObject *file = Py_None; int flush = 0; args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); if (!args) { goto exit; } __clinic_args = args[0]; if (!noptargs) { goto skip_optional_kwonly; } if (args[1]) { sep = args[1]; if (!--noptargs) { goto skip_optional_kwonly; } } if (args[2]) { end = args[2]; if (!--noptargs) { goto skip_optional_kwonly; } } if (args[3]) { file = args[3]; if (!--noptargs) { goto skip_optional_kwonly; } } flush = PyObject_IsTrue(args[4]); if (flush < 0) { goto exit; } skip_optional_kwonly: return_value = builtin_print_impl(module, __clinic_args, sep, end, file, flush); exit: Py_XDECREF(__clinic_args); return return_value; } PyDoc_STRVAR(builtin_input__doc__, "input($module, prompt=\'\', /)\n" "--\n" "\n" "Read a string from standard input. The trailing newline is stripped.\n" "\n" "The prompt string, if given, is printed to standard output without a\n" "trailing newline before reading input.\n" "\n" "If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.\n" "On *nix systems, readline is used if available."); #define BUILTIN_INPUT_METHODDEF \ {"input", _PyCFunction_CAST(builtin_input), METH_FASTCALL, builtin_input__doc__}, static PyObject * builtin_input_impl(PyObject *module, PyObject *prompt); static PyObject * builtin_input(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *prompt = NULL; if (!_PyArg_CheckPositional("input", nargs, 0, 1)) { goto exit; } if (nargs < 1) { goto skip_optional; } prompt = args[0]; skip_optional: return_value = builtin_input_impl(module, prompt); exit: return return_value; } PyDoc_STRVAR(builtin_repr__doc__, "repr($module, obj, /)\n" "--\n" "\n" "Return the canonical string representation of the object.\n" "\n" "For many object types, including most builtins, eval(repr(obj)) == obj."); #define BUILTIN_REPR_METHODDEF \ {"repr", (PyCFunction)builtin_repr, METH_O, builtin_repr__doc__}, PyDoc_STRVAR(builtin_round__doc__, "round($module, /, number, ndigits=None)\n" "--\n" "\n" "Round a number to a given precision in decimal digits.\n" "\n" "The return value is an integer if ndigits is omitted or None. Otherwise\n" "the return value has the same type as the number. ndigits may be negative."); #define BUILTIN_ROUND_METHODDEF \ {"round", _PyCFunction_CAST(builtin_round), METH_FASTCALL|METH_KEYWORDS, builtin_round__doc__}, static PyObject * builtin_round_impl(PyObject *module, PyObject *number, PyObject *ndigits); static PyObject * builtin_round(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 2 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(number), &_Py_ID(ndigits), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"number", "ndigits", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "round", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[2]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *number; PyObject *ndigits = Py_None; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf); if (!args) { goto exit; } number = args[0]; if (!noptargs) { goto skip_optional_pos; } ndigits = args[1]; skip_optional_pos: return_value = builtin_round_impl(module, number, ndigits); exit: return return_value; } PyDoc_STRVAR(builtin_vars__doc__, "vars($module, object=, /)\n" "--\n" "\n" "Show vars.\n" "\n" "Without arguments, equivalent to locals().\n" "With an argument, equivalent to object.__dict__."); #define BUILTIN_VARS_METHODDEF \ {"vars", _PyCFunction_CAST(builtin_vars), METH_FASTCALL, builtin_vars__doc__}, static PyObject * builtin_vars_impl(PyObject *module, PyObject *object); static PyObject * builtin_vars(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *object = NULL; if (!_PyArg_CheckPositional("vars", nargs, 0, 1)) { goto exit; } if (nargs < 1) { goto skip_optional; } object = args[0]; skip_optional: return_value = builtin_vars_impl(module, object); exit: return return_value; } PyDoc_STRVAR(builtin_sum__doc__, "sum($module, iterable, /, start=0)\n" "--\n" "\n" "Return the sum of a \'start\' value (default: 0) plus an iterable of numbers\n" "\n" "When the iterable is empty, return the start value.\n" "This function is intended specifically for use with numeric values and may\n" "reject non-numeric types."); #define BUILTIN_SUM_METHODDEF \ {"sum", _PyCFunction_CAST(builtin_sum), METH_FASTCALL|METH_KEYWORDS, builtin_sum__doc__}, static PyObject * builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start); static PyObject * builtin_sum(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 1 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(start), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"", "start", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "sum", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[2]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *iterable; PyObject *start = NULL; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf); if (!args) { goto exit; } iterable = args[0]; if (!noptargs) { goto skip_optional_pos; } start = args[1]; skip_optional_pos: return_value = builtin_sum_impl(module, iterable, start); exit: return return_value; } PyDoc_STRVAR(builtin_isinstance__doc__, "isinstance($module, obj, class_or_tuple, /)\n" "--\n" "\n" "Return whether an object is an instance of a class or of a subclass thereof.\n" "\n" "A tuple, as in ``isinstance(x, (A, B, ...))``, may be given as the target to\n" "check against. This is equivalent to ``isinstance(x, A) or isinstance(x, B)\n" "or ...`` etc."); #define BUILTIN_ISINSTANCE_METHODDEF \ {"isinstance", _PyCFunction_CAST(builtin_isinstance), METH_FASTCALL, builtin_isinstance__doc__}, static PyObject * builtin_isinstance_impl(PyObject *module, PyObject *obj, PyObject *class_or_tuple); static PyObject * builtin_isinstance(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *obj; PyObject *class_or_tuple; if (!_PyArg_CheckPositional("isinstance", nargs, 2, 2)) { goto exit; } obj = args[0]; class_or_tuple = args[1]; return_value = builtin_isinstance_impl(module, obj, class_or_tuple); exit: return return_value; } PyDoc_STRVAR(builtin_issubclass__doc__, "issubclass($module, cls, class_or_tuple, /)\n" "--\n" "\n" "Return whether \'cls\' is derived from another class or is the same class.\n" "\n" "A tuple, as in ``issubclass(x, (A, B, ...))``, may be given as the target to\n" "check against. This is equivalent to ``issubclass(x, A) or issubclass(x, B)\n" "or ...``."); #define BUILTIN_ISSUBCLASS_METHODDEF \ {"issubclass", _PyCFunction_CAST(builtin_issubclass), METH_FASTCALL, builtin_issubclass__doc__}, static PyObject * builtin_issubclass_impl(PyObject *module, PyObject *cls, PyObject *class_or_tuple); static PyObject * builtin_issubclass(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *cls; PyObject *class_or_tuple; if (!_PyArg_CheckPositional("issubclass", nargs, 2, 2)) { goto exit; } cls = args[0]; class_or_tuple = args[1]; return_value = builtin_issubclass_impl(module, cls, class_or_tuple); exit: return return_value; } /*[clinic end generated code: output=ef2f16ece134d62d input=a9049054013a1b77]*/ ================================================ FILE: Clinic/context.c.h ================================================ /*[clinic input] preserve [clinic start generated code]*/ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif PyDoc_STRVAR(_contextvars_Context_get__doc__, "get($self, key, default=None, /)\n" "--\n" "\n" "Return the value for `key` if `key` has the value in the context object.\n" "\n" "If `key` does not exist, return `default`. If `default` is not given,\n" "return None."); #define _CONTEXTVARS_CONTEXT_GET_METHODDEF \ {"get", _PyCFunction_CAST(_contextvars_Context_get), METH_FASTCALL, _contextvars_Context_get__doc__}, static PyObject * _contextvars_Context_get_impl(PyContext *self, PyObject *key, PyObject *default_value); static PyObject * _contextvars_Context_get(PyContext *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *key; PyObject *default_value = Py_None; if (!_PyArg_CheckPositional("get", nargs, 1, 2)) { goto exit; } key = args[0]; if (nargs < 2) { goto skip_optional; } default_value = args[1]; skip_optional: return_value = _contextvars_Context_get_impl(self, key, default_value); exit: return return_value; } PyDoc_STRVAR(_contextvars_Context_items__doc__, "items($self, /)\n" "--\n" "\n" "Return all variables and their values in the context object.\n" "\n" "The result is returned as a list of 2-tuples (variable, value)."); #define _CONTEXTVARS_CONTEXT_ITEMS_METHODDEF \ {"items", (PyCFunction)_contextvars_Context_items, METH_NOARGS, _contextvars_Context_items__doc__}, static PyObject * _contextvars_Context_items_impl(PyContext *self); static PyObject * _contextvars_Context_items(PyContext *self, PyObject *Py_UNUSED(ignored)) { return _contextvars_Context_items_impl(self); } PyDoc_STRVAR(_contextvars_Context_keys__doc__, "keys($self, /)\n" "--\n" "\n" "Return a list of all variables in the context object."); #define _CONTEXTVARS_CONTEXT_KEYS_METHODDEF \ {"keys", (PyCFunction)_contextvars_Context_keys, METH_NOARGS, _contextvars_Context_keys__doc__}, static PyObject * _contextvars_Context_keys_impl(PyContext *self); static PyObject * _contextvars_Context_keys(PyContext *self, PyObject *Py_UNUSED(ignored)) { return _contextvars_Context_keys_impl(self); } PyDoc_STRVAR(_contextvars_Context_values__doc__, "values($self, /)\n" "--\n" "\n" "Return a list of all variables\' values in the context object."); #define _CONTEXTVARS_CONTEXT_VALUES_METHODDEF \ {"values", (PyCFunction)_contextvars_Context_values, METH_NOARGS, _contextvars_Context_values__doc__}, static PyObject * _contextvars_Context_values_impl(PyContext *self); static PyObject * _contextvars_Context_values(PyContext *self, PyObject *Py_UNUSED(ignored)) { return _contextvars_Context_values_impl(self); } PyDoc_STRVAR(_contextvars_Context_copy__doc__, "copy($self, /)\n" "--\n" "\n" "Return a shallow copy of the context object."); #define _CONTEXTVARS_CONTEXT_COPY_METHODDEF \ {"copy", (PyCFunction)_contextvars_Context_copy, METH_NOARGS, _contextvars_Context_copy__doc__}, static PyObject * _contextvars_Context_copy_impl(PyContext *self); static PyObject * _contextvars_Context_copy(PyContext *self, PyObject *Py_UNUSED(ignored)) { return _contextvars_Context_copy_impl(self); } PyDoc_STRVAR(_contextvars_ContextVar_get__doc__, "get($self, default=, /)\n" "--\n" "\n" "Return a value for the context variable for the current context.\n" "\n" "If there is no value for the variable in the current context, the method will:\n" " * return the value of the default argument of the method, if provided; or\n" " * return the default value for the context variable, if it was created\n" " with one; or\n" " * raise a LookupError."); #define _CONTEXTVARS_CONTEXTVAR_GET_METHODDEF \ {"get", _PyCFunction_CAST(_contextvars_ContextVar_get), METH_FASTCALL, _contextvars_ContextVar_get__doc__}, static PyObject * _contextvars_ContextVar_get_impl(PyContextVar *self, PyObject *default_value); static PyObject * _contextvars_ContextVar_get(PyContextVar *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *default_value = NULL; if (!_PyArg_CheckPositional("get", nargs, 0, 1)) { goto exit; } if (nargs < 1) { goto skip_optional; } default_value = args[0]; skip_optional: return_value = _contextvars_ContextVar_get_impl(self, default_value); exit: return return_value; } PyDoc_STRVAR(_contextvars_ContextVar_set__doc__, "set($self, value, /)\n" "--\n" "\n" "Call to set a new value for the context variable in the current context.\n" "\n" "The required value argument is the new value for the context variable.\n" "\n" "Returns a Token object that can be used to restore the variable to its previous\n" "value via the `ContextVar.reset()` method."); #define _CONTEXTVARS_CONTEXTVAR_SET_METHODDEF \ {"set", (PyCFunction)_contextvars_ContextVar_set, METH_O, _contextvars_ContextVar_set__doc__}, PyDoc_STRVAR(_contextvars_ContextVar_reset__doc__, "reset($self, token, /)\n" "--\n" "\n" "Reset the context variable.\n" "\n" "The variable is reset to the value it had before the `ContextVar.set()` that\n" "created the token was used."); #define _CONTEXTVARS_CONTEXTVAR_RESET_METHODDEF \ {"reset", (PyCFunction)_contextvars_ContextVar_reset, METH_O, _contextvars_ContextVar_reset__doc__}, /*[clinic end generated code: output=0c94d4b919500438 input=a9049054013a1b77]*/ ================================================ FILE: Clinic/import.c.h ================================================ /*[clinic input] preserve [clinic start generated code]*/ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif PyDoc_STRVAR(_imp_lock_held__doc__, "lock_held($module, /)\n" "--\n" "\n" "Return True if the import lock is currently held, else False.\n" "\n" "On platforms without threads, return False."); #define _IMP_LOCK_HELD_METHODDEF \ {"lock_held", (PyCFunction)_imp_lock_held, METH_NOARGS, _imp_lock_held__doc__}, static PyObject * _imp_lock_held_impl(PyObject *module); static PyObject * _imp_lock_held(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _imp_lock_held_impl(module); } PyDoc_STRVAR(_imp_acquire_lock__doc__, "acquire_lock($module, /)\n" "--\n" "\n" "Acquires the interpreter\'s import lock for the current thread.\n" "\n" "This lock should be used by import hooks to ensure thread-safety when importing\n" "modules. On platforms without threads, this function does nothing."); #define _IMP_ACQUIRE_LOCK_METHODDEF \ {"acquire_lock", (PyCFunction)_imp_acquire_lock, METH_NOARGS, _imp_acquire_lock__doc__}, static PyObject * _imp_acquire_lock_impl(PyObject *module); static PyObject * _imp_acquire_lock(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _imp_acquire_lock_impl(module); } PyDoc_STRVAR(_imp_release_lock__doc__, "release_lock($module, /)\n" "--\n" "\n" "Release the interpreter\'s import lock.\n" "\n" "On platforms without threads, this function does nothing."); #define _IMP_RELEASE_LOCK_METHODDEF \ {"release_lock", (PyCFunction)_imp_release_lock, METH_NOARGS, _imp_release_lock__doc__}, static PyObject * _imp_release_lock_impl(PyObject *module); static PyObject * _imp_release_lock(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _imp_release_lock_impl(module); } PyDoc_STRVAR(_imp__fix_co_filename__doc__, "_fix_co_filename($module, code, path, /)\n" "--\n" "\n" "Changes code.co_filename to specify the passed-in file path.\n" "\n" " code\n" " Code object to change.\n" " path\n" " File path to use."); #define _IMP__FIX_CO_FILENAME_METHODDEF \ {"_fix_co_filename", _PyCFunction_CAST(_imp__fix_co_filename), METH_FASTCALL, _imp__fix_co_filename__doc__}, static PyObject * _imp__fix_co_filename_impl(PyObject *module, PyCodeObject *code, PyObject *path); static PyObject * _imp__fix_co_filename(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyCodeObject *code; PyObject *path; if (!_PyArg_CheckPositional("_fix_co_filename", nargs, 2, 2)) { goto exit; } if (!PyObject_TypeCheck(args[0], &PyCode_Type)) { _PyArg_BadArgument("_fix_co_filename", "argument 1", (&PyCode_Type)->tp_name, args[0]); goto exit; } code = (PyCodeObject *)args[0]; if (!PyUnicode_Check(args[1])) { _PyArg_BadArgument("_fix_co_filename", "argument 2", "str", args[1]); goto exit; } path = args[1]; return_value = _imp__fix_co_filename_impl(module, code, path); exit: return return_value; } PyDoc_STRVAR(_imp_create_builtin__doc__, "create_builtin($module, spec, /)\n" "--\n" "\n" "Create an extension module."); #define _IMP_CREATE_BUILTIN_METHODDEF \ {"create_builtin", (PyCFunction)_imp_create_builtin, METH_O, _imp_create_builtin__doc__}, PyDoc_STRVAR(_imp_extension_suffixes__doc__, "extension_suffixes($module, /)\n" "--\n" "\n" "Returns the list of file suffixes used to identify extension modules."); #define _IMP_EXTENSION_SUFFIXES_METHODDEF \ {"extension_suffixes", (PyCFunction)_imp_extension_suffixes, METH_NOARGS, _imp_extension_suffixes__doc__}, static PyObject * _imp_extension_suffixes_impl(PyObject *module); static PyObject * _imp_extension_suffixes(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _imp_extension_suffixes_impl(module); } PyDoc_STRVAR(_imp_init_frozen__doc__, "init_frozen($module, name, /)\n" "--\n" "\n" "Initializes a frozen module."); #define _IMP_INIT_FROZEN_METHODDEF \ {"init_frozen", (PyCFunction)_imp_init_frozen, METH_O, _imp_init_frozen__doc__}, static PyObject * _imp_init_frozen_impl(PyObject *module, PyObject *name); static PyObject * _imp_init_frozen(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; PyObject *name; if (!PyUnicode_Check(arg)) { _PyArg_BadArgument("init_frozen", "argument", "str", arg); goto exit; } name = arg; return_value = _imp_init_frozen_impl(module, name); exit: return return_value; } PyDoc_STRVAR(_imp_find_frozen__doc__, "find_frozen($module, name, /, *, withdata=False)\n" "--\n" "\n" "Return info about the corresponding frozen module (if there is one) or None.\n" "\n" "The returned info (a 2-tuple):\n" "\n" " * data the raw marshalled bytes\n" " * is_package whether or not it is a package\n" " * origname the originally frozen module\'s name, or None if not\n" " a stdlib module (this will usually be the same as\n" " the module\'s current name)"); #define _IMP_FIND_FROZEN_METHODDEF \ {"find_frozen", _PyCFunction_CAST(_imp_find_frozen), METH_FASTCALL|METH_KEYWORDS, _imp_find_frozen__doc__}, static PyObject * _imp_find_frozen_impl(PyObject *module, PyObject *name, int withdata); static PyObject * _imp_find_frozen(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 1 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(withdata), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"", "withdata", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "find_frozen", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[2]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *name; int withdata = 0; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); if (!args) { goto exit; } if (!PyUnicode_Check(args[0])) { _PyArg_BadArgument("find_frozen", "argument 1", "str", args[0]); goto exit; } name = args[0]; if (!noptargs) { goto skip_optional_kwonly; } withdata = PyObject_IsTrue(args[1]); if (withdata < 0) { goto exit; } skip_optional_kwonly: return_value = _imp_find_frozen_impl(module, name, withdata); exit: return return_value; } PyDoc_STRVAR(_imp_get_frozen_object__doc__, "get_frozen_object($module, name, data=None, /)\n" "--\n" "\n" "Create a code object for a frozen module."); #define _IMP_GET_FROZEN_OBJECT_METHODDEF \ {"get_frozen_object", _PyCFunction_CAST(_imp_get_frozen_object), METH_FASTCALL, _imp_get_frozen_object__doc__}, static PyObject * _imp_get_frozen_object_impl(PyObject *module, PyObject *name, PyObject *dataobj); static PyObject * _imp_get_frozen_object(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *name; PyObject *dataobj = Py_None; if (!_PyArg_CheckPositional("get_frozen_object", nargs, 1, 2)) { goto exit; } if (!PyUnicode_Check(args[0])) { _PyArg_BadArgument("get_frozen_object", "argument 1", "str", args[0]); goto exit; } name = args[0]; if (nargs < 2) { goto skip_optional; } dataobj = args[1]; skip_optional: return_value = _imp_get_frozen_object_impl(module, name, dataobj); exit: return return_value; } PyDoc_STRVAR(_imp_is_frozen_package__doc__, "is_frozen_package($module, name, /)\n" "--\n" "\n" "Returns True if the module name is of a frozen package."); #define _IMP_IS_FROZEN_PACKAGE_METHODDEF \ {"is_frozen_package", (PyCFunction)_imp_is_frozen_package, METH_O, _imp_is_frozen_package__doc__}, static PyObject * _imp_is_frozen_package_impl(PyObject *module, PyObject *name); static PyObject * _imp_is_frozen_package(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; PyObject *name; if (!PyUnicode_Check(arg)) { _PyArg_BadArgument("is_frozen_package", "argument", "str", arg); goto exit; } name = arg; return_value = _imp_is_frozen_package_impl(module, name); exit: return return_value; } PyDoc_STRVAR(_imp_is_builtin__doc__, "is_builtin($module, name, /)\n" "--\n" "\n" "Returns True if the module name corresponds to a built-in module."); #define _IMP_IS_BUILTIN_METHODDEF \ {"is_builtin", (PyCFunction)_imp_is_builtin, METH_O, _imp_is_builtin__doc__}, static PyObject * _imp_is_builtin_impl(PyObject *module, PyObject *name); static PyObject * _imp_is_builtin(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; PyObject *name; if (!PyUnicode_Check(arg)) { _PyArg_BadArgument("is_builtin", "argument", "str", arg); goto exit; } name = arg; return_value = _imp_is_builtin_impl(module, name); exit: return return_value; } PyDoc_STRVAR(_imp_is_frozen__doc__, "is_frozen($module, name, /)\n" "--\n" "\n" "Returns True if the module name corresponds to a frozen module."); #define _IMP_IS_FROZEN_METHODDEF \ {"is_frozen", (PyCFunction)_imp_is_frozen, METH_O, _imp_is_frozen__doc__}, static PyObject * _imp_is_frozen_impl(PyObject *module, PyObject *name); static PyObject * _imp_is_frozen(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; PyObject *name; if (!PyUnicode_Check(arg)) { _PyArg_BadArgument("is_frozen", "argument", "str", arg); goto exit; } name = arg; return_value = _imp_is_frozen_impl(module, name); exit: return return_value; } PyDoc_STRVAR(_imp__frozen_module_names__doc__, "_frozen_module_names($module, /)\n" "--\n" "\n" "Returns the list of available frozen modules."); #define _IMP__FROZEN_MODULE_NAMES_METHODDEF \ {"_frozen_module_names", (PyCFunction)_imp__frozen_module_names, METH_NOARGS, _imp__frozen_module_names__doc__}, static PyObject * _imp__frozen_module_names_impl(PyObject *module); static PyObject * _imp__frozen_module_names(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _imp__frozen_module_names_impl(module); } PyDoc_STRVAR(_imp__override_frozen_modules_for_tests__doc__, "_override_frozen_modules_for_tests($module, override, /)\n" "--\n" "\n" "(internal-only) Override PyConfig.use_frozen_modules.\n" "\n" "(-1: \"off\", 1: \"on\", 0: no override)\n" "See frozen_modules() in Lib/test/support/import_helper.py."); #define _IMP__OVERRIDE_FROZEN_MODULES_FOR_TESTS_METHODDEF \ {"_override_frozen_modules_for_tests", (PyCFunction)_imp__override_frozen_modules_for_tests, METH_O, _imp__override_frozen_modules_for_tests__doc__}, static PyObject * _imp__override_frozen_modules_for_tests_impl(PyObject *module, int override); static PyObject * _imp__override_frozen_modules_for_tests(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; int override; override = _PyLong_AsInt(arg); if (override == -1 && PyErr_Occurred()) { goto exit; } return_value = _imp__override_frozen_modules_for_tests_impl(module, override); exit: return return_value; } PyDoc_STRVAR(_imp__override_multi_interp_extensions_check__doc__, "_override_multi_interp_extensions_check($module, override, /)\n" "--\n" "\n" "(internal-only) Override PyInterpreterConfig.check_multi_interp_extensions.\n" "\n" "(-1: \"never\", 1: \"always\", 0: no override)"); #define _IMP__OVERRIDE_MULTI_INTERP_EXTENSIONS_CHECK_METHODDEF \ {"_override_multi_interp_extensions_check", (PyCFunction)_imp__override_multi_interp_extensions_check, METH_O, _imp__override_multi_interp_extensions_check__doc__}, static PyObject * _imp__override_multi_interp_extensions_check_impl(PyObject *module, int override); static PyObject * _imp__override_multi_interp_extensions_check(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; int override; override = _PyLong_AsInt(arg); if (override == -1 && PyErr_Occurred()) { goto exit; } return_value = _imp__override_multi_interp_extensions_check_impl(module, override); exit: return return_value; } #if defined(HAVE_DYNAMIC_LOADING) PyDoc_STRVAR(_imp_create_dynamic__doc__, "create_dynamic($module, spec, file=, /)\n" "--\n" "\n" "Create an extension module."); #define _IMP_CREATE_DYNAMIC_METHODDEF \ {"create_dynamic", _PyCFunction_CAST(_imp_create_dynamic), METH_FASTCALL, _imp_create_dynamic__doc__}, static PyObject * _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file); static PyObject * _imp_create_dynamic(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *spec; PyObject *file = NULL; if (!_PyArg_CheckPositional("create_dynamic", nargs, 1, 2)) { goto exit; } spec = args[0]; if (nargs < 2) { goto skip_optional; } file = args[1]; skip_optional: return_value = _imp_create_dynamic_impl(module, spec, file); exit: return return_value; } #endif /* defined(HAVE_DYNAMIC_LOADING) */ #if defined(HAVE_DYNAMIC_LOADING) PyDoc_STRVAR(_imp_exec_dynamic__doc__, "exec_dynamic($module, mod, /)\n" "--\n" "\n" "Initialize an extension module."); #define _IMP_EXEC_DYNAMIC_METHODDEF \ {"exec_dynamic", (PyCFunction)_imp_exec_dynamic, METH_O, _imp_exec_dynamic__doc__}, static int _imp_exec_dynamic_impl(PyObject *module, PyObject *mod); static PyObject * _imp_exec_dynamic(PyObject *module, PyObject *mod) { PyObject *return_value = NULL; int _return_value; _return_value = _imp_exec_dynamic_impl(module, mod); if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } return_value = PyLong_FromLong((long)_return_value); exit: return return_value; } #endif /* defined(HAVE_DYNAMIC_LOADING) */ PyDoc_STRVAR(_imp_exec_builtin__doc__, "exec_builtin($module, mod, /)\n" "--\n" "\n" "Initialize a built-in module."); #define _IMP_EXEC_BUILTIN_METHODDEF \ {"exec_builtin", (PyCFunction)_imp_exec_builtin, METH_O, _imp_exec_builtin__doc__}, static int _imp_exec_builtin_impl(PyObject *module, PyObject *mod); static PyObject * _imp_exec_builtin(PyObject *module, PyObject *mod) { PyObject *return_value = NULL; int _return_value; _return_value = _imp_exec_builtin_impl(module, mod); if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } return_value = PyLong_FromLong((long)_return_value); exit: return return_value; } PyDoc_STRVAR(_imp_source_hash__doc__, "source_hash($module, /, key, source)\n" "--\n" "\n"); #define _IMP_SOURCE_HASH_METHODDEF \ {"source_hash", _PyCFunction_CAST(_imp_source_hash), METH_FASTCALL|METH_KEYWORDS, _imp_source_hash__doc__}, static PyObject * _imp_source_hash_impl(PyObject *module, long key, Py_buffer *source); static PyObject * _imp_source_hash(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 2 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(key), &_Py_ID(source), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"key", "source", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "source_hash", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[2]; long key; Py_buffer source = {NULL, NULL}; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); if (!args) { goto exit; } key = PyLong_AsLong(args[0]); if (key == -1 && PyErr_Occurred()) { goto exit; } if (PyObject_GetBuffer(args[1], &source, PyBUF_SIMPLE) != 0) { goto exit; } if (!PyBuffer_IsContiguous(&source, 'C')) { _PyArg_BadArgument("source_hash", "argument 'source'", "contiguous buffer", args[1]); goto exit; } return_value = _imp_source_hash_impl(module, key, &source); exit: /* Cleanup for source */ if (source.obj) { PyBuffer_Release(&source); } return return_value; } #ifndef _IMP_CREATE_DYNAMIC_METHODDEF #define _IMP_CREATE_DYNAMIC_METHODDEF #endif /* !defined(_IMP_CREATE_DYNAMIC_METHODDEF) */ #ifndef _IMP_EXEC_DYNAMIC_METHODDEF #define _IMP_EXEC_DYNAMIC_METHODDEF #endif /* !defined(_IMP_EXEC_DYNAMIC_METHODDEF) */ /*[clinic end generated code: output=a95ec234672280a2 input=a9049054013a1b77]*/ ================================================ FILE: Clinic/instrumentation.c.h ================================================ /*[clinic input] preserve [clinic start generated code]*/ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif PyDoc_STRVAR(monitoring_use_tool_id__doc__, "use_tool_id($module, tool_id, name, /)\n" "--\n" "\n"); #define MONITORING_USE_TOOL_ID_METHODDEF \ {"use_tool_id", _PyCFunction_CAST(monitoring_use_tool_id), METH_FASTCALL, monitoring_use_tool_id__doc__}, static PyObject * monitoring_use_tool_id_impl(PyObject *module, int tool_id, PyObject *name); static PyObject * monitoring_use_tool_id(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int tool_id; PyObject *name; if (!_PyArg_CheckPositional("use_tool_id", nargs, 2, 2)) { goto exit; } tool_id = _PyLong_AsInt(args[0]); if (tool_id == -1 && PyErr_Occurred()) { goto exit; } name = args[1]; return_value = monitoring_use_tool_id_impl(module, tool_id, name); exit: return return_value; } PyDoc_STRVAR(monitoring_free_tool_id__doc__, "free_tool_id($module, tool_id, /)\n" "--\n" "\n"); #define MONITORING_FREE_TOOL_ID_METHODDEF \ {"free_tool_id", (PyCFunction)monitoring_free_tool_id, METH_O, monitoring_free_tool_id__doc__}, static PyObject * monitoring_free_tool_id_impl(PyObject *module, int tool_id); static PyObject * monitoring_free_tool_id(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; int tool_id; tool_id = _PyLong_AsInt(arg); if (tool_id == -1 && PyErr_Occurred()) { goto exit; } return_value = monitoring_free_tool_id_impl(module, tool_id); exit: return return_value; } PyDoc_STRVAR(monitoring_get_tool__doc__, "get_tool($module, tool_id, /)\n" "--\n" "\n"); #define MONITORING_GET_TOOL_METHODDEF \ {"get_tool", (PyCFunction)monitoring_get_tool, METH_O, monitoring_get_tool__doc__}, static PyObject * monitoring_get_tool_impl(PyObject *module, int tool_id); static PyObject * monitoring_get_tool(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; int tool_id; tool_id = _PyLong_AsInt(arg); if (tool_id == -1 && PyErr_Occurred()) { goto exit; } return_value = monitoring_get_tool_impl(module, tool_id); exit: return return_value; } PyDoc_STRVAR(monitoring_register_callback__doc__, "register_callback($module, tool_id, event, func, /)\n" "--\n" "\n"); #define MONITORING_REGISTER_CALLBACK_METHODDEF \ {"register_callback", _PyCFunction_CAST(monitoring_register_callback), METH_FASTCALL, monitoring_register_callback__doc__}, static PyObject * monitoring_register_callback_impl(PyObject *module, int tool_id, int event, PyObject *func); static PyObject * monitoring_register_callback(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int tool_id; int event; PyObject *func; if (!_PyArg_CheckPositional("register_callback", nargs, 3, 3)) { goto exit; } tool_id = _PyLong_AsInt(args[0]); if (tool_id == -1 && PyErr_Occurred()) { goto exit; } event = _PyLong_AsInt(args[1]); if (event == -1 && PyErr_Occurred()) { goto exit; } func = args[2]; return_value = monitoring_register_callback_impl(module, tool_id, event, func); exit: return return_value; } PyDoc_STRVAR(monitoring_get_events__doc__, "get_events($module, tool_id, /)\n" "--\n" "\n"); #define MONITORING_GET_EVENTS_METHODDEF \ {"get_events", (PyCFunction)monitoring_get_events, METH_O, monitoring_get_events__doc__}, static int monitoring_get_events_impl(PyObject *module, int tool_id); static PyObject * monitoring_get_events(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; int tool_id; int _return_value; tool_id = _PyLong_AsInt(arg); if (tool_id == -1 && PyErr_Occurred()) { goto exit; } _return_value = monitoring_get_events_impl(module, tool_id); if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } return_value = PyLong_FromLong((long)_return_value); exit: return return_value; } PyDoc_STRVAR(monitoring_set_events__doc__, "set_events($module, tool_id, event_set, /)\n" "--\n" "\n"); #define MONITORING_SET_EVENTS_METHODDEF \ {"set_events", _PyCFunction_CAST(monitoring_set_events), METH_FASTCALL, monitoring_set_events__doc__}, static PyObject * monitoring_set_events_impl(PyObject *module, int tool_id, int event_set); static PyObject * monitoring_set_events(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int tool_id; int event_set; if (!_PyArg_CheckPositional("set_events", nargs, 2, 2)) { goto exit; } tool_id = _PyLong_AsInt(args[0]); if (tool_id == -1 && PyErr_Occurred()) { goto exit; } event_set = _PyLong_AsInt(args[1]); if (event_set == -1 && PyErr_Occurred()) { goto exit; } return_value = monitoring_set_events_impl(module, tool_id, event_set); exit: return return_value; } PyDoc_STRVAR(monitoring_get_local_events__doc__, "get_local_events($module, tool_id, code, /)\n" "--\n" "\n"); #define MONITORING_GET_LOCAL_EVENTS_METHODDEF \ {"get_local_events", _PyCFunction_CAST(monitoring_get_local_events), METH_FASTCALL, monitoring_get_local_events__doc__}, static int monitoring_get_local_events_impl(PyObject *module, int tool_id, PyObject *code); static PyObject * monitoring_get_local_events(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int tool_id; PyObject *code; int _return_value; if (!_PyArg_CheckPositional("get_local_events", nargs, 2, 2)) { goto exit; } tool_id = _PyLong_AsInt(args[0]); if (tool_id == -1 && PyErr_Occurred()) { goto exit; } code = args[1]; _return_value = monitoring_get_local_events_impl(module, tool_id, code); if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } return_value = PyLong_FromLong((long)_return_value); exit: return return_value; } PyDoc_STRVAR(monitoring_set_local_events__doc__, "set_local_events($module, tool_id, code, event_set, /)\n" "--\n" "\n"); #define MONITORING_SET_LOCAL_EVENTS_METHODDEF \ {"set_local_events", _PyCFunction_CAST(monitoring_set_local_events), METH_FASTCALL, monitoring_set_local_events__doc__}, static PyObject * monitoring_set_local_events_impl(PyObject *module, int tool_id, PyObject *code, int event_set); static PyObject * monitoring_set_local_events(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int tool_id; PyObject *code; int event_set; if (!_PyArg_CheckPositional("set_local_events", nargs, 3, 3)) { goto exit; } tool_id = _PyLong_AsInt(args[0]); if (tool_id == -1 && PyErr_Occurred()) { goto exit; } code = args[1]; event_set = _PyLong_AsInt(args[2]); if (event_set == -1 && PyErr_Occurred()) { goto exit; } return_value = monitoring_set_local_events_impl(module, tool_id, code, event_set); exit: return return_value; } PyDoc_STRVAR(monitoring_restart_events__doc__, "restart_events($module, /)\n" "--\n" "\n"); #define MONITORING_RESTART_EVENTS_METHODDEF \ {"restart_events", (PyCFunction)monitoring_restart_events, METH_NOARGS, monitoring_restart_events__doc__}, static PyObject * monitoring_restart_events_impl(PyObject *module); static PyObject * monitoring_restart_events(PyObject *module, PyObject *Py_UNUSED(ignored)) { return monitoring_restart_events_impl(module); } PyDoc_STRVAR(monitoring__all_events__doc__, "_all_events($module, /)\n" "--\n" "\n"); #define MONITORING__ALL_EVENTS_METHODDEF \ {"_all_events", (PyCFunction)monitoring__all_events, METH_NOARGS, monitoring__all_events__doc__}, static PyObject * monitoring__all_events_impl(PyObject *module); static PyObject * monitoring__all_events(PyObject *module, PyObject *Py_UNUSED(ignored)) { return monitoring__all_events_impl(module); } /*[clinic end generated code: output=11cc0803875b3ffa input=a9049054013a1b77]*/ ================================================ FILE: Clinic/marshal.c.h ================================================ /*[clinic input] preserve [clinic start generated code]*/ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif PyDoc_STRVAR(marshal_dump__doc__, "dump($module, value, file, version=version, /)\n" "--\n" "\n" "Write the value on the open file.\n" "\n" " value\n" " Must be a supported type.\n" " file\n" " Must be a writeable binary file.\n" " version\n" " Indicates the data format that dump should use.\n" "\n" "If the value has (or contains an object that has) an unsupported type, a\n" "ValueError exception is raised - but garbage data will also be written\n" "to the file. The object will not be properly read back by load()."); #define MARSHAL_DUMP_METHODDEF \ {"dump", _PyCFunction_CAST(marshal_dump), METH_FASTCALL, marshal_dump__doc__}, static PyObject * marshal_dump_impl(PyObject *module, PyObject *value, PyObject *file, int version); static PyObject * marshal_dump(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *value; PyObject *file; int version = Py_MARSHAL_VERSION; if (!_PyArg_CheckPositional("dump", nargs, 2, 3)) { goto exit; } value = args[0]; file = args[1]; if (nargs < 3) { goto skip_optional; } version = _PyLong_AsInt(args[2]); if (version == -1 && PyErr_Occurred()) { goto exit; } skip_optional: return_value = marshal_dump_impl(module, value, file, version); exit: return return_value; } PyDoc_STRVAR(marshal_load__doc__, "load($module, file, /)\n" "--\n" "\n" "Read one value from the open file and return it.\n" "\n" " file\n" " Must be readable binary file.\n" "\n" "If no valid value is read (e.g. because the data has a different Python\n" "version\'s incompatible marshal format), raise EOFError, ValueError or\n" "TypeError.\n" "\n" "Note: If an object containing an unsupported type was marshalled with\n" "dump(), load() will substitute None for the unmarshallable type."); #define MARSHAL_LOAD_METHODDEF \ {"load", (PyCFunction)marshal_load, METH_O, marshal_load__doc__}, PyDoc_STRVAR(marshal_dumps__doc__, "dumps($module, value, version=version, /)\n" "--\n" "\n" "Return the bytes object that would be written to a file by dump(value, file).\n" "\n" " value\n" " Must be a supported type.\n" " version\n" " Indicates the data format that dumps should use.\n" "\n" "Raise a ValueError exception if value has (or contains an object that has) an\n" "unsupported type."); #define MARSHAL_DUMPS_METHODDEF \ {"dumps", _PyCFunction_CAST(marshal_dumps), METH_FASTCALL, marshal_dumps__doc__}, static PyObject * marshal_dumps_impl(PyObject *module, PyObject *value, int version); static PyObject * marshal_dumps(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *value; int version = Py_MARSHAL_VERSION; if (!_PyArg_CheckPositional("dumps", nargs, 1, 2)) { goto exit; } value = args[0]; if (nargs < 2) { goto skip_optional; } version = _PyLong_AsInt(args[1]); if (version == -1 && PyErr_Occurred()) { goto exit; } skip_optional: return_value = marshal_dumps_impl(module, value, version); exit: return return_value; } PyDoc_STRVAR(marshal_loads__doc__, "loads($module, bytes, /)\n" "--\n" "\n" "Convert the bytes-like object to a value.\n" "\n" "If no valid value is found, raise EOFError, ValueError or TypeError. Extra\n" "bytes in the input are ignored."); #define MARSHAL_LOADS_METHODDEF \ {"loads", (PyCFunction)marshal_loads, METH_O, marshal_loads__doc__}, static PyObject * marshal_loads_impl(PyObject *module, Py_buffer *bytes); static PyObject * marshal_loads(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; Py_buffer bytes = {NULL, NULL}; if (PyObject_GetBuffer(arg, &bytes, PyBUF_SIMPLE) != 0) { goto exit; } if (!PyBuffer_IsContiguous(&bytes, 'C')) { _PyArg_BadArgument("loads", "argument", "contiguous buffer", arg); goto exit; } return_value = marshal_loads_impl(module, &bytes); exit: /* Cleanup for bytes */ if (bytes.obj) { PyBuffer_Release(&bytes); } return return_value; } /*[clinic end generated code: output=12082d61d2942473 input=a9049054013a1b77]*/ ================================================ FILE: Clinic/sysmodule.c.h ================================================ /*[clinic input] preserve [clinic start generated code]*/ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif PyDoc_STRVAR(sys_addaudithook__doc__, "addaudithook($module, /, hook)\n" "--\n" "\n" "Adds a new audit hook callback."); #define SYS_ADDAUDITHOOK_METHODDEF \ {"addaudithook", _PyCFunction_CAST(sys_addaudithook), METH_FASTCALL|METH_KEYWORDS, sys_addaudithook__doc__}, static PyObject * sys_addaudithook_impl(PyObject *module, PyObject *hook); static PyObject * sys_addaudithook(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 1 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(hook), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"hook", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "addaudithook", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[1]; PyObject *hook; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); if (!args) { goto exit; } hook = args[0]; return_value = sys_addaudithook_impl(module, hook); exit: return return_value; } PyDoc_STRVAR(sys_displayhook__doc__, "displayhook($module, object, /)\n" "--\n" "\n" "Print an object to sys.stdout and also save it in builtins._"); #define SYS_DISPLAYHOOK_METHODDEF \ {"displayhook", (PyCFunction)sys_displayhook, METH_O, sys_displayhook__doc__}, PyDoc_STRVAR(sys_excepthook__doc__, "excepthook($module, exctype, value, traceback, /)\n" "--\n" "\n" "Handle an exception by displaying it with a traceback on sys.stderr."); #define SYS_EXCEPTHOOK_METHODDEF \ {"excepthook", _PyCFunction_CAST(sys_excepthook), METH_FASTCALL, sys_excepthook__doc__}, static PyObject * sys_excepthook_impl(PyObject *module, PyObject *exctype, PyObject *value, PyObject *traceback); static PyObject * sys_excepthook(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *exctype; PyObject *value; PyObject *traceback; if (!_PyArg_CheckPositional("excepthook", nargs, 3, 3)) { goto exit; } exctype = args[0]; value = args[1]; traceback = args[2]; return_value = sys_excepthook_impl(module, exctype, value, traceback); exit: return return_value; } PyDoc_STRVAR(sys_exception__doc__, "exception($module, /)\n" "--\n" "\n" "Return the current exception.\n" "\n" "Return the most recent exception caught by an except clause\n" "in the current stack frame or in an older stack frame, or None\n" "if no such exception exists."); #define SYS_EXCEPTION_METHODDEF \ {"exception", (PyCFunction)sys_exception, METH_NOARGS, sys_exception__doc__}, static PyObject * sys_exception_impl(PyObject *module); static PyObject * sys_exception(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_exception_impl(module); } PyDoc_STRVAR(sys_exc_info__doc__, "exc_info($module, /)\n" "--\n" "\n" "Return current exception information: (type, value, traceback).\n" "\n" "Return information about the most recent exception caught by an except\n" "clause in the current stack frame or in an older stack frame."); #define SYS_EXC_INFO_METHODDEF \ {"exc_info", (PyCFunction)sys_exc_info, METH_NOARGS, sys_exc_info__doc__}, static PyObject * sys_exc_info_impl(PyObject *module); static PyObject * sys_exc_info(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_exc_info_impl(module); } PyDoc_STRVAR(sys_unraisablehook__doc__, "unraisablehook($module, unraisable, /)\n" "--\n" "\n" "Handle an unraisable exception.\n" "\n" "The unraisable argument has the following attributes:\n" "\n" "* exc_type: Exception type.\n" "* exc_value: Exception value, can be None.\n" "* exc_traceback: Exception traceback, can be None.\n" "* err_msg: Error message, can be None.\n" "* object: Object causing the exception, can be None."); #define SYS_UNRAISABLEHOOK_METHODDEF \ {"unraisablehook", (PyCFunction)sys_unraisablehook, METH_O, sys_unraisablehook__doc__}, PyDoc_STRVAR(sys_exit__doc__, "exit($module, status=None, /)\n" "--\n" "\n" "Exit the interpreter by raising SystemExit(status).\n" "\n" "If the status is omitted or None, it defaults to zero (i.e., success).\n" "If the status is an integer, it will be used as the system exit status.\n" "If it is another kind of object, it will be printed and the system\n" "exit status will be one (i.e., failure)."); #define SYS_EXIT_METHODDEF \ {"exit", _PyCFunction_CAST(sys_exit), METH_FASTCALL, sys_exit__doc__}, static PyObject * sys_exit_impl(PyObject *module, PyObject *status); static PyObject * sys_exit(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *status = Py_None; if (!_PyArg_CheckPositional("exit", nargs, 0, 1)) { goto exit; } if (nargs < 1) { goto skip_optional; } status = args[0]; skip_optional: return_value = sys_exit_impl(module, status); exit: return return_value; } PyDoc_STRVAR(sys_getdefaultencoding__doc__, "getdefaultencoding($module, /)\n" "--\n" "\n" "Return the current default encoding used by the Unicode implementation."); #define SYS_GETDEFAULTENCODING_METHODDEF \ {"getdefaultencoding", (PyCFunction)sys_getdefaultencoding, METH_NOARGS, sys_getdefaultencoding__doc__}, static PyObject * sys_getdefaultencoding_impl(PyObject *module); static PyObject * sys_getdefaultencoding(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_getdefaultencoding_impl(module); } PyDoc_STRVAR(sys_getfilesystemencoding__doc__, "getfilesystemencoding($module, /)\n" "--\n" "\n" "Return the encoding used to convert Unicode filenames to OS filenames."); #define SYS_GETFILESYSTEMENCODING_METHODDEF \ {"getfilesystemencoding", (PyCFunction)sys_getfilesystemencoding, METH_NOARGS, sys_getfilesystemencoding__doc__}, static PyObject * sys_getfilesystemencoding_impl(PyObject *module); static PyObject * sys_getfilesystemencoding(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_getfilesystemencoding_impl(module); } PyDoc_STRVAR(sys_getfilesystemencodeerrors__doc__, "getfilesystemencodeerrors($module, /)\n" "--\n" "\n" "Return the error mode used Unicode to OS filename conversion."); #define SYS_GETFILESYSTEMENCODEERRORS_METHODDEF \ {"getfilesystemencodeerrors", (PyCFunction)sys_getfilesystemencodeerrors, METH_NOARGS, sys_getfilesystemencodeerrors__doc__}, static PyObject * sys_getfilesystemencodeerrors_impl(PyObject *module); static PyObject * sys_getfilesystemencodeerrors(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_getfilesystemencodeerrors_impl(module); } PyDoc_STRVAR(sys_intern__doc__, "intern($module, string, /)\n" "--\n" "\n" "``Intern\'\' the given string.\n" "\n" "This enters the string in the (global) table of interned strings whose\n" "purpose is to speed up dictionary lookups. Return the string itself or\n" "the previously interned string object with the same value."); #define SYS_INTERN_METHODDEF \ {"intern", (PyCFunction)sys_intern, METH_O, sys_intern__doc__}, static PyObject * sys_intern_impl(PyObject *module, PyObject *s); static PyObject * sys_intern(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; PyObject *s; if (!PyUnicode_Check(arg)) { _PyArg_BadArgument("intern", "argument", "str", arg); goto exit; } s = arg; return_value = sys_intern_impl(module, s); exit: return return_value; } PyDoc_STRVAR(sys__settraceallthreads__doc__, "_settraceallthreads($module, arg, /)\n" "--\n" "\n" "Set the global debug tracing function in all running threads belonging to the current interpreter.\n" "\n" "It will be called on each function call. See the debugger chapter\n" "in the library manual."); #define SYS__SETTRACEALLTHREADS_METHODDEF \ {"_settraceallthreads", (PyCFunction)sys__settraceallthreads, METH_O, sys__settraceallthreads__doc__}, PyDoc_STRVAR(sys_gettrace__doc__, "gettrace($module, /)\n" "--\n" "\n" "Return the global debug tracing function set with sys.settrace.\n" "\n" "See the debugger chapter in the library manual."); #define SYS_GETTRACE_METHODDEF \ {"gettrace", (PyCFunction)sys_gettrace, METH_NOARGS, sys_gettrace__doc__}, static PyObject * sys_gettrace_impl(PyObject *module); static PyObject * sys_gettrace(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_gettrace_impl(module); } PyDoc_STRVAR(sys__setprofileallthreads__doc__, "_setprofileallthreads($module, arg, /)\n" "--\n" "\n" "Set the profiling function in all running threads belonging to the current interpreter.\n" "\n" "It will be called on each function call and return. See the profiler chapter\n" "in the library manual."); #define SYS__SETPROFILEALLTHREADS_METHODDEF \ {"_setprofileallthreads", (PyCFunction)sys__setprofileallthreads, METH_O, sys__setprofileallthreads__doc__}, PyDoc_STRVAR(sys_getprofile__doc__, "getprofile($module, /)\n" "--\n" "\n" "Return the profiling function set with sys.setprofile.\n" "\n" "See the profiler chapter in the library manual."); #define SYS_GETPROFILE_METHODDEF \ {"getprofile", (PyCFunction)sys_getprofile, METH_NOARGS, sys_getprofile__doc__}, static PyObject * sys_getprofile_impl(PyObject *module); static PyObject * sys_getprofile(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_getprofile_impl(module); } PyDoc_STRVAR(sys_setswitchinterval__doc__, "setswitchinterval($module, interval, /)\n" "--\n" "\n" "Set the ideal thread switching delay inside the Python interpreter.\n" "\n" "The actual frequency of switching threads can be lower if the\n" "interpreter executes long sequences of uninterruptible code\n" "(this is implementation-specific and workload-dependent).\n" "\n" "The parameter must represent the desired switching delay in seconds\n" "A typical value is 0.005 (5 milliseconds)."); #define SYS_SETSWITCHINTERVAL_METHODDEF \ {"setswitchinterval", (PyCFunction)sys_setswitchinterval, METH_O, sys_setswitchinterval__doc__}, static PyObject * sys_setswitchinterval_impl(PyObject *module, double interval); static PyObject * sys_setswitchinterval(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; double interval; if (PyFloat_CheckExact(arg)) { interval = PyFloat_AS_DOUBLE(arg); } else { interval = PyFloat_AsDouble(arg); if (interval == -1.0 && PyErr_Occurred()) { goto exit; } } return_value = sys_setswitchinterval_impl(module, interval); exit: return return_value; } PyDoc_STRVAR(sys_getswitchinterval__doc__, "getswitchinterval($module, /)\n" "--\n" "\n" "Return the current thread switch interval; see sys.setswitchinterval()."); #define SYS_GETSWITCHINTERVAL_METHODDEF \ {"getswitchinterval", (PyCFunction)sys_getswitchinterval, METH_NOARGS, sys_getswitchinterval__doc__}, static double sys_getswitchinterval_impl(PyObject *module); static PyObject * sys_getswitchinterval(PyObject *module, PyObject *Py_UNUSED(ignored)) { PyObject *return_value = NULL; double _return_value; _return_value = sys_getswitchinterval_impl(module); if ((_return_value == -1.0) && PyErr_Occurred()) { goto exit; } return_value = PyFloat_FromDouble(_return_value); exit: return return_value; } PyDoc_STRVAR(sys_setrecursionlimit__doc__, "setrecursionlimit($module, limit, /)\n" "--\n" "\n" "Set the maximum depth of the Python interpreter stack to n.\n" "\n" "This limit prevents infinite recursion from causing an overflow of the C\n" "stack and crashing Python. The highest possible limit is platform-\n" "dependent."); #define SYS_SETRECURSIONLIMIT_METHODDEF \ {"setrecursionlimit", (PyCFunction)sys_setrecursionlimit, METH_O, sys_setrecursionlimit__doc__}, static PyObject * sys_setrecursionlimit_impl(PyObject *module, int new_limit); static PyObject * sys_setrecursionlimit(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; int new_limit; new_limit = _PyLong_AsInt(arg); if (new_limit == -1 && PyErr_Occurred()) { goto exit; } return_value = sys_setrecursionlimit_impl(module, new_limit); exit: return return_value; } PyDoc_STRVAR(sys_set_coroutine_origin_tracking_depth__doc__, "set_coroutine_origin_tracking_depth($module, /, depth)\n" "--\n" "\n" "Enable or disable origin tracking for coroutine objects in this thread.\n" "\n" "Coroutine objects will track \'depth\' frames of traceback information\n" "about where they came from, available in their cr_origin attribute.\n" "\n" "Set a depth of 0 to disable."); #define SYS_SET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF \ {"set_coroutine_origin_tracking_depth", _PyCFunction_CAST(sys_set_coroutine_origin_tracking_depth), METH_FASTCALL|METH_KEYWORDS, sys_set_coroutine_origin_tracking_depth__doc__}, static PyObject * sys_set_coroutine_origin_tracking_depth_impl(PyObject *module, int depth); static PyObject * sys_set_coroutine_origin_tracking_depth(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 1 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(depth), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"depth", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "set_coroutine_origin_tracking_depth", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[1]; int depth; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); if (!args) { goto exit; } depth = _PyLong_AsInt(args[0]); if (depth == -1 && PyErr_Occurred()) { goto exit; } return_value = sys_set_coroutine_origin_tracking_depth_impl(module, depth); exit: return return_value; } PyDoc_STRVAR(sys_get_coroutine_origin_tracking_depth__doc__, "get_coroutine_origin_tracking_depth($module, /)\n" "--\n" "\n" "Check status of origin tracking for coroutine objects in this thread."); #define SYS_GET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF \ {"get_coroutine_origin_tracking_depth", (PyCFunction)sys_get_coroutine_origin_tracking_depth, METH_NOARGS, sys_get_coroutine_origin_tracking_depth__doc__}, static int sys_get_coroutine_origin_tracking_depth_impl(PyObject *module); static PyObject * sys_get_coroutine_origin_tracking_depth(PyObject *module, PyObject *Py_UNUSED(ignored)) { PyObject *return_value = NULL; int _return_value; _return_value = sys_get_coroutine_origin_tracking_depth_impl(module); if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } return_value = PyLong_FromLong((long)_return_value); exit: return return_value; } PyDoc_STRVAR(sys_get_asyncgen_hooks__doc__, "get_asyncgen_hooks($module, /)\n" "--\n" "\n" "Return the installed asynchronous generators hooks.\n" "\n" "This returns a namedtuple of the form (firstiter, finalizer)."); #define SYS_GET_ASYNCGEN_HOOKS_METHODDEF \ {"get_asyncgen_hooks", (PyCFunction)sys_get_asyncgen_hooks, METH_NOARGS, sys_get_asyncgen_hooks__doc__}, static PyObject * sys_get_asyncgen_hooks_impl(PyObject *module); static PyObject * sys_get_asyncgen_hooks(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_get_asyncgen_hooks_impl(module); } PyDoc_STRVAR(sys_getrecursionlimit__doc__, "getrecursionlimit($module, /)\n" "--\n" "\n" "Return the current value of the recursion limit.\n" "\n" "The recursion limit is the maximum depth of the Python interpreter\n" "stack. This limit prevents infinite recursion from causing an overflow\n" "of the C stack and crashing Python."); #define SYS_GETRECURSIONLIMIT_METHODDEF \ {"getrecursionlimit", (PyCFunction)sys_getrecursionlimit, METH_NOARGS, sys_getrecursionlimit__doc__}, static PyObject * sys_getrecursionlimit_impl(PyObject *module); static PyObject * sys_getrecursionlimit(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_getrecursionlimit_impl(module); } #if defined(MS_WINDOWS) PyDoc_STRVAR(sys_getwindowsversion__doc__, "getwindowsversion($module, /)\n" "--\n" "\n" "Return info about the running version of Windows as a named tuple.\n" "\n" "The members are named: major, minor, build, platform, service_pack,\n" "service_pack_major, service_pack_minor, suite_mask, product_type and\n" "platform_version. For backward compatibility, only the first 5 items\n" "are available by indexing. All elements are numbers, except\n" "service_pack and platform_type which are strings, and platform_version\n" "which is a 3-tuple. Platform is always 2. Product_type may be 1 for a\n" "workstation, 2 for a domain controller, 3 for a server.\n" "Platform_version is a 3-tuple containing a version number that is\n" "intended for identifying the OS rather than feature detection."); #define SYS_GETWINDOWSVERSION_METHODDEF \ {"getwindowsversion", (PyCFunction)sys_getwindowsversion, METH_NOARGS, sys_getwindowsversion__doc__}, static PyObject * sys_getwindowsversion_impl(PyObject *module); static PyObject * sys_getwindowsversion(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_getwindowsversion_impl(module); } #endif /* defined(MS_WINDOWS) */ #if defined(MS_WINDOWS) PyDoc_STRVAR(sys__enablelegacywindowsfsencoding__doc__, "_enablelegacywindowsfsencoding($module, /)\n" "--\n" "\n" "Changes the default filesystem encoding to mbcs:replace.\n" "\n" "This is done for consistency with earlier versions of Python. See PEP\n" "529 for more information.\n" "\n" "This is equivalent to defining the PYTHONLEGACYWINDOWSFSENCODING\n" "environment variable before launching Python."); #define SYS__ENABLELEGACYWINDOWSFSENCODING_METHODDEF \ {"_enablelegacywindowsfsencoding", (PyCFunction)sys__enablelegacywindowsfsencoding, METH_NOARGS, sys__enablelegacywindowsfsencoding__doc__}, static PyObject * sys__enablelegacywindowsfsencoding_impl(PyObject *module); static PyObject * sys__enablelegacywindowsfsencoding(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys__enablelegacywindowsfsencoding_impl(module); } #endif /* defined(MS_WINDOWS) */ #if defined(HAVE_DLOPEN) PyDoc_STRVAR(sys_setdlopenflags__doc__, "setdlopenflags($module, flags, /)\n" "--\n" "\n" "Set the flags used by the interpreter for dlopen calls.\n" "\n" "This is used, for example, when the interpreter loads extension\n" "modules. Among other things, this will enable a lazy resolving of\n" "symbols when importing a module, if called as sys.setdlopenflags(0).\n" "To share symbols across extension modules, call as\n" "sys.setdlopenflags(os.RTLD_GLOBAL). Symbolic names for the flag\n" "modules can be found in the os module (RTLD_xxx constants, e.g.\n" "os.RTLD_LAZY)."); #define SYS_SETDLOPENFLAGS_METHODDEF \ {"setdlopenflags", (PyCFunction)sys_setdlopenflags, METH_O, sys_setdlopenflags__doc__}, static PyObject * sys_setdlopenflags_impl(PyObject *module, int new_val); static PyObject * sys_setdlopenflags(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; int new_val; new_val = _PyLong_AsInt(arg); if (new_val == -1 && PyErr_Occurred()) { goto exit; } return_value = sys_setdlopenflags_impl(module, new_val); exit: return return_value; } #endif /* defined(HAVE_DLOPEN) */ #if defined(HAVE_DLOPEN) PyDoc_STRVAR(sys_getdlopenflags__doc__, "getdlopenflags($module, /)\n" "--\n" "\n" "Return the current value of the flags that are used for dlopen calls.\n" "\n" "The flag constants are defined in the os module."); #define SYS_GETDLOPENFLAGS_METHODDEF \ {"getdlopenflags", (PyCFunction)sys_getdlopenflags, METH_NOARGS, sys_getdlopenflags__doc__}, static PyObject * sys_getdlopenflags_impl(PyObject *module); static PyObject * sys_getdlopenflags(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_getdlopenflags_impl(module); } #endif /* defined(HAVE_DLOPEN) */ #if defined(USE_MALLOPT) PyDoc_STRVAR(sys_mdebug__doc__, "mdebug($module, flag, /)\n" "--\n" "\n"); #define SYS_MDEBUG_METHODDEF \ {"mdebug", (PyCFunction)sys_mdebug, METH_O, sys_mdebug__doc__}, static PyObject * sys_mdebug_impl(PyObject *module, int flag); static PyObject * sys_mdebug(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; int flag; flag = _PyLong_AsInt(arg); if (flag == -1 && PyErr_Occurred()) { goto exit; } return_value = sys_mdebug_impl(module, flag); exit: return return_value; } #endif /* defined(USE_MALLOPT) */ PyDoc_STRVAR(sys_get_int_max_str_digits__doc__, "get_int_max_str_digits($module, /)\n" "--\n" "\n" "Return the maximum string digits limit for non-binary int<->str conversions."); #define SYS_GET_INT_MAX_STR_DIGITS_METHODDEF \ {"get_int_max_str_digits", (PyCFunction)sys_get_int_max_str_digits, METH_NOARGS, sys_get_int_max_str_digits__doc__}, static PyObject * sys_get_int_max_str_digits_impl(PyObject *module); static PyObject * sys_get_int_max_str_digits(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_get_int_max_str_digits_impl(module); } PyDoc_STRVAR(sys_set_int_max_str_digits__doc__, "set_int_max_str_digits($module, /, maxdigits)\n" "--\n" "\n" "Set the maximum string digits limit for non-binary int<->str conversions."); #define SYS_SET_INT_MAX_STR_DIGITS_METHODDEF \ {"set_int_max_str_digits", _PyCFunction_CAST(sys_set_int_max_str_digits), METH_FASTCALL|METH_KEYWORDS, sys_set_int_max_str_digits__doc__}, static PyObject * sys_set_int_max_str_digits_impl(PyObject *module, int maxdigits); static PyObject * sys_set_int_max_str_digits(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 1 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(maxdigits), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"maxdigits", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "set_int_max_str_digits", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[1]; int maxdigits; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); if (!args) { goto exit; } maxdigits = _PyLong_AsInt(args[0]); if (maxdigits == -1 && PyErr_Occurred()) { goto exit; } return_value = sys_set_int_max_str_digits_impl(module, maxdigits); exit: return return_value; } PyDoc_STRVAR(sys_getrefcount__doc__, "getrefcount($module, object, /)\n" "--\n" "\n" "Return the reference count of object.\n" "\n" "The count returned is generally one higher than you might expect,\n" "because it includes the (temporary) reference as an argument to\n" "getrefcount()."); #define SYS_GETREFCOUNT_METHODDEF \ {"getrefcount", (PyCFunction)sys_getrefcount, METH_O, sys_getrefcount__doc__}, static Py_ssize_t sys_getrefcount_impl(PyObject *module, PyObject *object); static PyObject * sys_getrefcount(PyObject *module, PyObject *object) { PyObject *return_value = NULL; Py_ssize_t _return_value; _return_value = sys_getrefcount_impl(module, object); if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } return_value = PyLong_FromSsize_t(_return_value); exit: return return_value; } #if defined(Py_REF_DEBUG) PyDoc_STRVAR(sys_gettotalrefcount__doc__, "gettotalrefcount($module, /)\n" "--\n" "\n"); #define SYS_GETTOTALREFCOUNT_METHODDEF \ {"gettotalrefcount", (PyCFunction)sys_gettotalrefcount, METH_NOARGS, sys_gettotalrefcount__doc__}, static Py_ssize_t sys_gettotalrefcount_impl(PyObject *module); static PyObject * sys_gettotalrefcount(PyObject *module, PyObject *Py_UNUSED(ignored)) { PyObject *return_value = NULL; Py_ssize_t _return_value; _return_value = sys_gettotalrefcount_impl(module); if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } return_value = PyLong_FromSsize_t(_return_value); exit: return return_value; } #endif /* defined(Py_REF_DEBUG) */ PyDoc_STRVAR(sys_getallocatedblocks__doc__, "getallocatedblocks($module, /)\n" "--\n" "\n" "Return the number of memory blocks currently allocated."); #define SYS_GETALLOCATEDBLOCKS_METHODDEF \ {"getallocatedblocks", (PyCFunction)sys_getallocatedblocks, METH_NOARGS, sys_getallocatedblocks__doc__}, static Py_ssize_t sys_getallocatedblocks_impl(PyObject *module); static PyObject * sys_getallocatedblocks(PyObject *module, PyObject *Py_UNUSED(ignored)) { PyObject *return_value = NULL; Py_ssize_t _return_value; _return_value = sys_getallocatedblocks_impl(module); if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } return_value = PyLong_FromSsize_t(_return_value); exit: return return_value; } PyDoc_STRVAR(sys_getunicodeinternedsize__doc__, "getunicodeinternedsize($module, /)\n" "--\n" "\n" "Return the number of elements of the unicode interned dictionary"); #define SYS_GETUNICODEINTERNEDSIZE_METHODDEF \ {"getunicodeinternedsize", (PyCFunction)sys_getunicodeinternedsize, METH_NOARGS, sys_getunicodeinternedsize__doc__}, static Py_ssize_t sys_getunicodeinternedsize_impl(PyObject *module); static PyObject * sys_getunicodeinternedsize(PyObject *module, PyObject *Py_UNUSED(ignored)) { PyObject *return_value = NULL; Py_ssize_t _return_value; _return_value = sys_getunicodeinternedsize_impl(module); if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } return_value = PyLong_FromSsize_t(_return_value); exit: return return_value; } PyDoc_STRVAR(sys__getframe__doc__, "_getframe($module, depth=0, /)\n" "--\n" "\n" "Return a frame object from the call stack.\n" "\n" "If optional integer depth is given, return the frame object that many\n" "calls below the top of the stack. If that is deeper than the call\n" "stack, ValueError is raised. The default for depth is zero, returning\n" "the frame at the top of the call stack.\n" "\n" "This function should be used for internal and specialized purposes\n" "only."); #define SYS__GETFRAME_METHODDEF \ {"_getframe", _PyCFunction_CAST(sys__getframe), METH_FASTCALL, sys__getframe__doc__}, static PyObject * sys__getframe_impl(PyObject *module, int depth); static PyObject * sys__getframe(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int depth = 0; if (!_PyArg_CheckPositional("_getframe", nargs, 0, 1)) { goto exit; } if (nargs < 1) { goto skip_optional; } depth = _PyLong_AsInt(args[0]); if (depth == -1 && PyErr_Occurred()) { goto exit; } skip_optional: return_value = sys__getframe_impl(module, depth); exit: return return_value; } PyDoc_STRVAR(sys__current_frames__doc__, "_current_frames($module, /)\n" "--\n" "\n" "Return a dict mapping each thread\'s thread id to its current stack frame.\n" "\n" "This function should be used for specialized purposes only."); #define SYS__CURRENT_FRAMES_METHODDEF \ {"_current_frames", (PyCFunction)sys__current_frames, METH_NOARGS, sys__current_frames__doc__}, static PyObject * sys__current_frames_impl(PyObject *module); static PyObject * sys__current_frames(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys__current_frames_impl(module); } PyDoc_STRVAR(sys__current_exceptions__doc__, "_current_exceptions($module, /)\n" "--\n" "\n" "Return a dict mapping each thread\'s identifier to its current raised exception.\n" "\n" "This function should be used for specialized purposes only."); #define SYS__CURRENT_EXCEPTIONS_METHODDEF \ {"_current_exceptions", (PyCFunction)sys__current_exceptions, METH_NOARGS, sys__current_exceptions__doc__}, static PyObject * sys__current_exceptions_impl(PyObject *module); static PyObject * sys__current_exceptions(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys__current_exceptions_impl(module); } PyDoc_STRVAR(sys_call_tracing__doc__, "call_tracing($module, func, args, /)\n" "--\n" "\n" "Call func(*args), while tracing is enabled.\n" "\n" "The tracing state is saved, and restored afterwards. This is intended\n" "to be called from a debugger from a checkpoint, to recursively debug\n" "some other code."); #define SYS_CALL_TRACING_METHODDEF \ {"call_tracing", _PyCFunction_CAST(sys_call_tracing), METH_FASTCALL, sys_call_tracing__doc__}, static PyObject * sys_call_tracing_impl(PyObject *module, PyObject *func, PyObject *funcargs); static PyObject * sys_call_tracing(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; PyObject *func; PyObject *funcargs; if (!_PyArg_CheckPositional("call_tracing", nargs, 2, 2)) { goto exit; } func = args[0]; if (!PyTuple_Check(args[1])) { _PyArg_BadArgument("call_tracing", "argument 2", "tuple", args[1]); goto exit; } funcargs = args[1]; return_value = sys_call_tracing_impl(module, func, funcargs); exit: return return_value; } PyDoc_STRVAR(sys__debugmallocstats__doc__, "_debugmallocstats($module, /)\n" "--\n" "\n" "Print summary info to stderr about the state of pymalloc\'s structures.\n" "\n" "In Py_DEBUG mode, also perform some expensive internal consistency\n" "checks."); #define SYS__DEBUGMALLOCSTATS_METHODDEF \ {"_debugmallocstats", (PyCFunction)sys__debugmallocstats, METH_NOARGS, sys__debugmallocstats__doc__}, static PyObject * sys__debugmallocstats_impl(PyObject *module); static PyObject * sys__debugmallocstats(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys__debugmallocstats_impl(module); } PyDoc_STRVAR(sys__clear_type_cache__doc__, "_clear_type_cache($module, /)\n" "--\n" "\n" "Clear the internal type lookup cache."); #define SYS__CLEAR_TYPE_CACHE_METHODDEF \ {"_clear_type_cache", (PyCFunction)sys__clear_type_cache, METH_NOARGS, sys__clear_type_cache__doc__}, static PyObject * sys__clear_type_cache_impl(PyObject *module); static PyObject * sys__clear_type_cache(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys__clear_type_cache_impl(module); } PyDoc_STRVAR(sys_is_finalizing__doc__, "is_finalizing($module, /)\n" "--\n" "\n" "Return True if Python is exiting."); #define SYS_IS_FINALIZING_METHODDEF \ {"is_finalizing", (PyCFunction)sys_is_finalizing, METH_NOARGS, sys_is_finalizing__doc__}, static PyObject * sys_is_finalizing_impl(PyObject *module); static PyObject * sys_is_finalizing(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_is_finalizing_impl(module); } #if defined(Py_STATS) PyDoc_STRVAR(sys__stats_on__doc__, "_stats_on($module, /)\n" "--\n" "\n" "Turns on stats gathering (stats gathering is on by default)."); #define SYS__STATS_ON_METHODDEF \ {"_stats_on", (PyCFunction)sys__stats_on, METH_NOARGS, sys__stats_on__doc__}, static PyObject * sys__stats_on_impl(PyObject *module); static PyObject * sys__stats_on(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys__stats_on_impl(module); } #endif /* defined(Py_STATS) */ #if defined(Py_STATS) PyDoc_STRVAR(sys__stats_off__doc__, "_stats_off($module, /)\n" "--\n" "\n" "Turns off stats gathering (stats gathering is on by default)."); #define SYS__STATS_OFF_METHODDEF \ {"_stats_off", (PyCFunction)sys__stats_off, METH_NOARGS, sys__stats_off__doc__}, static PyObject * sys__stats_off_impl(PyObject *module); static PyObject * sys__stats_off(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys__stats_off_impl(module); } #endif /* defined(Py_STATS) */ #if defined(Py_STATS) PyDoc_STRVAR(sys__stats_clear__doc__, "_stats_clear($module, /)\n" "--\n" "\n" "Clears the stats."); #define SYS__STATS_CLEAR_METHODDEF \ {"_stats_clear", (PyCFunction)sys__stats_clear, METH_NOARGS, sys__stats_clear__doc__}, static PyObject * sys__stats_clear_impl(PyObject *module); static PyObject * sys__stats_clear(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys__stats_clear_impl(module); } #endif /* defined(Py_STATS) */ #if defined(Py_STATS) PyDoc_STRVAR(sys__stats_dump__doc__, "_stats_dump($module, /)\n" "--\n" "\n" "Dump stats to file, and clears the stats."); #define SYS__STATS_DUMP_METHODDEF \ {"_stats_dump", (PyCFunction)sys__stats_dump, METH_NOARGS, sys__stats_dump__doc__}, static PyObject * sys__stats_dump_impl(PyObject *module); static PyObject * sys__stats_dump(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys__stats_dump_impl(module); } #endif /* defined(Py_STATS) */ #if defined(ANDROID_API_LEVEL) PyDoc_STRVAR(sys_getandroidapilevel__doc__, "getandroidapilevel($module, /)\n" "--\n" "\n" "Return the build time API version of Android as an integer."); #define SYS_GETANDROIDAPILEVEL_METHODDEF \ {"getandroidapilevel", (PyCFunction)sys_getandroidapilevel, METH_NOARGS, sys_getandroidapilevel__doc__}, static PyObject * sys_getandroidapilevel_impl(PyObject *module); static PyObject * sys_getandroidapilevel(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_getandroidapilevel_impl(module); } #endif /* defined(ANDROID_API_LEVEL) */ PyDoc_STRVAR(sys_activate_stack_trampoline__doc__, "activate_stack_trampoline($module, backend, /)\n" "--\n" "\n" "Activate stack profiler trampoline *backend*."); #define SYS_ACTIVATE_STACK_TRAMPOLINE_METHODDEF \ {"activate_stack_trampoline", (PyCFunction)sys_activate_stack_trampoline, METH_O, sys_activate_stack_trampoline__doc__}, static PyObject * sys_activate_stack_trampoline_impl(PyObject *module, const char *backend); static PyObject * sys_activate_stack_trampoline(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; const char *backend; if (!PyUnicode_Check(arg)) { _PyArg_BadArgument("activate_stack_trampoline", "argument", "str", arg); goto exit; } Py_ssize_t backend_length; backend = PyUnicode_AsUTF8AndSize(arg, &backend_length); if (backend == NULL) { goto exit; } if (strlen(backend) != (size_t)backend_length) { PyErr_SetString(PyExc_ValueError, "embedded null character"); goto exit; } return_value = sys_activate_stack_trampoline_impl(module, backend); exit: return return_value; } PyDoc_STRVAR(sys_deactivate_stack_trampoline__doc__, "deactivate_stack_trampoline($module, /)\n" "--\n" "\n" "Deactivate the current stack profiler trampoline backend.\n" "\n" "If no stack profiler is activated, this function has no effect."); #define SYS_DEACTIVATE_STACK_TRAMPOLINE_METHODDEF \ {"deactivate_stack_trampoline", (PyCFunction)sys_deactivate_stack_trampoline, METH_NOARGS, sys_deactivate_stack_trampoline__doc__}, static PyObject * sys_deactivate_stack_trampoline_impl(PyObject *module); static PyObject * sys_deactivate_stack_trampoline(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_deactivate_stack_trampoline_impl(module); } PyDoc_STRVAR(sys_is_stack_trampoline_active__doc__, "is_stack_trampoline_active($module, /)\n" "--\n" "\n" "Return *True* if a stack profiler trampoline is active."); #define SYS_IS_STACK_TRAMPOLINE_ACTIVE_METHODDEF \ {"is_stack_trampoline_active", (PyCFunction)sys_is_stack_trampoline_active, METH_NOARGS, sys_is_stack_trampoline_active__doc__}, static PyObject * sys_is_stack_trampoline_active_impl(PyObject *module); static PyObject * sys_is_stack_trampoline_active(PyObject *module, PyObject *Py_UNUSED(ignored)) { return sys_is_stack_trampoline_active_impl(module); } PyDoc_STRVAR(sys__getframemodulename__doc__, "_getframemodulename($module, /, depth=0)\n" "--\n" "\n" "Return the name of the module for a calling frame.\n" "\n" "The default depth returns the module containing the call to this API.\n" "A more typical use in a library will pass a depth of 1 to get the user\'s\n" "module rather than the library module.\n" "\n" "If no frame, module, or name can be found, returns None."); #define SYS__GETFRAMEMODULENAME_METHODDEF \ {"_getframemodulename", _PyCFunction_CAST(sys__getframemodulename), METH_FASTCALL|METH_KEYWORDS, sys__getframemodulename__doc__}, static PyObject * sys__getframemodulename_impl(PyObject *module, int depth); static PyObject * sys__getframemodulename(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 1 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(depth), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"depth", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "_getframemodulename", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[1]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; int depth = 0; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); if (!args) { goto exit; } if (!noptargs) { goto skip_optional_pos; } depth = _PyLong_AsInt(args[0]); if (depth == -1 && PyErr_Occurred()) { goto exit; } skip_optional_pos: return_value = sys__getframemodulename_impl(module, depth); exit: return return_value; } #ifndef SYS_GETWINDOWSVERSION_METHODDEF #define SYS_GETWINDOWSVERSION_METHODDEF #endif /* !defined(SYS_GETWINDOWSVERSION_METHODDEF) */ #ifndef SYS__ENABLELEGACYWINDOWSFSENCODING_METHODDEF #define SYS__ENABLELEGACYWINDOWSFSENCODING_METHODDEF #endif /* !defined(SYS__ENABLELEGACYWINDOWSFSENCODING_METHODDEF) */ #ifndef SYS_SETDLOPENFLAGS_METHODDEF #define SYS_SETDLOPENFLAGS_METHODDEF #endif /* !defined(SYS_SETDLOPENFLAGS_METHODDEF) */ #ifndef SYS_GETDLOPENFLAGS_METHODDEF #define SYS_GETDLOPENFLAGS_METHODDEF #endif /* !defined(SYS_GETDLOPENFLAGS_METHODDEF) */ #ifndef SYS_MDEBUG_METHODDEF #define SYS_MDEBUG_METHODDEF #endif /* !defined(SYS_MDEBUG_METHODDEF) */ #ifndef SYS_GETTOTALREFCOUNT_METHODDEF #define SYS_GETTOTALREFCOUNT_METHODDEF #endif /* !defined(SYS_GETTOTALREFCOUNT_METHODDEF) */ #ifndef SYS__STATS_ON_METHODDEF #define SYS__STATS_ON_METHODDEF #endif /* !defined(SYS__STATS_ON_METHODDEF) */ #ifndef SYS__STATS_OFF_METHODDEF #define SYS__STATS_OFF_METHODDEF #endif /* !defined(SYS__STATS_OFF_METHODDEF) */ #ifndef SYS__STATS_CLEAR_METHODDEF #define SYS__STATS_CLEAR_METHODDEF #endif /* !defined(SYS__STATS_CLEAR_METHODDEF) */ #ifndef SYS__STATS_DUMP_METHODDEF #define SYS__STATS_DUMP_METHODDEF #endif /* !defined(SYS__STATS_DUMP_METHODDEF) */ #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ /*[clinic end generated code: output=41937e0843c68009 input=a9049054013a1b77]*/ ================================================ FILE: Clinic/traceback.c.h ================================================ /*[clinic input] preserve [clinic start generated code]*/ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif PyDoc_STRVAR(tb_new__doc__, "TracebackType(tb_next, tb_frame, tb_lasti, tb_lineno)\n" "--\n" "\n" "Create a new traceback object."); static PyObject * tb_new_impl(PyTypeObject *type, PyObject *tb_next, PyFrameObject *tb_frame, int tb_lasti, int tb_lineno); static PyObject * tb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) #define NUM_KEYWORDS 4 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_item = { &_Py_ID(tb_next), &_Py_ID(tb_frame), &_Py_ID(tb_lasti), &_Py_ID(tb_lineno), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) #else // !Py_BUILD_CORE # define KWTUPLE NULL #endif // !Py_BUILD_CORE static const char * const _keywords[] = {"tb_next", "tb_frame", "tb_lasti", "tb_lineno", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "TracebackType", .kwtuple = KWTUPLE, }; #undef KWTUPLE PyObject *argsbuf[4]; PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); PyObject *tb_next; PyFrameObject *tb_frame; int tb_lasti; int tb_lineno; fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 4, 4, 0, argsbuf); if (!fastargs) { goto exit; } tb_next = fastargs[0]; if (!PyObject_TypeCheck(fastargs[1], &PyFrame_Type)) { _PyArg_BadArgument("TracebackType", "argument 'tb_frame'", (&PyFrame_Type)->tp_name, fastargs[1]); goto exit; } tb_frame = (PyFrameObject *)fastargs[1]; tb_lasti = _PyLong_AsInt(fastargs[2]); if (tb_lasti == -1 && PyErr_Occurred()) { goto exit; } tb_lineno = _PyLong_AsInt(fastargs[3]); if (tb_lineno == -1 && PyErr_Occurred()) { goto exit; } return_value = tb_new_impl(type, tb_next, tb_frame, tb_lasti, tb_lineno); exit: return return_value; } /*[clinic end generated code: output=7bc9927e362fdfb7 input=a9049054013a1b77]*/ ================================================ FILE: CodeCS.c ================================================ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_interp.h" // PyInterpreterState.codec_search_path #include "pycore_pyerrors.h" // _PyErr_FormatNote() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI #include const char *Py_hexdigits = "0123456789abcdef"; /* --- Codec Registry ----------------------------------------------------- */ /* Import the standard encodings package which will register the first codec search function. This is done in a lazy way so that the Unicode implementation does not downgrade startup time of scripts not needing it. ImportErrors are silently ignored by this function. Only one try is made. */ static int _PyCodecRegistry_Init(void); /* Forward */ int PyCodec_Register(PyObject *search_function) { PyInterpreterState *interp = _PyInterpreterState_GET(); if (interp->codec_search_path == NULL && _PyCodecRegistry_Init()) goto onError; if (search_function == NULL) { PyErr_BadArgument(); goto onError; } if (!PyCallable_Check(search_function)) { PyErr_SetString(PyExc_TypeError, "argument must be callable"); goto onError; } return PyList_Append(interp->codec_search_path, search_function); onError: return -1; } int PyCodec_Unregister(PyObject *search_function) { PyInterpreterState *interp = PyInterpreterState_Get(); PyObject *codec_search_path = interp->codec_search_path; /* Do nothing if codec_search_path is not created yet or was cleared. */ if (codec_search_path == NULL) { return 0; } assert(PyList_CheckExact(codec_search_path)); Py_ssize_t n = PyList_GET_SIZE(codec_search_path); for (Py_ssize_t i = 0; i < n; i++) { PyObject *item = PyList_GET_ITEM(codec_search_path, i); if (item == search_function) { if (interp->codec_search_cache != NULL) { assert(PyDict_CheckExact(interp->codec_search_cache)); PyDict_Clear(interp->codec_search_cache); } return PyList_SetSlice(codec_search_path, i, i+1, NULL); } } return 0; } extern int _Py_normalize_encoding(const char *, char *, size_t); /* Convert a string to a normalized Python string(decoded from UTF-8): all characters are converted to lower case, spaces and hyphens are replaced with underscores. */ static PyObject *normalizestring(const char *string) { size_t len = strlen(string); char *encoding; PyObject *v; if (len > PY_SSIZE_T_MAX) { PyErr_SetString(PyExc_OverflowError, "string is too large"); return NULL; } encoding = PyMem_Malloc(len + 1); if (encoding == NULL) return PyErr_NoMemory(); if (!_Py_normalize_encoding(string, encoding, len + 1)) { PyErr_SetString(PyExc_RuntimeError, "_Py_normalize_encoding() failed"); PyMem_Free(encoding); return NULL; } v = PyUnicode_FromString(encoding); PyMem_Free(encoding); return v; } /* Lookup the given encoding and return a tuple providing the codec facilities. The encoding string is looked up converted to all lower-case characters. This makes encodings looked up through this mechanism effectively case-insensitive. If no codec is found, a LookupError is set and NULL returned. As side effect, this tries to load the encodings package, if not yet done. This is part of the lazy load strategy for the encodings package. */ PyObject *_PyCodec_Lookup(const char *encoding) { if (encoding == NULL) { PyErr_BadArgument(); return NULL; } PyInterpreterState *interp = _PyInterpreterState_GET(); if (interp->codec_search_path == NULL && _PyCodecRegistry_Init()) { return NULL; } /* Convert the encoding to a normalized Python string: all characters are converted to lower case, spaces and hyphens are replaced with underscores. */ PyObject *v = normalizestring(encoding); if (v == NULL) { return NULL; } PyUnicode_InternInPlace(&v); /* First, try to lookup the name in the registry dictionary */ PyObject *result = PyDict_GetItemWithError(interp->codec_search_cache, v); if (result != NULL) { Py_INCREF(result); Py_DECREF(v); return result; } else if (PyErr_Occurred()) { goto onError; } /* Next, scan the search functions in order of registration */ const Py_ssize_t len = PyList_Size(interp->codec_search_path); if (len < 0) goto onError; if (len == 0) { PyErr_SetString(PyExc_LookupError, "no codec search functions registered: " "can't find encoding"); goto onError; } Py_ssize_t i; for (i = 0; i < len; i++) { PyObject *func; func = PyList_GetItem(interp->codec_search_path, i); if (func == NULL) goto onError; result = PyObject_CallOneArg(func, v); if (result == NULL) goto onError; if (result == Py_None) { Py_DECREF(result); continue; } if (!PyTuple_Check(result) || PyTuple_GET_SIZE(result) != 4) { PyErr_SetString(PyExc_TypeError, "codec search functions must return 4-tuples"); Py_DECREF(result); goto onError; } break; } if (i == len) { /* XXX Perhaps we should cache misses too ? */ PyErr_Format(PyExc_LookupError, "unknown encoding: %s", encoding); goto onError; } /* Cache and return the result */ if (PyDict_SetItem(interp->codec_search_cache, v, result) < 0) { Py_DECREF(result); goto onError; } Py_DECREF(v); return result; onError: Py_DECREF(v); return NULL; } /* Codec registry encoding check API. */ int PyCodec_KnownEncoding(const char *encoding) { PyObject *codecs; codecs = _PyCodec_Lookup(encoding); if (!codecs) { PyErr_Clear(); return 0; } else { Py_DECREF(codecs); return 1; } } static PyObject *args_tuple(PyObject *object, const char *errors) { PyObject *args; args = PyTuple_New(1 + (errors != NULL)); if (args == NULL) return NULL; PyTuple_SET_ITEM(args, 0, Py_NewRef(object)); if (errors) { PyObject *v; v = PyUnicode_FromString(errors); if (v == NULL) { Py_DECREF(args); return NULL; } PyTuple_SET_ITEM(args, 1, v); } return args; } /* Helper function to get a codec item */ static PyObject *codec_getitem(const char *encoding, int index) { PyObject *codecs; PyObject *v; codecs = _PyCodec_Lookup(encoding); if (codecs == NULL) return NULL; v = PyTuple_GET_ITEM(codecs, index); Py_DECREF(codecs); return Py_NewRef(v); } /* Helper functions to create an incremental codec. */ static PyObject *codec_makeincrementalcodec(PyObject *codec_info, const char *errors, const char *attrname) { PyObject *ret, *inccodec; inccodec = PyObject_GetAttrString(codec_info, attrname); if (inccodec == NULL) return NULL; if (errors) ret = PyObject_CallFunction(inccodec, "s", errors); else ret = _PyObject_CallNoArgs(inccodec); Py_DECREF(inccodec); return ret; } static PyObject *codec_getincrementalcodec(const char *encoding, const char *errors, const char *attrname) { PyObject *codec_info, *ret; codec_info = _PyCodec_Lookup(encoding); if (codec_info == NULL) return NULL; ret = codec_makeincrementalcodec(codec_info, errors, attrname); Py_DECREF(codec_info); return ret; } /* Helper function to create a stream codec. */ static PyObject *codec_getstreamcodec(const char *encoding, PyObject *stream, const char *errors, const int index) { PyObject *codecs, *streamcodec, *codeccls; codecs = _PyCodec_Lookup(encoding); if (codecs == NULL) return NULL; codeccls = PyTuple_GET_ITEM(codecs, index); if (errors != NULL) streamcodec = PyObject_CallFunction(codeccls, "Os", stream, errors); else streamcodec = PyObject_CallOneArg(codeccls, stream); Py_DECREF(codecs); return streamcodec; } /* Helpers to work with the result of _PyCodec_Lookup */ PyObject *_PyCodecInfo_GetIncrementalDecoder(PyObject *codec_info, const char *errors) { return codec_makeincrementalcodec(codec_info, errors, "incrementaldecoder"); } PyObject *_PyCodecInfo_GetIncrementalEncoder(PyObject *codec_info, const char *errors) { return codec_makeincrementalcodec(codec_info, errors, "incrementalencoder"); } /* Convenience APIs to query the Codec registry. All APIs return a codec object with incremented refcount. */ PyObject *PyCodec_Encoder(const char *encoding) { return codec_getitem(encoding, 0); } PyObject *PyCodec_Decoder(const char *encoding) { return codec_getitem(encoding, 1); } PyObject *PyCodec_IncrementalEncoder(const char *encoding, const char *errors) { return codec_getincrementalcodec(encoding, errors, "incrementalencoder"); } PyObject *PyCodec_IncrementalDecoder(const char *encoding, const char *errors) { return codec_getincrementalcodec(encoding, errors, "incrementaldecoder"); } PyObject *PyCodec_StreamReader(const char *encoding, PyObject *stream, const char *errors) { return codec_getstreamcodec(encoding, stream, errors, 2); } PyObject *PyCodec_StreamWriter(const char *encoding, PyObject *stream, const char *errors) { return codec_getstreamcodec(encoding, stream, errors, 3); } /* Encode an object (e.g. a Unicode object) using the given encoding and return the resulting encoded object (usually a Python string). errors is passed to the encoder factory as argument if non-NULL. */ static PyObject * _PyCodec_EncodeInternal(PyObject *object, PyObject *encoder, const char *encoding, const char *errors) { PyObject *args = NULL, *result = NULL; PyObject *v = NULL; args = args_tuple(object, errors); if (args == NULL) goto onError; result = PyObject_Call(encoder, args, NULL); if (result == NULL) { _PyErr_FormatNote("%s with '%s' codec failed", "encoding", encoding); goto onError; } if (!PyTuple_Check(result) || PyTuple_GET_SIZE(result) != 2) { PyErr_SetString(PyExc_TypeError, "encoder must return a tuple (object, integer)"); goto onError; } v = Py_NewRef(PyTuple_GET_ITEM(result,0)); /* We don't check or use the second (integer) entry. */ Py_DECREF(args); Py_DECREF(encoder); Py_DECREF(result); return v; onError: Py_XDECREF(result); Py_XDECREF(args); Py_XDECREF(encoder); return NULL; } /* Decode an object (usually a Python string) using the given encoding and return an equivalent object (e.g. a Unicode object). errors is passed to the decoder factory as argument if non-NULL. */ static PyObject * _PyCodec_DecodeInternal(PyObject *object, PyObject *decoder, const char *encoding, const char *errors) { PyObject *args = NULL, *result = NULL; PyObject *v; args = args_tuple(object, errors); if (args == NULL) goto onError; result = PyObject_Call(decoder, args, NULL); if (result == NULL) { _PyErr_FormatNote("%s with '%s' codec failed", "decoding", encoding); goto onError; } if (!PyTuple_Check(result) || PyTuple_GET_SIZE(result) != 2) { PyErr_SetString(PyExc_TypeError, "decoder must return a tuple (object,integer)"); goto onError; } v = Py_NewRef(PyTuple_GET_ITEM(result,0)); /* We don't check or use the second (integer) entry. */ Py_DECREF(args); Py_DECREF(decoder); Py_DECREF(result); return v; onError: Py_XDECREF(args); Py_XDECREF(decoder); Py_XDECREF(result); return NULL; } /* Generic encoding/decoding API */ PyObject *PyCodec_Encode(PyObject *object, const char *encoding, const char *errors) { PyObject *encoder; encoder = PyCodec_Encoder(encoding); if (encoder == NULL) return NULL; return _PyCodec_EncodeInternal(object, encoder, encoding, errors); } PyObject *PyCodec_Decode(PyObject *object, const char *encoding, const char *errors) { PyObject *decoder; decoder = PyCodec_Decoder(encoding); if (decoder == NULL) return NULL; return _PyCodec_DecodeInternal(object, decoder, encoding, errors); } /* Text encoding/decoding API */ PyObject * _PyCodec_LookupTextEncoding(const char *encoding, const char *alternate_command) { PyObject *codec; PyObject *attr; int is_text_codec; codec = _PyCodec_Lookup(encoding); if (codec == NULL) return NULL; /* Backwards compatibility: assume any raw tuple describes a text * encoding, and the same for anything lacking the private * attribute. */ if (!PyTuple_CheckExact(codec)) { if (_PyObject_LookupAttr(codec, &_Py_ID(_is_text_encoding), &attr) < 0) { Py_DECREF(codec); return NULL; } if (attr != NULL) { is_text_codec = PyObject_IsTrue(attr); Py_DECREF(attr); if (is_text_codec <= 0) { Py_DECREF(codec); if (!is_text_codec) PyErr_Format(PyExc_LookupError, "'%.400s' is not a text encoding; " "use %s to handle arbitrary codecs", encoding, alternate_command); return NULL; } } } /* This appears to be a valid text encoding */ return codec; } static PyObject *codec_getitem_checked(const char *encoding, const char *alternate_command, int index) { PyObject *codec; PyObject *v; codec = _PyCodec_LookupTextEncoding(encoding, alternate_command); if (codec == NULL) return NULL; v = Py_NewRef(PyTuple_GET_ITEM(codec, index)); Py_DECREF(codec); return v; } static PyObject * _PyCodec_TextEncoder(const char *encoding) { return codec_getitem_checked(encoding, "codecs.encode()", 0); } static PyObject * _PyCodec_TextDecoder(const char *encoding) { return codec_getitem_checked(encoding, "codecs.decode()", 1); } PyObject *_PyCodec_EncodeText(PyObject *object, const char *encoding, const char *errors) { PyObject *encoder; encoder = _PyCodec_TextEncoder(encoding); if (encoder == NULL) return NULL; return _PyCodec_EncodeInternal(object, encoder, encoding, errors); } PyObject *_PyCodec_DecodeText(PyObject *object, const char *encoding, const char *errors) { PyObject *decoder; decoder = _PyCodec_TextDecoder(encoding); if (decoder == NULL) return NULL; return _PyCodec_DecodeInternal(object, decoder, encoding, errors); } /* Register the error handling callback function error under the name name. This function will be called by the codec when it encounters an unencodable characters/undecodable bytes and doesn't know the callback name, when name is specified as the error parameter in the call to the encode/decode function. Return 0 on success, -1 on error */ int PyCodec_RegisterError(const char *name, PyObject *error) { PyInterpreterState *interp = _PyInterpreterState_GET(); if (interp->codec_search_path == NULL && _PyCodecRegistry_Init()) return -1; if (!PyCallable_Check(error)) { PyErr_SetString(PyExc_TypeError, "handler must be callable"); return -1; } return PyDict_SetItemString(interp->codec_error_registry, name, error); } /* Lookup the error handling callback function registered under the name error. As a special case NULL can be passed, in which case the error handling callback for strict encoding will be returned. */ PyObject *PyCodec_LookupError(const char *name) { PyObject *handler = NULL; PyInterpreterState *interp = _PyInterpreterState_GET(); if (interp->codec_search_path == NULL && _PyCodecRegistry_Init()) return NULL; if (name==NULL) name = "strict"; handler = _PyDict_GetItemStringWithError(interp->codec_error_registry, name); if (handler) { Py_INCREF(handler); } else if (!PyErr_Occurred()) { PyErr_Format(PyExc_LookupError, "unknown error handler name '%.400s'", name); } return handler; } static void wrong_exception_type(PyObject *exc) { PyErr_Format(PyExc_TypeError, "don't know how to handle %.200s in error callback", Py_TYPE(exc)->tp_name); } PyObject *PyCodec_StrictErrors(PyObject *exc) { if (PyExceptionInstance_Check(exc)) PyErr_SetObject(PyExceptionInstance_Class(exc), exc); else PyErr_SetString(PyExc_TypeError, "codec must pass exception instance"); return NULL; } PyObject *PyCodec_IgnoreErrors(PyObject *exc) { Py_ssize_t end; if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { if (PyUnicodeEncodeError_GetEnd(exc, &end)) return NULL; } else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) { if (PyUnicodeDecodeError_GetEnd(exc, &end)) return NULL; } else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError)) { if (PyUnicodeTranslateError_GetEnd(exc, &end)) return NULL; } else { wrong_exception_type(exc); return NULL; } return Py_BuildValue("(Nn)", PyUnicode_New(0, 0), end); } PyObject *PyCodec_ReplaceErrors(PyObject *exc) { Py_ssize_t start, end, i, len; if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { PyObject *res; Py_UCS1 *outp; if (PyUnicodeEncodeError_GetStart(exc, &start)) return NULL; if (PyUnicodeEncodeError_GetEnd(exc, &end)) return NULL; len = end - start; res = PyUnicode_New(len, '?'); if (res == NULL) return NULL; assert(PyUnicode_KIND(res) == PyUnicode_1BYTE_KIND); outp = PyUnicode_1BYTE_DATA(res); for (i = 0; i < len; ++i) outp[i] = '?'; assert(_PyUnicode_CheckConsistency(res, 1)); return Py_BuildValue("(Nn)", res, end); } else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) { if (PyUnicodeDecodeError_GetEnd(exc, &end)) return NULL; return Py_BuildValue("(Cn)", (int)Py_UNICODE_REPLACEMENT_CHARACTER, end); } else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError)) { PyObject *res; Py_UCS2 *outp; if (PyUnicodeTranslateError_GetStart(exc, &start)) return NULL; if (PyUnicodeTranslateError_GetEnd(exc, &end)) return NULL; len = end - start; res = PyUnicode_New(len, Py_UNICODE_REPLACEMENT_CHARACTER); if (res == NULL) return NULL; assert(PyUnicode_KIND(res) == PyUnicode_2BYTE_KIND); outp = PyUnicode_2BYTE_DATA(res); for (i = 0; i < len; i++) outp[i] = Py_UNICODE_REPLACEMENT_CHARACTER; assert(_PyUnicode_CheckConsistency(res, 1)); return Py_BuildValue("(Nn)", res, end); } else { wrong_exception_type(exc); return NULL; } } PyObject *PyCodec_XMLCharRefReplaceErrors(PyObject *exc) { if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { PyObject *restuple; PyObject *object; Py_ssize_t i; Py_ssize_t start; Py_ssize_t end; PyObject *res; Py_UCS1 *outp; Py_ssize_t ressize; Py_UCS4 ch; if (PyUnicodeEncodeError_GetStart(exc, &start)) return NULL; if (PyUnicodeEncodeError_GetEnd(exc, &end)) return NULL; if (!(object = PyUnicodeEncodeError_GetObject(exc))) return NULL; if (end - start > PY_SSIZE_T_MAX / (2+7+1)) end = start + PY_SSIZE_T_MAX / (2+7+1); for (i = start, ressize = 0; i < end; ++i) { /* object is guaranteed to be "ready" */ ch = PyUnicode_READ_CHAR(object, i); if (ch<10) ressize += 2+1+1; else if (ch<100) ressize += 2+2+1; else if (ch<1000) ressize += 2+3+1; else if (ch<10000) ressize += 2+4+1; else if (ch<100000) ressize += 2+5+1; else if (ch<1000000) ressize += 2+6+1; else ressize += 2+7+1; } /* allocate replacement */ res = PyUnicode_New(ressize, 127); if (res == NULL) { Py_DECREF(object); return NULL; } outp = PyUnicode_1BYTE_DATA(res); /* generate replacement */ for (i = start; i < end; ++i) { int digits; int base; ch = PyUnicode_READ_CHAR(object, i); *outp++ = '&'; *outp++ = '#'; if (ch<10) { digits = 1; base = 1; } else if (ch<100) { digits = 2; base = 10; } else if (ch<1000) { digits = 3; base = 100; } else if (ch<10000) { digits = 4; base = 1000; } else if (ch<100000) { digits = 5; base = 10000; } else if (ch<1000000) { digits = 6; base = 100000; } else { digits = 7; base = 1000000; } while (digits-->0) { *outp++ = '0' + ch/base; ch %= base; base /= 10; } *outp++ = ';'; } assert(_PyUnicode_CheckConsistency(res, 1)); restuple = Py_BuildValue("(Nn)", res, end); Py_DECREF(object); return restuple; } else { wrong_exception_type(exc); return NULL; } } PyObject *PyCodec_BackslashReplaceErrors(PyObject *exc) { PyObject *object; Py_ssize_t i; Py_ssize_t start; Py_ssize_t end; PyObject *res; Py_UCS1 *outp; int ressize; Py_UCS4 c; if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) { const unsigned char *p; if (PyUnicodeDecodeError_GetStart(exc, &start)) return NULL; if (PyUnicodeDecodeError_GetEnd(exc, &end)) return NULL; if (!(object = PyUnicodeDecodeError_GetObject(exc))) return NULL; p = (const unsigned char*)PyBytes_AS_STRING(object); res = PyUnicode_New(4 * (end - start), 127); if (res == NULL) { Py_DECREF(object); return NULL; } outp = PyUnicode_1BYTE_DATA(res); for (i = start; i < end; i++, outp += 4) { unsigned char c = p[i]; outp[0] = '\\'; outp[1] = 'x'; outp[2] = Py_hexdigits[(c>>4)&0xf]; outp[3] = Py_hexdigits[c&0xf]; } assert(_PyUnicode_CheckConsistency(res, 1)); Py_DECREF(object); return Py_BuildValue("(Nn)", res, end); } if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { if (PyUnicodeEncodeError_GetStart(exc, &start)) return NULL; if (PyUnicodeEncodeError_GetEnd(exc, &end)) return NULL; if (!(object = PyUnicodeEncodeError_GetObject(exc))) return NULL; } else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError)) { if (PyUnicodeTranslateError_GetStart(exc, &start)) return NULL; if (PyUnicodeTranslateError_GetEnd(exc, &end)) return NULL; if (!(object = PyUnicodeTranslateError_GetObject(exc))) return NULL; } else { wrong_exception_type(exc); return NULL; } if (end - start > PY_SSIZE_T_MAX / (1+1+8)) end = start + PY_SSIZE_T_MAX / (1+1+8); for (i = start, ressize = 0; i < end; ++i) { /* object is guaranteed to be "ready" */ c = PyUnicode_READ_CHAR(object, i); if (c >= 0x10000) { ressize += 1+1+8; } else if (c >= 0x100) { ressize += 1+1+4; } else ressize += 1+1+2; } res = PyUnicode_New(ressize, 127); if (res == NULL) { Py_DECREF(object); return NULL; } outp = PyUnicode_1BYTE_DATA(res); for (i = start; i < end; ++i) { c = PyUnicode_READ_CHAR(object, i); *outp++ = '\\'; if (c >= 0x00010000) { *outp++ = 'U'; *outp++ = Py_hexdigits[(c>>28)&0xf]; *outp++ = Py_hexdigits[(c>>24)&0xf]; *outp++ = Py_hexdigits[(c>>20)&0xf]; *outp++ = Py_hexdigits[(c>>16)&0xf]; *outp++ = Py_hexdigits[(c>>12)&0xf]; *outp++ = Py_hexdigits[(c>>8)&0xf]; } else if (c >= 0x100) { *outp++ = 'u'; *outp++ = Py_hexdigits[(c>>12)&0xf]; *outp++ = Py_hexdigits[(c>>8)&0xf]; } else *outp++ = 'x'; *outp++ = Py_hexdigits[(c>>4)&0xf]; *outp++ = Py_hexdigits[c&0xf]; } assert(_PyUnicode_CheckConsistency(res, 1)); Py_DECREF(object); return Py_BuildValue("(Nn)", res, end); } static _PyUnicode_Name_CAPI *ucnhash_capi = NULL; PyObject *PyCodec_NameReplaceErrors(PyObject *exc) { if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { PyObject *restuple; PyObject *object; Py_ssize_t i; Py_ssize_t start; Py_ssize_t end; PyObject *res; Py_UCS1 *outp; Py_ssize_t ressize; int replsize; Py_UCS4 c; char buffer[256]; /* NAME_MAXLEN */ if (PyUnicodeEncodeError_GetStart(exc, &start)) return NULL; if (PyUnicodeEncodeError_GetEnd(exc, &end)) return NULL; if (!(object = PyUnicodeEncodeError_GetObject(exc))) return NULL; if (!ucnhash_capi) { /* load the unicode data module */ ucnhash_capi = (_PyUnicode_Name_CAPI *)PyCapsule_Import( PyUnicodeData_CAPSULE_NAME, 1); if (!ucnhash_capi) { return NULL; } } for (i = start, ressize = 0; i < end; ++i) { /* object is guaranteed to be "ready" */ c = PyUnicode_READ_CHAR(object, i); if (ucnhash_capi->getname(c, buffer, sizeof(buffer), 1)) { replsize = 1+1+1+(int)strlen(buffer)+1; } else if (c >= 0x10000) { replsize = 1+1+8; } else if (c >= 0x100) { replsize = 1+1+4; } else replsize = 1+1+2; if (ressize > PY_SSIZE_T_MAX - replsize) break; ressize += replsize; } end = i; res = PyUnicode_New(ressize, 127); if (res==NULL) return NULL; for (i = start, outp = PyUnicode_1BYTE_DATA(res); i < end; ++i) { c = PyUnicode_READ_CHAR(object, i); *outp++ = '\\'; if (ucnhash_capi->getname(c, buffer, sizeof(buffer), 1)) { *outp++ = 'N'; *outp++ = '{'; strcpy((char *)outp, buffer); outp += strlen(buffer); *outp++ = '}'; continue; } if (c >= 0x00010000) { *outp++ = 'U'; *outp++ = Py_hexdigits[(c>>28)&0xf]; *outp++ = Py_hexdigits[(c>>24)&0xf]; *outp++ = Py_hexdigits[(c>>20)&0xf]; *outp++ = Py_hexdigits[(c>>16)&0xf]; *outp++ = Py_hexdigits[(c>>12)&0xf]; *outp++ = Py_hexdigits[(c>>8)&0xf]; } else if (c >= 0x100) { *outp++ = 'u'; *outp++ = Py_hexdigits[(c>>12)&0xf]; *outp++ = Py_hexdigits[(c>>8)&0xf]; } else *outp++ = 'x'; *outp++ = Py_hexdigits[(c>>4)&0xf]; *outp++ = Py_hexdigits[c&0xf]; } assert(outp == PyUnicode_1BYTE_DATA(res) + ressize); assert(_PyUnicode_CheckConsistency(res, 1)); restuple = Py_BuildValue("(Nn)", res, end); Py_DECREF(object); return restuple; } else { wrong_exception_type(exc); return NULL; } } #define ENC_UNKNOWN -1 #define ENC_UTF8 0 #define ENC_UTF16BE 1 #define ENC_UTF16LE 2 #define ENC_UTF32BE 3 #define ENC_UTF32LE 4 static int get_standard_encoding(const char *encoding, int *bytelength) { if (Py_TOLOWER(encoding[0]) == 'u' && Py_TOLOWER(encoding[1]) == 't' && Py_TOLOWER(encoding[2]) == 'f') { encoding += 3; if (*encoding == '-' || *encoding == '_' ) encoding++; if (encoding[0] == '8' && encoding[1] == '\0') { *bytelength = 3; return ENC_UTF8; } else if (encoding[0] == '1' && encoding[1] == '6') { encoding += 2; *bytelength = 2; if (*encoding == '\0') { #ifdef WORDS_BIGENDIAN return ENC_UTF16BE; #else return ENC_UTF16LE; #endif } if (*encoding == '-' || *encoding == '_' ) encoding++; if (Py_TOLOWER(encoding[1]) == 'e' && encoding[2] == '\0') { if (Py_TOLOWER(encoding[0]) == 'b') return ENC_UTF16BE; if (Py_TOLOWER(encoding[0]) == 'l') return ENC_UTF16LE; } } else if (encoding[0] == '3' && encoding[1] == '2') { encoding += 2; *bytelength = 4; if (*encoding == '\0') { #ifdef WORDS_BIGENDIAN return ENC_UTF32BE; #else return ENC_UTF32LE; #endif } if (*encoding == '-' || *encoding == '_' ) encoding++; if (Py_TOLOWER(encoding[1]) == 'e' && encoding[2] == '\0') { if (Py_TOLOWER(encoding[0]) == 'b') return ENC_UTF32BE; if (Py_TOLOWER(encoding[0]) == 'l') return ENC_UTF32LE; } } } else if (strcmp(encoding, "CP_UTF8") == 0) { *bytelength = 3; return ENC_UTF8; } return ENC_UNKNOWN; } /* This handler is declared static until someone demonstrates a need to call it directly. */ static PyObject * PyCodec_SurrogatePassErrors(PyObject *exc) { PyObject *restuple; PyObject *object; PyObject *encode; const char *encoding; int code; int bytelength; Py_ssize_t i; Py_ssize_t start; Py_ssize_t end; PyObject *res; if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { unsigned char *outp; if (PyUnicodeEncodeError_GetStart(exc, &start)) return NULL; if (PyUnicodeEncodeError_GetEnd(exc, &end)) return NULL; if (!(object = PyUnicodeEncodeError_GetObject(exc))) return NULL; if (!(encode = PyUnicodeEncodeError_GetEncoding(exc))) { Py_DECREF(object); return NULL; } if (!(encoding = PyUnicode_AsUTF8(encode))) { Py_DECREF(object); Py_DECREF(encode); return NULL; } code = get_standard_encoding(encoding, &bytelength); Py_DECREF(encode); if (code == ENC_UNKNOWN) { /* Not supported, fail with original exception */ PyErr_SetObject(PyExceptionInstance_Class(exc), exc); Py_DECREF(object); return NULL; } if (end - start > PY_SSIZE_T_MAX / bytelength) end = start + PY_SSIZE_T_MAX / bytelength; res = PyBytes_FromStringAndSize(NULL, bytelength*(end-start)); if (!res) { Py_DECREF(object); return NULL; } outp = (unsigned char*)PyBytes_AsString(res); for (i = start; i < end; i++) { /* object is guaranteed to be "ready" */ Py_UCS4 ch = PyUnicode_READ_CHAR(object, i); if (!Py_UNICODE_IS_SURROGATE(ch)) { /* Not a surrogate, fail with original exception */ PyErr_SetObject(PyExceptionInstance_Class(exc), exc); Py_DECREF(res); Py_DECREF(object); return NULL; } switch (code) { case ENC_UTF8: *outp++ = (unsigned char)(0xe0 | (ch >> 12)); *outp++ = (unsigned char)(0x80 | ((ch >> 6) & 0x3f)); *outp++ = (unsigned char)(0x80 | (ch & 0x3f)); break; case ENC_UTF16LE: *outp++ = (unsigned char) ch; *outp++ = (unsigned char)(ch >> 8); break; case ENC_UTF16BE: *outp++ = (unsigned char)(ch >> 8); *outp++ = (unsigned char) ch; break; case ENC_UTF32LE: *outp++ = (unsigned char) ch; *outp++ = (unsigned char)(ch >> 8); *outp++ = (unsigned char)(ch >> 16); *outp++ = (unsigned char)(ch >> 24); break; case ENC_UTF32BE: *outp++ = (unsigned char)(ch >> 24); *outp++ = (unsigned char)(ch >> 16); *outp++ = (unsigned char)(ch >> 8); *outp++ = (unsigned char) ch; break; } } restuple = Py_BuildValue("(On)", res, end); Py_DECREF(res); Py_DECREF(object); return restuple; } else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) { const unsigned char *p; Py_UCS4 ch = 0; if (PyUnicodeDecodeError_GetStart(exc, &start)) return NULL; if (PyUnicodeDecodeError_GetEnd(exc, &end)) return NULL; if (!(object = PyUnicodeDecodeError_GetObject(exc))) return NULL; p = (const unsigned char*)PyBytes_AS_STRING(object); if (!(encode = PyUnicodeDecodeError_GetEncoding(exc))) { Py_DECREF(object); return NULL; } if (!(encoding = PyUnicode_AsUTF8(encode))) { Py_DECREF(object); Py_DECREF(encode); return NULL; } code = get_standard_encoding(encoding, &bytelength); Py_DECREF(encode); if (code == ENC_UNKNOWN) { /* Not supported, fail with original exception */ PyErr_SetObject(PyExceptionInstance_Class(exc), exc); Py_DECREF(object); return NULL; } /* Try decoding a single surrogate character. If there are more, let the codec call us again. */ p += start; if (PyBytes_GET_SIZE(object) - start >= bytelength) { switch (code) { case ENC_UTF8: if ((p[0] & 0xf0) == 0xe0 && (p[1] & 0xc0) == 0x80 && (p[2] & 0xc0) == 0x80) { /* it's a three-byte code */ ch = ((p[0] & 0x0f) << 12) + ((p[1] & 0x3f) << 6) + (p[2] & 0x3f); } break; case ENC_UTF16LE: ch = p[1] << 8 | p[0]; break; case ENC_UTF16BE: ch = p[0] << 8 | p[1]; break; case ENC_UTF32LE: ch = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; break; case ENC_UTF32BE: ch = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; break; } } Py_DECREF(object); if (!Py_UNICODE_IS_SURROGATE(ch)) { /* it's not a surrogate - fail */ PyErr_SetObject(PyExceptionInstance_Class(exc), exc); return NULL; } res = PyUnicode_FromOrdinal(ch); if (res == NULL) return NULL; return Py_BuildValue("(Nn)", res, start + bytelength); } else { wrong_exception_type(exc); return NULL; } } static PyObject * PyCodec_SurrogateEscapeErrors(PyObject *exc) { PyObject *restuple; PyObject *object; Py_ssize_t i; Py_ssize_t start; Py_ssize_t end; PyObject *res; if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) { char *outp; if (PyUnicodeEncodeError_GetStart(exc, &start)) return NULL; if (PyUnicodeEncodeError_GetEnd(exc, &end)) return NULL; if (!(object = PyUnicodeEncodeError_GetObject(exc))) return NULL; res = PyBytes_FromStringAndSize(NULL, end-start); if (!res) { Py_DECREF(object); return NULL; } outp = PyBytes_AsString(res); for (i = start; i < end; i++) { /* object is guaranteed to be "ready" */ Py_UCS4 ch = PyUnicode_READ_CHAR(object, i); if (ch < 0xdc80 || ch > 0xdcff) { /* Not a UTF-8b surrogate, fail with original exception */ PyErr_SetObject(PyExceptionInstance_Class(exc), exc); Py_DECREF(res); Py_DECREF(object); return NULL; } *outp++ = ch - 0xdc00; } restuple = Py_BuildValue("(On)", res, end); Py_DECREF(res); Py_DECREF(object); return restuple; } else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) { PyObject *str; const unsigned char *p; Py_UCS2 ch[4]; /* decode up to 4 bad bytes. */ int consumed = 0; if (PyUnicodeDecodeError_GetStart(exc, &start)) return NULL; if (PyUnicodeDecodeError_GetEnd(exc, &end)) return NULL; if (!(object = PyUnicodeDecodeError_GetObject(exc))) return NULL; p = (const unsigned char*)PyBytes_AS_STRING(object); while (consumed < 4 && consumed < end-start) { /* Refuse to escape ASCII bytes. */ if (p[start+consumed] < 128) break; ch[consumed] = 0xdc00 + p[start+consumed]; consumed++; } Py_DECREF(object); if (!consumed) { /* codec complained about ASCII byte. */ PyErr_SetObject(PyExceptionInstance_Class(exc), exc); return NULL; } str = PyUnicode_FromKindAndData(PyUnicode_2BYTE_KIND, ch, consumed); if (str == NULL) return NULL; return Py_BuildValue("(Nn)", str, start+consumed); } else { wrong_exception_type(exc); return NULL; } } static PyObject *strict_errors(PyObject *self, PyObject *exc) { return PyCodec_StrictErrors(exc); } static PyObject *ignore_errors(PyObject *self, PyObject *exc) { return PyCodec_IgnoreErrors(exc); } static PyObject *replace_errors(PyObject *self, PyObject *exc) { return PyCodec_ReplaceErrors(exc); } static PyObject *xmlcharrefreplace_errors(PyObject *self, PyObject *exc) { return PyCodec_XMLCharRefReplaceErrors(exc); } static PyObject *backslashreplace_errors(PyObject *self, PyObject *exc) { return PyCodec_BackslashReplaceErrors(exc); } static PyObject *namereplace_errors(PyObject *self, PyObject *exc) { return PyCodec_NameReplaceErrors(exc); } static PyObject *surrogatepass_errors(PyObject *self, PyObject *exc) { return PyCodec_SurrogatePassErrors(exc); } static PyObject *surrogateescape_errors(PyObject *self, PyObject *exc) { return PyCodec_SurrogateEscapeErrors(exc); } static int _PyCodecRegistry_Init(void) { static struct { const char *name; PyMethodDef def; } methods[] = { { "strict", { "strict_errors", strict_errors, METH_O, PyDoc_STR("Implements the 'strict' error handling, which " "raises a UnicodeError on coding errors.") } }, { "ignore", { "ignore_errors", ignore_errors, METH_O, PyDoc_STR("Implements the 'ignore' error handling, which " "ignores malformed data and continues.") } }, { "replace", { "replace_errors", replace_errors, METH_O, PyDoc_STR("Implements the 'replace' error handling, which " "replaces malformed data with a replacement marker.") } }, { "xmlcharrefreplace", { "xmlcharrefreplace_errors", xmlcharrefreplace_errors, METH_O, PyDoc_STR("Implements the 'xmlcharrefreplace' error handling, " "which replaces an unencodable character with the " "appropriate XML character reference.") } }, { "backslashreplace", { "backslashreplace_errors", backslashreplace_errors, METH_O, PyDoc_STR("Implements the 'backslashreplace' error handling, " "which replaces malformed data with a backslashed " "escape sequence.") } }, { "namereplace", { "namereplace_errors", namereplace_errors, METH_O, PyDoc_STR("Implements the 'namereplace' error handling, " "which replaces an unencodable character with a " "\\N{...} escape sequence.") } }, { "surrogatepass", { "surrogatepass", surrogatepass_errors, METH_O } }, { "surrogateescape", { "surrogateescape", surrogateescape_errors, METH_O } } }; PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *mod; if (interp->codec_search_path != NULL) return 0; interp->codec_search_path = PyList_New(0); if (interp->codec_search_path == NULL) { return -1; } interp->codec_search_cache = PyDict_New(); if (interp->codec_search_cache == NULL) { return -1; } interp->codec_error_registry = PyDict_New(); if (interp->codec_error_registry == NULL) { return -1; } for (size_t i = 0; i < Py_ARRAY_LENGTH(methods); ++i) { PyObject *func = PyCFunction_NewEx(&methods[i].def, NULL, NULL); if (!func) { return -1; } int res = PyCodec_RegisterError(methods[i].name, func); Py_DECREF(func); if (res) { return -1; } } mod = PyImport_ImportModule("encodings"); if (mod == NULL) { return -1; } Py_DECREF(mod); interp->codecs_initialized = 1; return 0; } ================================================ FILE: Compile.c ================================================ #include #include "Python.h" #include "pycore_ast.h" // _PyAST_GetDocString() #define NEED_OPCODE_TABLES #include "pycore_opcode_utils.h" #undef NEED_OPCODE_TABLES #include "pycore_flowgraph.h" #include "pycore_code.h" // _PyCode_New() #include "pycore_compile.h" #include "pycore_intrinsics.h" #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_symtable.h" // PySTEntryObject, _PyFuture_FromAST() #include "opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed #define COMP_GENEXP 0 #define COMP_LISTCOMP 1 #define COMP_SETCOMP 2 #define COMP_DICTCOMP 3 /* A soft limit for stack use, to avoid excessive * memory use for large constants, etc. * * The value 30 is plucked out of thin air. * Code that could use more stack than this is * rare, so the exact value is unimportant. */ #define STACK_USE_GUIDELINE 30 #undef SUCCESS #undef ERROR #define SUCCESS 0 #define ERROR -1 #define RETURN_IF_ERROR(X) \ if ((X) == -1) { \ return ERROR; \ } #define IS_TOP_LEVEL_AWAIT(C) ( \ ((C)->c_flags.cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) \ && ((C)->u->u_ste->ste_type == ModuleBlock)) typedef _PyCompilerSrcLocation location; typedef _PyCfgInstruction cfg_instr; typedef _PyCfgBasicblock basicblock; typedef _PyCfgBuilder cfg_builder; #define LOCATION(LNO, END_LNO, COL, END_COL) \ ((const _PyCompilerSrcLocation){(LNO), (END_LNO), (COL), (END_COL)}) /* Return true if loc1 starts after loc2 ends. */ static inline bool location_is_after(location loc1, location loc2) { return (loc1.lineno > loc2.end_lineno) || ((loc1.lineno == loc2.end_lineno) && (loc1.col_offset > loc2.end_col_offset)); } #define LOC(x) SRC_LOCATION_FROM_AST(x) typedef _PyCfgJumpTargetLabel jump_target_label; static jump_target_label NO_LABEL = {-1}; #define SAME_LABEL(L1, L2) ((L1).id == (L2).id) #define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL))) #define NEW_JUMP_TARGET_LABEL(C, NAME) \ jump_target_label NAME = instr_sequence_new_label(INSTR_SEQUENCE(C)); \ if (!IS_LABEL(NAME)) { \ return ERROR; \ } #define USE_LABEL(C, LBL) \ RETURN_IF_ERROR(instr_sequence_use_label(INSTR_SEQUENCE(C), (LBL).id)) /* fblockinfo tracks the current frame block. A frame block is used to handle loops, try/except, and try/finally. It's called a frame block to distinguish it from a basic block in the compiler IR. */ enum fblocktype { WHILE_LOOP, FOR_LOOP, TRY_EXCEPT, FINALLY_TRY, FINALLY_END, WITH, ASYNC_WITH, HANDLER_CLEANUP, POP_VALUE, EXCEPTION_HANDLER, EXCEPTION_GROUP_HANDLER, ASYNC_COMPREHENSION_GENERATOR }; struct fblockinfo { enum fblocktype fb_type; jump_target_label fb_block; /* (optional) type-specific exit or cleanup block */ jump_target_label fb_exit; /* (optional) additional information required for unwinding */ void *fb_datum; }; enum { COMPILER_SCOPE_MODULE, COMPILER_SCOPE_CLASS, COMPILER_SCOPE_FUNCTION, COMPILER_SCOPE_ASYNC_FUNCTION, COMPILER_SCOPE_LAMBDA, COMPILER_SCOPE_COMPREHENSION, COMPILER_SCOPE_TYPEPARAMS, }; int _PyCompile_InstrSize(int opcode, int oparg) { assert(!IS_PSEUDO_OPCODE(opcode)); assert(HAS_ARG(opcode) || oparg == 0); int extended_args = (0xFFFFFF < oparg) + (0xFFFF < oparg) + (0xFF < oparg); int caches = _PyOpcode_Caches[opcode]; return extended_args + 1 + caches; } typedef _PyCompile_Instruction instruction; typedef _PyCompile_InstructionSequence instr_sequence; #define INITIAL_INSTR_SEQUENCE_SIZE 100 #define INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE 10 /* * Resize the array if index is out of range. * * idx: the index we want to access * arr: pointer to the array * alloc: pointer to the capacity of the array * default_alloc: initial number of items * item_size: size of each item * */ int _PyCompile_EnsureArrayLargeEnough(int idx, void **array, int *alloc, int default_alloc, size_t item_size) { void *arr = *array; if (arr == NULL) { int new_alloc = default_alloc; if (idx >= new_alloc) { new_alloc = idx + default_alloc; } arr = PyObject_Calloc(new_alloc, item_size); if (arr == NULL) { PyErr_NoMemory(); return ERROR; } *alloc = new_alloc; } else if (idx >= *alloc) { size_t oldsize = *alloc * item_size; int new_alloc = *alloc << 1; if (idx >= new_alloc) { new_alloc = idx + default_alloc; } size_t newsize = new_alloc * item_size; if (oldsize > (SIZE_MAX >> 1)) { PyErr_NoMemory(); return ERROR; } assert(newsize > 0); void *tmp = PyObject_Realloc(arr, newsize); if (tmp == NULL) { PyErr_NoMemory(); return ERROR; } *alloc = new_alloc; arr = tmp; memset((char *)arr + oldsize, 0, newsize - oldsize); } *array = arr; return SUCCESS; } static int instr_sequence_next_inst(instr_sequence *seq) { assert(seq->s_instrs != NULL || seq->s_used == 0); RETURN_IF_ERROR( _PyCompile_EnsureArrayLargeEnough(seq->s_used + 1, (void**)&seq->s_instrs, &seq->s_allocated, INITIAL_INSTR_SEQUENCE_SIZE, sizeof(instruction))); assert(seq->s_allocated >= 0); assert(seq->s_used < seq->s_allocated); return seq->s_used++; } static jump_target_label instr_sequence_new_label(instr_sequence *seq) { jump_target_label lbl = {++seq->s_next_free_label}; return lbl; } static int instr_sequence_use_label(instr_sequence *seq, int lbl) { int old_size = seq->s_labelmap_size; RETURN_IF_ERROR( _PyCompile_EnsureArrayLargeEnough(lbl, (void**)&seq->s_labelmap, &seq->s_labelmap_size, INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE, sizeof(int))); for(int i = old_size; i < seq->s_labelmap_size; i++) { seq->s_labelmap[i] = -111; /* something weird, for debugging */ } seq->s_labelmap[lbl] = seq->s_used; /* label refers to the next instruction */ return SUCCESS; } static int instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc) { assert(IS_WITHIN_OPCODE_RANGE(opcode)); assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0); assert(0 <= oparg && oparg < (1 << 30)); int idx = instr_sequence_next_inst(seq); RETURN_IF_ERROR(idx); instruction *ci = &seq->s_instrs[idx]; ci->i_opcode = opcode; ci->i_oparg = oparg; ci->i_loc = loc; return SUCCESS; } static int instr_sequence_insert_instruction(instr_sequence *seq, int pos, int opcode, int oparg, location loc) { assert(pos >= 0 && pos <= seq->s_used); int last_idx = instr_sequence_next_inst(seq); RETURN_IF_ERROR(last_idx); for (int i=last_idx-1; i >= pos; i--) { seq->s_instrs[i+1] = seq->s_instrs[i]; } instruction *ci = &seq->s_instrs[pos]; ci->i_opcode = opcode; ci->i_oparg = oparg; ci->i_loc = loc; /* fix the labels map */ for(int lbl=0; lbl < seq->s_labelmap_size; lbl++) { if (seq->s_labelmap[lbl] >= pos) { seq->s_labelmap[lbl]++; } } return SUCCESS; } static void instr_sequence_fini(instr_sequence *seq) { PyObject_Free(seq->s_labelmap); seq->s_labelmap = NULL; PyObject_Free(seq->s_instrs); seq->s_instrs = NULL; } static int instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { memset(g, 0, sizeof(cfg_builder)); RETURN_IF_ERROR(_PyCfgBuilder_Init(g)); /* There can be more than one label for the same offset. The * offset2lbl maping selects one of them which we use consistently. */ int *offset2lbl = PyMem_Malloc(seq->s_used * sizeof(int)); if (offset2lbl == NULL) { PyErr_NoMemory(); return ERROR; } for (int i = 0; i < seq->s_used; i++) { offset2lbl[i] = -1; } for (int lbl=0; lbl < seq->s_labelmap_size; lbl++) { int offset = seq->s_labelmap[lbl]; if (offset >= 0) { assert(offset < seq->s_used); offset2lbl[offset] = lbl; } } for (int i = 0; i < seq->s_used; i++) { int lbl = offset2lbl[i]; if (lbl >= 0) { assert (lbl < seq->s_labelmap_size); jump_target_label lbl_ = {lbl}; if (_PyCfgBuilder_UseLabel(g, lbl_) < 0) { goto error; } } instruction *instr = &seq->s_instrs[i]; int opcode = instr->i_opcode; int oparg = instr->i_oparg; if (HAS_TARGET(opcode)) { int offset = seq->s_labelmap[oparg]; assert(offset >= 0 && offset < seq->s_used); int lbl = offset2lbl[offset]; assert(lbl >= 0 && lbl < seq->s_labelmap_size); oparg = lbl; } if (_PyCfgBuilder_Addop(g, opcode, oparg, instr->i_loc) < 0) { goto error; } } PyMem_Free(offset2lbl); int nblocks = 0; for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { nblocks++; } if ((size_t)nblocks > SIZE_MAX / sizeof(basicblock *)) { PyErr_NoMemory(); return ERROR; } return SUCCESS; error: PyMem_Free(offset2lbl); return ERROR; } /* The following items change on entry and exit of code blocks. They must be saved and restored when returning to a block. */ struct compiler_unit { PySTEntryObject *u_ste; int u_scope_type; PyObject *u_private; /* for private name mangling */ instr_sequence u_instr_sequence; /* codegen output */ int u_nfblocks; int u_in_inlined_comp; struct fblockinfo u_fblock[CO_MAXBLOCKS]; _PyCompile_CodeUnitMetadata u_metadata; }; /* This struct captures the global state of a compilation. The u pointer points to the current compilation unit, while units for enclosing blocks are stored in c_stack. The u and c_stack are managed by compiler_enter_scope() and compiler_exit_scope(). Note that we don't track recursion levels during compilation - the task of detecting and rejecting excessive levels of nesting is handled by the symbol analysis pass. */ struct compiler { PyObject *c_filename; struct symtable *c_st; PyFutureFeatures c_future; /* module's __future__ */ PyCompilerFlags c_flags; int c_optimize; /* optimization level */ int c_interactive; /* true if in interactive mode */ int c_nestlevel; PyObject *c_const_cache; /* Python dict holding all constants, including names tuple */ struct compiler_unit *u; /* compiler state for current block */ PyObject *c_stack; /* Python list holding compiler_unit ptrs */ PyArena *c_arena; /* pointer to memory allocation arena */ }; #define INSTR_SEQUENCE(C) (&((C)->u->u_instr_sequence)) typedef struct { // A list of strings corresponding to name captures. It is used to track: // - Repeated name assignments in the same pattern. // - Different name assignments in alternatives. // - The order of name assignments in alternatives. PyObject *stores; // If 0, any name captures against our subject will raise. int allow_irrefutable; // An array of blocks to jump to on failure. Jumping to fail_pop[i] will pop // i items off of the stack. The end result looks like this (with each block // falling through to the next): // fail_pop[4]: POP_TOP // fail_pop[3]: POP_TOP // fail_pop[2]: POP_TOP // fail_pop[1]: POP_TOP // fail_pop[0]: NOP jump_target_label *fail_pop; // The current length of fail_pop. Py_ssize_t fail_pop_size; // The number of items on top of the stack that need to *stay* on top of the // stack. Variable captures go beneath these. All of them will be popped on // failure. Py_ssize_t on_top; } pattern_context; static int codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc); static void compiler_free(struct compiler *); static int compiler_error(struct compiler *, location loc, const char *, ...); static int compiler_warn(struct compiler *, location loc, const char *, ...); static int compiler_nameop(struct compiler *, location, identifier, expr_context_ty); static PyCodeObject *compiler_mod(struct compiler *, mod_ty); static int compiler_visit_stmt(struct compiler *, stmt_ty); static int compiler_visit_keyword(struct compiler *, keyword_ty); static int compiler_visit_expr(struct compiler *, expr_ty); static int compiler_augassign(struct compiler *, stmt_ty); static int compiler_annassign(struct compiler *, stmt_ty); static int compiler_subscript(struct compiler *, expr_ty); static int compiler_slice(struct compiler *, expr_ty); static bool are_all_items_const(asdl_expr_seq *, Py_ssize_t, Py_ssize_t); static int compiler_with(struct compiler *, stmt_ty, int); static int compiler_async_with(struct compiler *, stmt_ty, int); static int compiler_async_for(struct compiler *, stmt_ty); static int compiler_call_simple_kw_helper(struct compiler *c, location loc, asdl_keyword_seq *keywords, Py_ssize_t nkwelts); static int compiler_call_helper(struct compiler *c, location loc, int n, asdl_expr_seq *args, asdl_keyword_seq *keywords); static int compiler_try_except(struct compiler *, stmt_ty); static int compiler_try_star_except(struct compiler *, stmt_ty); static int compiler_set_qualname(struct compiler *); static int compiler_sync_comprehension_generator( struct compiler *c, location loc, asdl_comprehension_seq *generators, int gen_index, int depth, expr_ty elt, expr_ty val, int type, int iter_on_stack); static int compiler_async_comprehension_generator( struct compiler *c, location loc, asdl_comprehension_seq *generators, int gen_index, int depth, expr_ty elt, expr_ty val, int type, int iter_on_stack); static int compiler_pattern(struct compiler *, pattern_ty, pattern_context *); static int compiler_match(struct compiler *, stmt_ty); static int compiler_pattern_subpattern(struct compiler *, pattern_ty, pattern_context *); static PyCodeObject *optimize_and_assemble(struct compiler *, int addNone); #define CAPSULE_NAME "compile.c compiler unit" static int compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename, PyCompilerFlags flags, int optimize, PyArena *arena) { c->c_const_cache = PyDict_New(); if (!c->c_const_cache) { return ERROR; } c->c_stack = PyList_New(0); if (!c->c_stack) { return ERROR; } c->c_filename = Py_NewRef(filename); c->c_arena = arena; if (!_PyFuture_FromAST(mod, filename, &c->c_future)) { return ERROR; } int merged = c->c_future.ff_features | flags.cf_flags; c->c_future.ff_features = merged; flags.cf_flags = merged; c->c_flags = flags; c->c_optimize = (optimize == -1) ? _Py_GetConfig()->optimization_level : optimize; c->c_nestlevel = 0; if (!_PyAST_Optimize(mod, arena, c->c_optimize, merged)) { return ERROR; } c->c_st = _PySymtable_Build(mod, filename, &c->c_future); if (c->c_st == NULL) { if (!PyErr_Occurred()) { PyErr_SetString(PyExc_SystemError, "no symtable"); } return ERROR; } return SUCCESS; } static struct compiler* new_compiler(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags, int optimize, PyArena *arena) { PyCompilerFlags flags = pflags ? *pflags : _PyCompilerFlags_INIT; struct compiler *c = PyMem_Calloc(1, sizeof(struct compiler)); if (c == NULL) { return NULL; } if (compiler_setup(c, mod, filename, flags, optimize, arena) < 0) { compiler_free(c); return NULL; } return c; } PyCodeObject * _PyAST_Compile(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags, int optimize, PyArena *arena) { assert(!PyErr_Occurred()); struct compiler *c = new_compiler(mod, filename, pflags, optimize, arena); if (c == NULL) { return NULL; } PyCodeObject *co = compiler_mod(c, mod); compiler_free(c); assert(co || PyErr_Occurred()); return co; } static void compiler_free(struct compiler *c) { if (c->c_st) _PySymtable_Free(c->c_st); Py_XDECREF(c->c_filename); Py_XDECREF(c->c_const_cache); Py_XDECREF(c->c_stack); PyMem_Free(c); } static PyObject * list2dict(PyObject *list) { Py_ssize_t i, n; PyObject *v, *k; PyObject *dict = PyDict_New(); if (!dict) return NULL; n = PyList_Size(list); for (i = 0; i < n; i++) { v = PyLong_FromSsize_t(i); if (!v) { Py_DECREF(dict); return NULL; } k = PyList_GET_ITEM(list, i); if (PyDict_SetItem(dict, k, v) < 0) { Py_DECREF(v); Py_DECREF(dict); return NULL; } Py_DECREF(v); } return dict; } /* Return new dict containing names from src that match scope(s). src is a symbol table dictionary. If the scope of a name matches either scope_type or flag is set, insert it into the new dict. The values are integers, starting at offset and increasing by one for each key. */ static PyObject * dictbytype(PyObject *src, int scope_type, int flag, Py_ssize_t offset) { Py_ssize_t i = offset, scope, num_keys, key_i; PyObject *k, *v, *dest = PyDict_New(); PyObject *sorted_keys; assert(offset >= 0); if (dest == NULL) return NULL; /* Sort the keys so that we have a deterministic order on the indexes saved in the returned dictionary. These indexes are used as indexes into the free and cell var storage. Therefore if they aren't deterministic, then the generated bytecode is not deterministic. */ sorted_keys = PyDict_Keys(src); if (sorted_keys == NULL) return NULL; if (PyList_Sort(sorted_keys) != 0) { Py_DECREF(sorted_keys); return NULL; } num_keys = PyList_GET_SIZE(sorted_keys); for (key_i = 0; key_i < num_keys; key_i++) { /* XXX this should probably be a macro in symtable.h */ long vi; k = PyList_GET_ITEM(sorted_keys, key_i); v = PyDict_GetItemWithError(src, k); assert(v && PyLong_Check(v)); vi = PyLong_AS_LONG(v); scope = (vi >> SCOPE_OFFSET) & SCOPE_MASK; if (scope == scope_type || vi & flag) { PyObject *item = PyLong_FromSsize_t(i); if (item == NULL) { Py_DECREF(sorted_keys); Py_DECREF(dest); return NULL; } i++; if (PyDict_SetItem(dest, k, item) < 0) { Py_DECREF(sorted_keys); Py_DECREF(item); Py_DECREF(dest); return NULL; } Py_DECREF(item); } } Py_DECREF(sorted_keys); return dest; } static void compiler_unit_free(struct compiler_unit *u) { instr_sequence_fini(&u->u_instr_sequence); Py_CLEAR(u->u_ste); Py_CLEAR(u->u_metadata.u_name); Py_CLEAR(u->u_metadata.u_qualname); Py_CLEAR(u->u_metadata.u_consts); Py_CLEAR(u->u_metadata.u_names); Py_CLEAR(u->u_metadata.u_varnames); Py_CLEAR(u->u_metadata.u_freevars); Py_CLEAR(u->u_metadata.u_cellvars); Py_CLEAR(u->u_metadata.u_fasthidden); Py_CLEAR(u->u_private); PyObject_Free(u); } static int compiler_set_qualname(struct compiler *c) { Py_ssize_t stack_size; struct compiler_unit *u = c->u; PyObject *name, *base; base = NULL; stack_size = PyList_GET_SIZE(c->c_stack); assert(stack_size >= 1); if (stack_size > 1) { int scope, force_global = 0; struct compiler_unit *parent; PyObject *mangled, *capsule; capsule = PyList_GET_ITEM(c->c_stack, stack_size - 1); parent = (struct compiler_unit *)PyCapsule_GetPointer(capsule, CAPSULE_NAME); assert(parent); if (parent->u_scope_type == COMPILER_SCOPE_TYPEPARAMS) { /* The parent is a type parameter scope, so we need to look at the grandparent. */ if (stack_size == 2) { // If we're immediately within the module, we can skip // the rest and just set the qualname to be the same as name. u->u_metadata.u_qualname = Py_NewRef(u->u_metadata.u_name); return SUCCESS; } capsule = PyList_GET_ITEM(c->c_stack, stack_size - 2); parent = (struct compiler_unit *)PyCapsule_GetPointer(capsule, CAPSULE_NAME); assert(parent); } if (u->u_scope_type == COMPILER_SCOPE_FUNCTION || u->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION || u->u_scope_type == COMPILER_SCOPE_CLASS) { assert(u->u_metadata.u_name); mangled = _Py_Mangle(parent->u_private, u->u_metadata.u_name); if (!mangled) { return ERROR; } scope = _PyST_GetScope(parent->u_ste, mangled); Py_DECREF(mangled); assert(scope != GLOBAL_IMPLICIT); if (scope == GLOBAL_EXPLICIT) force_global = 1; } if (!force_global) { if (parent->u_scope_type == COMPILER_SCOPE_FUNCTION || parent->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION || parent->u_scope_type == COMPILER_SCOPE_LAMBDA) { _Py_DECLARE_STR(dot_locals, "."); base = PyUnicode_Concat(parent->u_metadata.u_qualname, &_Py_STR(dot_locals)); if (base == NULL) { return ERROR; } } else { base = Py_NewRef(parent->u_metadata.u_qualname); } } } if (base != NULL) { _Py_DECLARE_STR(dot, "."); name = PyUnicode_Concat(base, &_Py_STR(dot)); Py_DECREF(base); if (name == NULL) { return ERROR; } PyUnicode_Append(&name, u->u_metadata.u_name); if (name == NULL) { return ERROR; } } else { name = Py_NewRef(u->u_metadata.u_name); } u->u_metadata.u_qualname = name; return SUCCESS; } /* Return the stack effect of opcode with argument oparg. Some opcodes have different stack effect when jump to the target and when not jump. The 'jump' parameter specifies the case: * 0 -- when not jump * 1 -- when jump * -1 -- maximal */ static int stack_effect(int opcode, int oparg, int jump) { if (0 <= opcode && opcode <= MAX_REAL_OPCODE) { if (_PyOpcode_Deopt[opcode] != opcode) { // Specialized instructions are not supported. return PY_INVALID_STACK_EFFECT; } int popped, pushed; if (jump > 0) { popped = _PyOpcode_num_popped(opcode, oparg, true); pushed = _PyOpcode_num_pushed(opcode, oparg, true); } else { popped = _PyOpcode_num_popped(opcode, oparg, false); pushed = _PyOpcode_num_pushed(opcode, oparg, false); } if (popped < 0 || pushed < 0) { return PY_INVALID_STACK_EFFECT; } if (jump >= 0) { return pushed - popped; } if (jump < 0) { // Compute max(pushed - popped, alt_pushed - alt_popped) int alt_popped = _PyOpcode_num_popped(opcode, oparg, true); int alt_pushed = _PyOpcode_num_pushed(opcode, oparg, true); if (alt_popped < 0 || alt_pushed < 0) { return PY_INVALID_STACK_EFFECT; } int diff = pushed - popped; int alt_diff = alt_pushed - alt_popped; if (alt_diff > diff) { return alt_diff; } return diff; } } // Pseudo ops switch (opcode) { case POP_BLOCK: case JUMP: case JUMP_NO_INTERRUPT: return 0; /* Exception handling pseudo-instructions */ case SETUP_FINALLY: /* 0 in the normal flow. * Restore the stack position and push 1 value before jumping to * the handler if an exception be raised. */ return jump ? 1 : 0; case SETUP_CLEANUP: /* As SETUP_FINALLY, but pushes lasti as well */ return jump ? 2 : 0; case SETUP_WITH: /* 0 in the normal flow. * Restore the stack position to the position before the result * of __(a)enter__ and push 2 values before jumping to the handler * if an exception be raised. */ return jump ? 1 : 0; case STORE_FAST_MAYBE_NULL: return -1; case LOAD_METHOD: return 1; case LOAD_SUPER_METHOD: case LOAD_ZERO_SUPER_METHOD: case LOAD_ZERO_SUPER_ATTR: return -1; default: return PY_INVALID_STACK_EFFECT; } return PY_INVALID_STACK_EFFECT; /* not reachable */ } int PyCompile_OpcodeStackEffectWithJump(int opcode, int oparg, int jump) { return stack_effect(opcode, oparg, jump); } int PyCompile_OpcodeStackEffect(int opcode, int oparg) { return stack_effect(opcode, oparg, -1); } static int codegen_addop_noarg(instr_sequence *seq, int opcode, location loc) { assert(!HAS_ARG(opcode)); assert(!IS_ASSEMBLER_OPCODE(opcode)); return instr_sequence_addop(seq, opcode, 0, loc); } static Py_ssize_t dict_add_o(PyObject *dict, PyObject *o) { PyObject *v; Py_ssize_t arg; v = PyDict_GetItemWithError(dict, o); if (!v) { if (PyErr_Occurred()) { return ERROR; } arg = PyDict_GET_SIZE(dict); v = PyLong_FromSsize_t(arg); if (!v) { return ERROR; } if (PyDict_SetItem(dict, o, v) < 0) { Py_DECREF(v); return ERROR; } Py_DECREF(v); } else arg = PyLong_AsLong(v); return arg; } // Merge const *o* recursively and return constant key object. static PyObject* merge_consts_recursive(PyObject *const_cache, PyObject *o) { assert(PyDict_CheckExact(const_cache)); // None and Ellipsis are immortal objects, and key is the singleton. // No need to merge object and key. if (o == Py_None || o == Py_Ellipsis) { return o; } PyObject *key = _PyCode_ConstantKey(o); if (key == NULL) { return NULL; } // t is borrowed reference PyObject *t = PyDict_SetDefault(const_cache, key, key); if (t != key) { // o is registered in const_cache. Just use it. Py_XINCREF(t); Py_DECREF(key); return t; } // We registered o in const_cache. // When o is a tuple or frozenset, we want to merge its // items too. if (PyTuple_CheckExact(o)) { Py_ssize_t len = PyTuple_GET_SIZE(o); for (Py_ssize_t i = 0; i < len; i++) { PyObject *item = PyTuple_GET_ITEM(o, i); PyObject *u = merge_consts_recursive(const_cache, item); if (u == NULL) { Py_DECREF(key); return NULL; } // See _PyCode_ConstantKey() PyObject *v; // borrowed if (PyTuple_CheckExact(u)) { v = PyTuple_GET_ITEM(u, 1); } else { v = u; } if (v != item) { PyTuple_SET_ITEM(o, i, Py_NewRef(v)); Py_DECREF(item); } Py_DECREF(u); } } else if (PyFrozenSet_CheckExact(o)) { // *key* is tuple. And its first item is frozenset of // constant keys. // See _PyCode_ConstantKey() for detail. assert(PyTuple_CheckExact(key)); assert(PyTuple_GET_SIZE(key) == 2); Py_ssize_t len = PySet_GET_SIZE(o); if (len == 0) { // empty frozenset should not be re-created. return key; } PyObject *tuple = PyTuple_New(len); if (tuple == NULL) { Py_DECREF(key); return NULL; } Py_ssize_t i = 0, pos = 0; PyObject *item; Py_hash_t hash; while (_PySet_NextEntry(o, &pos, &item, &hash)) { PyObject *k = merge_consts_recursive(const_cache, item); if (k == NULL) { Py_DECREF(tuple); Py_DECREF(key); return NULL; } PyObject *u; if (PyTuple_CheckExact(k)) { u = Py_NewRef(PyTuple_GET_ITEM(k, 1)); Py_DECREF(k); } else { u = k; } PyTuple_SET_ITEM(tuple, i, u); // Steals reference of u. i++; } // Instead of rewriting o, we create new frozenset and embed in the // key tuple. Caller should get merged frozenset from the key tuple. PyObject *new = PyFrozenSet_New(tuple); Py_DECREF(tuple); if (new == NULL) { Py_DECREF(key); return NULL; } assert(PyTuple_GET_ITEM(key, 1) == o); Py_DECREF(o); PyTuple_SET_ITEM(key, 1, new); } return key; } static Py_ssize_t compiler_add_const(PyObject *const_cache, struct compiler_unit *u, PyObject *o) { assert(PyDict_CheckExact(const_cache)); PyObject *key = merge_consts_recursive(const_cache, o); if (key == NULL) { return ERROR; } Py_ssize_t arg = dict_add_o(u->u_metadata.u_consts, key); Py_DECREF(key); return arg; } static int compiler_addop_load_const(PyObject *const_cache, struct compiler_unit *u, location loc, PyObject *o) { Py_ssize_t arg = compiler_add_const(const_cache, u, o); if (arg < 0) { return ERROR; } return codegen_addop_i(&u->u_instr_sequence, LOAD_CONST, arg, loc); } static int compiler_addop_o(struct compiler_unit *u, location loc, int opcode, PyObject *dict, PyObject *o) { Py_ssize_t arg = dict_add_o(dict, o); if (arg < 0) { return ERROR; } return codegen_addop_i(&u->u_instr_sequence, opcode, arg, loc); } static int compiler_addop_name(struct compiler_unit *u, location loc, int opcode, PyObject *dict, PyObject *o) { PyObject *mangled = _Py_Mangle(u->u_private, o); if (!mangled) { return ERROR; } Py_ssize_t arg = dict_add_o(dict, mangled); Py_DECREF(mangled); if (arg < 0) { return ERROR; } if (opcode == LOAD_ATTR) { arg <<= 1; } if (opcode == LOAD_METHOD) { opcode = LOAD_ATTR; arg <<= 1; arg |= 1; } if (opcode == LOAD_SUPER_ATTR) { arg <<= 2; arg |= 2; } if (opcode == LOAD_SUPER_METHOD) { opcode = LOAD_SUPER_ATTR; arg <<= 2; arg |= 3; } if (opcode == LOAD_ZERO_SUPER_ATTR) { opcode = LOAD_SUPER_ATTR; arg <<= 2; } if (opcode == LOAD_ZERO_SUPER_METHOD) { opcode = LOAD_SUPER_ATTR; arg <<= 2; arg |= 1; } return codegen_addop_i(&u->u_instr_sequence, opcode, arg, loc); } /* Add an opcode with an integer argument */ static int codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc) { /* oparg value is unsigned, but a signed C int is usually used to store it in the C code (like Python/ceval.c). Limit to 32-bit signed C int (rather than INT_MAX) for portability. The argument of a concrete bytecode instruction is limited to 8-bit. EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */ int oparg_ = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int); assert(!IS_ASSEMBLER_OPCODE(opcode)); return instr_sequence_addop(seq, opcode, oparg_, loc); } static int codegen_addop_j(instr_sequence *seq, location loc, int opcode, jump_target_label target) { assert(IS_LABEL(target)); assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); assert(!IS_ASSEMBLER_OPCODE(opcode)); return instr_sequence_addop(seq, opcode, target.id, loc); } #define RETURN_IF_ERROR_IN_SCOPE(C, CALL) { \ if ((CALL) < 0) { \ compiler_exit_scope((C)); \ return ERROR; \ } \ } #define ADDOP(C, LOC, OP) \ RETURN_IF_ERROR(codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC))) #define ADDOP_IN_SCOPE(C, LOC, OP) RETURN_IF_ERROR_IN_SCOPE((C), codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC))) #define ADDOP_LOAD_CONST(C, LOC, O) \ RETURN_IF_ERROR(compiler_addop_load_const((C)->c_const_cache, (C)->u, (LOC), (O))) /* Same as ADDOP_LOAD_CONST, but steals a reference. */ #define ADDOP_LOAD_CONST_NEW(C, LOC, O) { \ PyObject *__new_const = (O); \ if (__new_const == NULL) { \ return ERROR; \ } \ if (compiler_addop_load_const((C)->c_const_cache, (C)->u, (LOC), __new_const) < 0) { \ Py_DECREF(__new_const); \ return ERROR; \ } \ Py_DECREF(__new_const); \ } #define ADDOP_N(C, LOC, OP, O, TYPE) { \ assert(!HAS_CONST(OP)); /* use ADDOP_LOAD_CONST_NEW */ \ if (compiler_addop_o((C)->u, (LOC), (OP), (C)->u->u_metadata.u_ ## TYPE, (O)) < 0) { \ Py_DECREF((O)); \ return ERROR; \ } \ Py_DECREF((O)); \ } #define ADDOP_NAME(C, LOC, OP, O, TYPE) \ RETURN_IF_ERROR(compiler_addop_name((C)->u, (LOC), (OP), (C)->u->u_metadata.u_ ## TYPE, (O))) #define ADDOP_I(C, LOC, OP, O) \ RETURN_IF_ERROR(codegen_addop_i(INSTR_SEQUENCE(C), (OP), (O), (LOC))) #define ADDOP_JUMP(C, LOC, OP, O) \ RETURN_IF_ERROR(codegen_addop_j(INSTR_SEQUENCE(C), (LOC), (OP), (O))) #define ADDOP_COMPARE(C, LOC, CMP) \ RETURN_IF_ERROR(compiler_addcompare((C), (LOC), (cmpop_ty)(CMP))) #define ADDOP_BINARY(C, LOC, BINOP) \ RETURN_IF_ERROR(addop_binary((C), (LOC), (BINOP), false)) #define ADDOP_INPLACE(C, LOC, BINOP) \ RETURN_IF_ERROR(addop_binary((C), (LOC), (BINOP), true)) #define ADD_YIELD_FROM(C, LOC, await) \ RETURN_IF_ERROR(compiler_add_yield_from((C), (LOC), (await))) #define POP_EXCEPT_AND_RERAISE(C, LOC) \ RETURN_IF_ERROR(compiler_pop_except_and_reraise((C), (LOC))) #define ADDOP_YIELD(C, LOC) \ RETURN_IF_ERROR(addop_yield((C), (LOC))) /* VISIT and VISIT_SEQ takes an ASDL type as their second argument. They use the ASDL name to synthesize the name of the C type and the visit function. */ #define VISIT(C, TYPE, V) \ RETURN_IF_ERROR(compiler_visit_ ## TYPE((C), (V))); #define VISIT_IN_SCOPE(C, TYPE, V) \ RETURN_IF_ERROR_IN_SCOPE((C), compiler_visit_ ## TYPE((C), (V))) #define VISIT_SEQ(C, TYPE, SEQ) { \ int _i; \ asdl_ ## TYPE ## _seq *seq = (SEQ); /* avoid variable capture */ \ for (_i = 0; _i < asdl_seq_LEN(seq); _i++) { \ TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, _i); \ RETURN_IF_ERROR(compiler_visit_ ## TYPE((C), elt)); \ } \ } #define VISIT_SEQ_IN_SCOPE(C, TYPE, SEQ) { \ int _i; \ asdl_ ## TYPE ## _seq *seq = (SEQ); /* avoid variable capture */ \ for (_i = 0; _i < asdl_seq_LEN(seq); _i++) { \ TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, _i); \ if (compiler_visit_ ## TYPE((C), elt) < 0) { \ compiler_exit_scope(C); \ return ERROR; \ } \ } \ } static int compiler_enter_scope(struct compiler *c, identifier name, int scope_type, void *key, int lineno) { location loc = LOCATION(lineno, lineno, 0, 0); struct compiler_unit *u; u = (struct compiler_unit *)PyObject_Calloc(1, sizeof( struct compiler_unit)); if (!u) { PyErr_NoMemory(); return ERROR; } u->u_scope_type = scope_type; u->u_metadata.u_argcount = 0; u->u_metadata.u_posonlyargcount = 0; u->u_metadata.u_kwonlyargcount = 0; u->u_ste = PySymtable_Lookup(c->c_st, key); if (!u->u_ste) { compiler_unit_free(u); return ERROR; } u->u_metadata.u_name = Py_NewRef(name); u->u_metadata.u_varnames = list2dict(u->u_ste->ste_varnames); if (!u->u_metadata.u_varnames) { compiler_unit_free(u); return ERROR; } u->u_metadata.u_cellvars = dictbytype(u->u_ste->ste_symbols, CELL, DEF_COMP_CELL, 0); if (!u->u_metadata.u_cellvars) { compiler_unit_free(u); return ERROR; } if (u->u_ste->ste_needs_class_closure) { /* Cook up an implicit __class__ cell. */ Py_ssize_t res; assert(u->u_scope_type == COMPILER_SCOPE_CLASS); res = dict_add_o(u->u_metadata.u_cellvars, &_Py_ID(__class__)); if (res < 0) { compiler_unit_free(u); return ERROR; } } if (u->u_ste->ste_needs_classdict) { /* Cook up an implicit __classdict__ cell. */ Py_ssize_t res; assert(u->u_scope_type == COMPILER_SCOPE_CLASS); res = dict_add_o(u->u_metadata.u_cellvars, &_Py_ID(__classdict__)); if (res < 0) { compiler_unit_free(u); return ERROR; } } u->u_metadata.u_freevars = dictbytype(u->u_ste->ste_symbols, FREE, DEF_FREE_CLASS, PyDict_GET_SIZE(u->u_metadata.u_cellvars)); if (!u->u_metadata.u_freevars) { compiler_unit_free(u); return ERROR; } u->u_metadata.u_fasthidden = PyDict_New(); if (!u->u_metadata.u_fasthidden) { compiler_unit_free(u); return ERROR; } u->u_nfblocks = 0; u->u_in_inlined_comp = 0; u->u_metadata.u_firstlineno = lineno; u->u_metadata.u_consts = PyDict_New(); if (!u->u_metadata.u_consts) { compiler_unit_free(u); return ERROR; } u->u_metadata.u_names = PyDict_New(); if (!u->u_metadata.u_names) { compiler_unit_free(u); return ERROR; } u->u_private = NULL; /* Push the old compiler_unit on the stack. */ if (c->u) { PyObject *capsule = PyCapsule_New(c->u, CAPSULE_NAME, NULL); if (!capsule || PyList_Append(c->c_stack, capsule) < 0) { Py_XDECREF(capsule); compiler_unit_free(u); return ERROR; } Py_DECREF(capsule); u->u_private = Py_XNewRef(c->u->u_private); } c->u = u; c->c_nestlevel++; if (u->u_scope_type == COMPILER_SCOPE_MODULE) { loc.lineno = 0; } else { RETURN_IF_ERROR(compiler_set_qualname(c)); } ADDOP_I(c, loc, RESUME, 0); if (u->u_scope_type == COMPILER_SCOPE_MODULE) { loc.lineno = -1; } return SUCCESS; } static void compiler_exit_scope(struct compiler *c) { // Don't call PySequence_DelItem() with an exception raised PyObject *exc = PyErr_GetRaisedException(); c->c_nestlevel--; compiler_unit_free(c->u); /* Restore c->u to the parent unit. */ Py_ssize_t n = PyList_GET_SIZE(c->c_stack) - 1; if (n >= 0) { PyObject *capsule = PyList_GET_ITEM(c->c_stack, n); c->u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, CAPSULE_NAME); assert(c->u); /* we are deleting from a list so this really shouldn't fail */ if (PySequence_DelItem(c->c_stack, n) < 0) { _PyErr_WriteUnraisableMsg("on removing the last compiler " "stack item", NULL); } } else { c->u = NULL; } PyErr_SetRaisedException(exc); } /* Search if variable annotations are present statically in a block. */ static bool find_ann(asdl_stmt_seq *stmts) { int i, j, res = 0; stmt_ty st; for (i = 0; i < asdl_seq_LEN(stmts); i++) { st = (stmt_ty)asdl_seq_GET(stmts, i); switch (st->kind) { case AnnAssign_kind: return true; case For_kind: res = find_ann(st->v.For.body) || find_ann(st->v.For.orelse); break; case AsyncFor_kind: res = find_ann(st->v.AsyncFor.body) || find_ann(st->v.AsyncFor.orelse); break; case While_kind: res = find_ann(st->v.While.body) || find_ann(st->v.While.orelse); break; case If_kind: res = find_ann(st->v.If.body) || find_ann(st->v.If.orelse); break; case With_kind: res = find_ann(st->v.With.body); break; case AsyncWith_kind: res = find_ann(st->v.AsyncWith.body); break; case Try_kind: for (j = 0; j < asdl_seq_LEN(st->v.Try.handlers); j++) { excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET( st->v.Try.handlers, j); if (find_ann(handler->v.ExceptHandler.body)) { return true; } } res = find_ann(st->v.Try.body) || find_ann(st->v.Try.finalbody) || find_ann(st->v.Try.orelse); break; case TryStar_kind: for (j = 0; j < asdl_seq_LEN(st->v.TryStar.handlers); j++) { excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET( st->v.TryStar.handlers, j); if (find_ann(handler->v.ExceptHandler.body)) { return true; } } res = find_ann(st->v.TryStar.body) || find_ann(st->v.TryStar.finalbody) || find_ann(st->v.TryStar.orelse); break; case Match_kind: for (j = 0; j < asdl_seq_LEN(st->v.Match.cases); j++) { match_case_ty match_case = (match_case_ty)asdl_seq_GET( st->v.Match.cases, j); if (find_ann(match_case->body)) { return true; } } break; default: res = false; break; } if (res) { break; } } return res; } /* * Frame block handling functions */ static int compiler_push_fblock(struct compiler *c, location loc, enum fblocktype t, jump_target_label block_label, jump_target_label exit, void *datum) { struct fblockinfo *f; if (c->u->u_nfblocks >= CO_MAXBLOCKS) { return compiler_error(c, loc, "too many statically nested blocks"); } f = &c->u->u_fblock[c->u->u_nfblocks++]; f->fb_type = t; f->fb_block = block_label; f->fb_exit = exit; f->fb_datum = datum; return SUCCESS; } static void compiler_pop_fblock(struct compiler *c, enum fblocktype t, jump_target_label block_label) { struct compiler_unit *u = c->u; assert(u->u_nfblocks > 0); u->u_nfblocks--; assert(u->u_fblock[u->u_nfblocks].fb_type == t); assert(SAME_LABEL(u->u_fblock[u->u_nfblocks].fb_block, block_label)); } static int compiler_call_exit_with_nones(struct compiler *c, location loc) { ADDOP_LOAD_CONST(c, loc, Py_None); ADDOP_LOAD_CONST(c, loc, Py_None); ADDOP_LOAD_CONST(c, loc, Py_None); ADDOP_I(c, loc, CALL, 2); return SUCCESS; } static int compiler_add_yield_from(struct compiler *c, location loc, int await) { NEW_JUMP_TARGET_LABEL(c, send); NEW_JUMP_TARGET_LABEL(c, fail); NEW_JUMP_TARGET_LABEL(c, exit); USE_LABEL(c, send); ADDOP_JUMP(c, loc, SEND, exit); // Set up a virtual try/except to handle when StopIteration is raised during // a close or throw call. The only way YIELD_VALUE raises if they do! ADDOP_JUMP(c, loc, SETUP_FINALLY, fail); ADDOP_I(c, loc, YIELD_VALUE, 0); ADDOP(c, NO_LOCATION, POP_BLOCK); ADDOP_I(c, loc, RESUME, await ? 3 : 2); ADDOP_JUMP(c, loc, JUMP_NO_INTERRUPT, send); USE_LABEL(c, fail); ADDOP(c, loc, CLEANUP_THROW); USE_LABEL(c, exit); ADDOP(c, loc, END_SEND); return SUCCESS; } static int compiler_pop_except_and_reraise(struct compiler *c, location loc) { /* Stack contents * [exc_info, lasti, exc] COPY 3 * [exc_info, lasti, exc, exc_info] POP_EXCEPT * [exc_info, lasti, exc] RERAISE 1 * (exception_unwind clears the stack) */ ADDOP_I(c, loc, COPY, 3); ADDOP(c, loc, POP_EXCEPT); ADDOP_I(c, loc, RERAISE, 1); return SUCCESS; } /* Unwind a frame block. If preserve_tos is true, the TOS before * popping the blocks will be restored afterwards, unless another * return, break or continue is found. In which case, the TOS will * be popped. */ static int compiler_unwind_fblock(struct compiler *c, location *ploc, struct fblockinfo *info, int preserve_tos) { switch (info->fb_type) { case WHILE_LOOP: case EXCEPTION_HANDLER: case EXCEPTION_GROUP_HANDLER: case ASYNC_COMPREHENSION_GENERATOR: return SUCCESS; case FOR_LOOP: /* Pop the iterator */ if (preserve_tos) { ADDOP_I(c, *ploc, SWAP, 2); } ADDOP(c, *ploc, POP_TOP); return SUCCESS; case TRY_EXCEPT: ADDOP(c, *ploc, POP_BLOCK); return SUCCESS; case FINALLY_TRY: /* This POP_BLOCK gets the line number of the unwinding statement */ ADDOP(c, *ploc, POP_BLOCK); if (preserve_tos) { RETURN_IF_ERROR( compiler_push_fblock(c, *ploc, POP_VALUE, NO_LABEL, NO_LABEL, NULL)); } /* Emit the finally block */ VISIT_SEQ(c, stmt, info->fb_datum); if (preserve_tos) { compiler_pop_fblock(c, POP_VALUE, NO_LABEL); } /* The finally block should appear to execute after the * statement causing the unwinding, so make the unwinding * instruction artificial */ *ploc = NO_LOCATION; return SUCCESS; case FINALLY_END: if (preserve_tos) { ADDOP_I(c, *ploc, SWAP, 2); } ADDOP(c, *ploc, POP_TOP); /* exc_value */ if (preserve_tos) { ADDOP_I(c, *ploc, SWAP, 2); } ADDOP(c, *ploc, POP_BLOCK); ADDOP(c, *ploc, POP_EXCEPT); return SUCCESS; case WITH: case ASYNC_WITH: *ploc = LOC((stmt_ty)info->fb_datum); ADDOP(c, *ploc, POP_BLOCK); if (preserve_tos) { ADDOP_I(c, *ploc, SWAP, 2); } RETURN_IF_ERROR(compiler_call_exit_with_nones(c, *ploc)); if (info->fb_type == ASYNC_WITH) { ADDOP_I(c, *ploc, GET_AWAITABLE, 2); ADDOP_LOAD_CONST(c, *ploc, Py_None); ADD_YIELD_FROM(c, *ploc, 1); } ADDOP(c, *ploc, POP_TOP); /* The exit block should appear to execute after the * statement causing the unwinding, so make the unwinding * instruction artificial */ *ploc = NO_LOCATION; return SUCCESS; case HANDLER_CLEANUP: { if (info->fb_datum) { ADDOP(c, *ploc, POP_BLOCK); } if (preserve_tos) { ADDOP_I(c, *ploc, SWAP, 2); } ADDOP(c, *ploc, POP_BLOCK); ADDOP(c, *ploc, POP_EXCEPT); if (info->fb_datum) { ADDOP_LOAD_CONST(c, *ploc, Py_None); RETURN_IF_ERROR(compiler_nameop(c, *ploc, info->fb_datum, Store)); RETURN_IF_ERROR(compiler_nameop(c, *ploc, info->fb_datum, Del)); } return SUCCESS; } case POP_VALUE: { if (preserve_tos) { ADDOP_I(c, *ploc, SWAP, 2); } ADDOP(c, *ploc, POP_TOP); return SUCCESS; } } Py_UNREACHABLE(); } /** Unwind block stack. If loop is not NULL, then stop when the first loop is encountered. */ static int compiler_unwind_fblock_stack(struct compiler *c, location *ploc, int preserve_tos, struct fblockinfo **loop) { if (c->u->u_nfblocks == 0) { return SUCCESS; } struct fblockinfo *top = &c->u->u_fblock[c->u->u_nfblocks-1]; if (top->fb_type == EXCEPTION_GROUP_HANDLER) { return compiler_error( c, *ploc, "'break', 'continue' and 'return' cannot appear in an except* block"); } if (loop != NULL && (top->fb_type == WHILE_LOOP || top->fb_type == FOR_LOOP)) { *loop = top; return SUCCESS; } struct fblockinfo copy = *top; c->u->u_nfblocks--; RETURN_IF_ERROR(compiler_unwind_fblock(c, ploc, ©, preserve_tos)); RETURN_IF_ERROR(compiler_unwind_fblock_stack(c, ploc, preserve_tos, loop)); c->u->u_fblock[c->u->u_nfblocks] = copy; c->u->u_nfblocks++; return SUCCESS; } /* Compile a sequence of statements, checking for a docstring and for annotations. */ static int compiler_body(struct compiler *c, location loc, asdl_stmt_seq *stmts) { int i = 0; stmt_ty st; PyObject *docstring; /* Set current line number to the line number of first statement. This way line number for SETUP_ANNOTATIONS will always coincide with the line number of first "real" statement in module. If body is empty, then lineno will be set later in optimize_and_assemble. */ if (c->u->u_scope_type == COMPILER_SCOPE_MODULE && asdl_seq_LEN(stmts)) { st = (stmt_ty)asdl_seq_GET(stmts, 0); loc = LOC(st); } /* Every annotated class and module should have __annotations__. */ if (find_ann(stmts)) { ADDOP(c, loc, SETUP_ANNOTATIONS); } if (!asdl_seq_LEN(stmts)) { return SUCCESS; } /* if not -OO mode, set docstring */ if (c->c_optimize < 2) { docstring = _PyAST_GetDocString(stmts); if (docstring) { i = 1; st = (stmt_ty)asdl_seq_GET(stmts, 0); assert(st->kind == Expr_kind); VISIT(c, expr, st->v.Expr.value); RETURN_IF_ERROR(compiler_nameop(c, NO_LOCATION, &_Py_ID(__doc__), Store)); } } for (; i < asdl_seq_LEN(stmts); i++) { VISIT(c, stmt, (stmt_ty)asdl_seq_GET(stmts, i)); } return SUCCESS; } static int compiler_codegen(struct compiler *c, mod_ty mod) { _Py_DECLARE_STR(anon_module, ""); RETURN_IF_ERROR( compiler_enter_scope(c, &_Py_STR(anon_module), COMPILER_SCOPE_MODULE, mod, 1)); location loc = LOCATION(1, 1, 0, 0); switch (mod->kind) { case Module_kind: if (compiler_body(c, loc, mod->v.Module.body) < 0) { compiler_exit_scope(c); return ERROR; } break; case Interactive_kind: if (find_ann(mod->v.Interactive.body)) { ADDOP(c, loc, SETUP_ANNOTATIONS); } c->c_interactive = 1; VISIT_SEQ_IN_SCOPE(c, stmt, mod->v.Interactive.body); break; case Expression_kind: VISIT_IN_SCOPE(c, expr, mod->v.Expression.body); break; default: PyErr_Format(PyExc_SystemError, "module kind %d should not be possible", mod->kind); return ERROR; } return SUCCESS; } static PyCodeObject * compiler_mod(struct compiler *c, mod_ty mod) { int addNone = mod->kind != Expression_kind; if (compiler_codegen(c, mod) < 0) { return NULL; } PyCodeObject *co = optimize_and_assemble(c, addNone); compiler_exit_scope(c); return co; } /* The test for LOCAL must come before the test for FREE in order to handle classes where name is both local and free. The local var is a method and the free var is a free var referenced within a method. */ static int get_ref_type(struct compiler *c, PyObject *name) { int scope; if (c->u->u_scope_type == COMPILER_SCOPE_CLASS && (_PyUnicode_EqualToASCIIString(name, "__class__") || _PyUnicode_EqualToASCIIString(name, "__classdict__"))) { return CELL; } scope = _PyST_GetScope(c->u->u_ste, name); if (scope == 0) { PyErr_Format(PyExc_SystemError, "_PyST_GetScope(name=%R) failed: " "unknown scope in unit %S (%R); " "symbols: %R; locals: %R; globals: %R", name, c->u->u_metadata.u_name, c->u->u_ste->ste_id, c->u->u_ste->ste_symbols, c->u->u_metadata.u_varnames, c->u->u_metadata.u_names); return ERROR; } return scope; } static int compiler_lookup_arg(PyObject *dict, PyObject *name) { PyObject *v = PyDict_GetItemWithError(dict, name); if (v == NULL) { return ERROR; } return PyLong_AS_LONG(v); } static int compiler_make_closure(struct compiler *c, location loc, PyCodeObject *co, Py_ssize_t flags) { if (co->co_nfreevars) { int i = PyCode_GetFirstFree(co); for (; i < co->co_nlocalsplus; ++i) { /* Bypass com_addop_varname because it will generate LOAD_DEREF but LOAD_CLOSURE is needed. */ PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i); /* Special case: If a class contains a method with a free variable that has the same name as a method, the name will be considered free *and* local in the class. It should be handled by the closure, as well as by the normal name lookup logic. */ int reftype = get_ref_type(c, name); if (reftype == -1) { return ERROR; } int arg; if (reftype == CELL) { arg = compiler_lookup_arg(c->u->u_metadata.u_cellvars, name); } else { arg = compiler_lookup_arg(c->u->u_metadata.u_freevars, name); } if (arg == -1) { PyObject *freevars = _PyCode_GetFreevars(co); if (freevars == NULL) { PyErr_Clear(); } PyErr_Format(PyExc_SystemError, "compiler_lookup_arg(name=%R) with reftype=%d failed in %S; " "freevars of code %S: %R", name, reftype, c->u->u_metadata.u_name, co->co_name, freevars); Py_DECREF(freevars); return ERROR; } ADDOP_I(c, loc, LOAD_CLOSURE, arg); } flags |= MAKE_FUNCTION_CLOSURE; ADDOP_I(c, loc, BUILD_TUPLE, co->co_nfreevars); } ADDOP_LOAD_CONST(c, loc, (PyObject*)co); ADDOP_I(c, loc, MAKE_FUNCTION, flags); return SUCCESS; } static int compiler_decorators(struct compiler *c, asdl_expr_seq* decos) { if (!decos) { return SUCCESS; } for (Py_ssize_t i = 0; i < asdl_seq_LEN(decos); i++) { VISIT(c, expr, (expr_ty)asdl_seq_GET(decos, i)); } return SUCCESS; } static int compiler_apply_decorators(struct compiler *c, asdl_expr_seq* decos) { if (!decos) { return SUCCESS; } for (Py_ssize_t i = asdl_seq_LEN(decos) - 1; i > -1; i--) { location loc = LOC((expr_ty)asdl_seq_GET(decos, i)); ADDOP_I(c, loc, CALL, 0); } return SUCCESS; } static int compiler_visit_kwonlydefaults(struct compiler *c, location loc, asdl_arg_seq *kwonlyargs, asdl_expr_seq *kw_defaults) { /* Push a dict of keyword-only default values. Return -1 on error, 0 if no dict pushed, 1 if a dict is pushed. */ int i; PyObject *keys = NULL; for (i = 0; i < asdl_seq_LEN(kwonlyargs); i++) { arg_ty arg = asdl_seq_GET(kwonlyargs, i); expr_ty default_ = asdl_seq_GET(kw_defaults, i); if (default_) { PyObject *mangled = _Py_Mangle(c->u->u_private, arg->arg); if (!mangled) { goto error; } if (keys == NULL) { keys = PyList_New(1); if (keys == NULL) { Py_DECREF(mangled); return ERROR; } PyList_SET_ITEM(keys, 0, mangled); } else { int res = PyList_Append(keys, mangled); Py_DECREF(mangled); if (res == -1) { goto error; } } if (compiler_visit_expr(c, default_) < 0) { goto error; } } } if (keys != NULL) { Py_ssize_t default_count = PyList_GET_SIZE(keys); PyObject *keys_tuple = PyList_AsTuple(keys); Py_DECREF(keys); ADDOP_LOAD_CONST_NEW(c, loc, keys_tuple); ADDOP_I(c, loc, BUILD_CONST_KEY_MAP, default_count); assert(default_count > 0); return 1; } else { return 0; } error: Py_XDECREF(keys); return ERROR; } static int compiler_visit_annexpr(struct compiler *c, expr_ty annotation) { location loc = LOC(annotation); ADDOP_LOAD_CONST_NEW(c, loc, _PyAST_ExprAsUnicode(annotation)); return SUCCESS; } static int compiler_visit_argannotation(struct compiler *c, identifier id, expr_ty annotation, Py_ssize_t *annotations_len, location loc) { if (!annotation) { return SUCCESS; } PyObject *mangled = _Py_Mangle(c->u->u_private, id); if (!mangled) { return ERROR; } ADDOP_LOAD_CONST(c, loc, mangled); Py_DECREF(mangled); if (c->c_future.ff_features & CO_FUTURE_ANNOTATIONS) { VISIT(c, annexpr, annotation); } else { if (annotation->kind == Starred_kind) { // *args: *Ts (where Ts is a TypeVarTuple). // Do [annotation_value] = [*Ts]. // (Note that in theory we could end up here even for an argument // other than *args, but in practice the grammar doesn't allow it.) VISIT(c, expr, annotation->v.Starred.value); ADDOP_I(c, loc, UNPACK_SEQUENCE, (Py_ssize_t) 1); } else { VISIT(c, expr, annotation); } } *annotations_len += 2; return SUCCESS; } static int compiler_visit_argannotations(struct compiler *c, asdl_arg_seq* args, Py_ssize_t *annotations_len, location loc) { int i; for (i = 0; i < asdl_seq_LEN(args); i++) { arg_ty arg = (arg_ty)asdl_seq_GET(args, i); RETURN_IF_ERROR( compiler_visit_argannotation( c, arg->arg, arg->annotation, annotations_len, loc)); } return SUCCESS; } static int compiler_visit_annotations(struct compiler *c, location loc, arguments_ty args, expr_ty returns) { /* Push arg annotation names and values. The expressions are evaluated out-of-order wrt the source code. Return -1 on error, 0 if no annotations pushed, 1 if a annotations is pushed. */ Py_ssize_t annotations_len = 0; RETURN_IF_ERROR( compiler_visit_argannotations(c, args->args, &annotations_len, loc)); RETURN_IF_ERROR( compiler_visit_argannotations(c, args->posonlyargs, &annotations_len, loc)); if (args->vararg && args->vararg->annotation) { RETURN_IF_ERROR( compiler_visit_argannotation(c, args->vararg->arg, args->vararg->annotation, &annotations_len, loc)); } RETURN_IF_ERROR( compiler_visit_argannotations(c, args->kwonlyargs, &annotations_len, loc)); if (args->kwarg && args->kwarg->annotation) { RETURN_IF_ERROR( compiler_visit_argannotation(c, args->kwarg->arg, args->kwarg->annotation, &annotations_len, loc)); } RETURN_IF_ERROR( compiler_visit_argannotation(c, &_Py_ID(return), returns, &annotations_len, loc)); if (annotations_len) { ADDOP_I(c, loc, BUILD_TUPLE, annotations_len); return 1; } return 0; } static int compiler_visit_defaults(struct compiler *c, arguments_ty args, location loc) { VISIT_SEQ(c, expr, args->defaults); ADDOP_I(c, loc, BUILD_TUPLE, asdl_seq_LEN(args->defaults)); return SUCCESS; } static Py_ssize_t compiler_default_arguments(struct compiler *c, location loc, arguments_ty args) { Py_ssize_t funcflags = 0; if (args->defaults && asdl_seq_LEN(args->defaults) > 0) { RETURN_IF_ERROR(compiler_visit_defaults(c, args, loc)); funcflags |= MAKE_FUNCTION_DEFAULTS; } if (args->kwonlyargs) { int res = compiler_visit_kwonlydefaults(c, loc, args->kwonlyargs, args->kw_defaults); RETURN_IF_ERROR(res); if (res > 0) { funcflags |= MAKE_FUNCTION_KWDEFAULTS; } } return funcflags; } static bool forbidden_name(struct compiler *c, location loc, identifier name, expr_context_ty ctx) { if (ctx == Store && _PyUnicode_EqualToASCIIString(name, "__debug__")) { compiler_error(c, loc, "cannot assign to __debug__"); return true; } if (ctx == Del && _PyUnicode_EqualToASCIIString(name, "__debug__")) { compiler_error(c, loc, "cannot delete __debug__"); return true; } return false; } static int compiler_check_debug_one_arg(struct compiler *c, arg_ty arg) { if (arg != NULL) { if (forbidden_name(c, LOC(arg), arg->arg, Store)) { return ERROR; } } return SUCCESS; } static int compiler_check_debug_args_seq(struct compiler *c, asdl_arg_seq *args) { if (args != NULL) { for (Py_ssize_t i = 0, n = asdl_seq_LEN(args); i < n; i++) { RETURN_IF_ERROR( compiler_check_debug_one_arg(c, asdl_seq_GET(args, i))); } } return SUCCESS; } static int compiler_check_debug_args(struct compiler *c, arguments_ty args) { RETURN_IF_ERROR(compiler_check_debug_args_seq(c, args->posonlyargs)); RETURN_IF_ERROR(compiler_check_debug_args_seq(c, args->args)); RETURN_IF_ERROR(compiler_check_debug_one_arg(c, args->vararg)); RETURN_IF_ERROR(compiler_check_debug_args_seq(c, args->kwonlyargs)); RETURN_IF_ERROR(compiler_check_debug_one_arg(c, args->kwarg)); return SUCCESS; } static int wrap_in_stopiteration_handler(struct compiler *c) { NEW_JUMP_TARGET_LABEL(c, handler); /* Insert SETUP_CLEANUP at start */ RETURN_IF_ERROR( instr_sequence_insert_instruction( INSTR_SEQUENCE(c), 0, SETUP_CLEANUP, handler.id, NO_LOCATION)); ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); ADDOP(c, NO_LOCATION, RETURN_VALUE); USE_LABEL(c, handler); ADDOP_I(c, NO_LOCATION, CALL_INTRINSIC_1, INTRINSIC_STOPITERATION_ERROR); ADDOP_I(c, NO_LOCATION, RERAISE, 1); return SUCCESS; } static int compiler_type_params(struct compiler *c, asdl_type_param_seq *type_params) { if (!type_params) { return SUCCESS; } Py_ssize_t n = asdl_seq_LEN(type_params); for (Py_ssize_t i = 0; i < n; i++) { type_param_ty typeparam = asdl_seq_GET(type_params, i); location loc = LOC(typeparam); switch(typeparam->kind) { case TypeVar_kind: ADDOP_LOAD_CONST(c, loc, typeparam->v.TypeVar.name); if (typeparam->v.TypeVar.bound) { expr_ty bound = typeparam->v.TypeVar.bound; if (compiler_enter_scope(c, typeparam->v.TypeVar.name, COMPILER_SCOPE_TYPEPARAMS, (void *)typeparam, bound->lineno) == -1) { return ERROR; } VISIT_IN_SCOPE(c, expr, bound); ADDOP_IN_SCOPE(c, loc, RETURN_VALUE); PyCodeObject *co = optimize_and_assemble(c, 1); compiler_exit_scope(c); if (co == NULL) { return ERROR; } if (compiler_make_closure(c, loc, co, 0) < 0) { Py_DECREF(co); return ERROR; } Py_DECREF(co); int intrinsic = bound->kind == Tuple_kind ? INTRINSIC_TYPEVAR_WITH_CONSTRAINTS : INTRINSIC_TYPEVAR_WITH_BOUND; ADDOP_I(c, loc, CALL_INTRINSIC_2, intrinsic); } else { ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_TYPEVAR); } ADDOP_I(c, loc, COPY, 1); RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.TypeVar.name, Store)); break; case TypeVarTuple_kind: ADDOP_LOAD_CONST(c, loc, typeparam->v.TypeVarTuple.name); ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_TYPEVARTUPLE); ADDOP_I(c, loc, COPY, 1); RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.TypeVarTuple.name, Store)); break; case ParamSpec_kind: ADDOP_LOAD_CONST(c, loc, typeparam->v.ParamSpec.name); ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_PARAMSPEC); ADDOP_I(c, loc, COPY, 1); RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.ParamSpec.name, Store)); break; } } ADDOP_I(c, LOC(asdl_seq_GET(type_params, 0)), BUILD_TUPLE, n); return SUCCESS; } static int compiler_function_body(struct compiler *c, stmt_ty s, int is_async, Py_ssize_t funcflags, int firstlineno) { PyObject *docstring = NULL; arguments_ty args; identifier name; asdl_stmt_seq *body; int scope_type; if (is_async) { assert(s->kind == AsyncFunctionDef_kind); args = s->v.AsyncFunctionDef.args; name = s->v.AsyncFunctionDef.name; body = s->v.AsyncFunctionDef.body; scope_type = COMPILER_SCOPE_ASYNC_FUNCTION; } else { assert(s->kind == FunctionDef_kind); args = s->v.FunctionDef.args; name = s->v.FunctionDef.name; body = s->v.FunctionDef.body; scope_type = COMPILER_SCOPE_FUNCTION; } RETURN_IF_ERROR( compiler_enter_scope(c, name, scope_type, (void *)s, firstlineno)); /* if not -OO mode, add docstring */ if (c->c_optimize < 2) { docstring = _PyAST_GetDocString(body); } if (compiler_add_const(c->c_const_cache, c->u, docstring ? docstring : Py_None) < 0) { compiler_exit_scope(c); return ERROR; } c->u->u_metadata.u_argcount = asdl_seq_LEN(args->args); c->u->u_metadata.u_posonlyargcount = asdl_seq_LEN(args->posonlyargs); c->u->u_metadata.u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs); for (Py_ssize_t i = docstring ? 1 : 0; i < asdl_seq_LEN(body); i++) { VISIT_IN_SCOPE(c, stmt, (stmt_ty)asdl_seq_GET(body, i)); } if (c->u->u_ste->ste_coroutine || c->u->u_ste->ste_generator) { if (wrap_in_stopiteration_handler(c) < 0) { compiler_exit_scope(c); return ERROR; } } PyCodeObject *co = optimize_and_assemble(c, 1); compiler_exit_scope(c); if (co == NULL) { Py_XDECREF(co); return ERROR; } location loc = LOC(s); if (compiler_make_closure(c, loc, co, funcflags) < 0) { Py_DECREF(co); return ERROR; } Py_DECREF(co); return SUCCESS; } static int compiler_function(struct compiler *c, stmt_ty s, int is_async) { arguments_ty args; expr_ty returns; identifier name; asdl_expr_seq *decos; asdl_type_param_seq *type_params; Py_ssize_t funcflags; int annotations; int firstlineno; if (is_async) { assert(s->kind == AsyncFunctionDef_kind); args = s->v.AsyncFunctionDef.args; returns = s->v.AsyncFunctionDef.returns; decos = s->v.AsyncFunctionDef.decorator_list; name = s->v.AsyncFunctionDef.name; type_params = s->v.AsyncFunctionDef.type_params; } else { assert(s->kind == FunctionDef_kind); args = s->v.FunctionDef.args; returns = s->v.FunctionDef.returns; decos = s->v.FunctionDef.decorator_list; name = s->v.FunctionDef.name; type_params = s->v.FunctionDef.type_params; } RETURN_IF_ERROR(compiler_check_debug_args(c, args)); RETURN_IF_ERROR(compiler_decorators(c, decos)); firstlineno = s->lineno; if (asdl_seq_LEN(decos)) { firstlineno = ((expr_ty)asdl_seq_GET(decos, 0))->lineno; } location loc = LOC(s); int is_generic = asdl_seq_LEN(type_params) > 0; if (is_generic) { // Used by the CALL to the type parameters function. ADDOP(c, loc, PUSH_NULL); } funcflags = compiler_default_arguments(c, loc, args); if (funcflags == -1) { return ERROR; } int num_typeparam_args = 0; if (is_generic) { if (funcflags & MAKE_FUNCTION_DEFAULTS) { num_typeparam_args += 1; } if (funcflags & MAKE_FUNCTION_KWDEFAULTS) { num_typeparam_args += 1; } if (num_typeparam_args == 2) { ADDOP_I(c, loc, SWAP, 2); } PyObject *type_params_name = PyUnicode_FromFormat("", name); if (!type_params_name) { return ERROR; } if (compiler_enter_scope(c, type_params_name, COMPILER_SCOPE_TYPEPARAMS, (void *)type_params, firstlineno) == -1) { Py_DECREF(type_params_name); return ERROR; } Py_DECREF(type_params_name); RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, type_params)); for (int i = 0; i < num_typeparam_args; i++) { RETURN_IF_ERROR_IN_SCOPE(c, codegen_addop_i(INSTR_SEQUENCE(c), LOAD_FAST, i, loc)); } } annotations = compiler_visit_annotations(c, loc, args, returns); if (annotations < 0) { if (is_generic) { compiler_exit_scope(c); } return ERROR; } if (annotations > 0) { funcflags |= MAKE_FUNCTION_ANNOTATIONS; } if (compiler_function_body(c, s, is_async, funcflags, firstlineno) < 0) { if (is_generic) { compiler_exit_scope(c); } return ERROR; } if (is_generic) { RETURN_IF_ERROR_IN_SCOPE(c, codegen_addop_i( INSTR_SEQUENCE(c), SWAP, 2, loc)); RETURN_IF_ERROR_IN_SCOPE(c, codegen_addop_i( INSTR_SEQUENCE(c), CALL_INTRINSIC_2, INTRINSIC_SET_FUNCTION_TYPE_PARAMS, loc)); c->u->u_metadata.u_argcount = num_typeparam_args; PyCodeObject *co = optimize_and_assemble(c, 0); compiler_exit_scope(c); if (co == NULL) { return ERROR; } if (compiler_make_closure(c, loc, co, 0) < 0) { Py_DECREF(co); return ERROR; } Py_DECREF(co); if (num_typeparam_args > 0) { ADDOP_I(c, loc, SWAP, num_typeparam_args + 1); } ADDOP_I(c, loc, CALL, num_typeparam_args); } RETURN_IF_ERROR(compiler_apply_decorators(c, decos)); return compiler_nameop(c, loc, name, Store); } static int compiler_set_type_params_in_class(struct compiler *c, location loc) { _Py_DECLARE_STR(type_params, ".type_params"); RETURN_IF_ERROR(compiler_nameop(c, loc, &_Py_STR(type_params), Load)); RETURN_IF_ERROR(compiler_nameop(c, loc, &_Py_ID(__type_params__), Store)); return 1; } static int compiler_class_body(struct compiler *c, stmt_ty s, int firstlineno) { /* ultimately generate code for: = __build_class__(, , *, **) where: is a zero arg function/closure created from the class body. It mutates its locals to build the class namespace. is the class name is the positional arguments and *varargs argument is the keyword arguments and **kwds argument This borrows from compiler_call. */ /* 1. compile the class body into a code object */ RETURN_IF_ERROR( compiler_enter_scope(c, s->v.ClassDef.name, COMPILER_SCOPE_CLASS, (void *)s, firstlineno)); location loc = LOCATION(firstlineno, firstlineno, 0, 0); /* use the class name for name mangling */ Py_XSETREF(c->u->u_private, Py_NewRef(s->v.ClassDef.name)); /* load (global) __name__ ... */ if (compiler_nameop(c, loc, &_Py_ID(__name__), Load) < 0) { compiler_exit_scope(c); return ERROR; } /* ... and store it as __module__ */ if (compiler_nameop(c, loc, &_Py_ID(__module__), Store) < 0) { compiler_exit_scope(c); return ERROR; } assert(c->u->u_metadata.u_qualname); ADDOP_LOAD_CONST(c, loc, c->u->u_metadata.u_qualname); if (compiler_nameop(c, loc, &_Py_ID(__qualname__), Store) < 0) { compiler_exit_scope(c); return ERROR; } asdl_type_param_seq *type_params = s->v.ClassDef.type_params; if (asdl_seq_LEN(type_params) > 0) { if (!compiler_set_type_params_in_class(c, loc)) { compiler_exit_scope(c); return ERROR; } } if (c->u->u_ste->ste_needs_classdict) { ADDOP(c, loc, LOAD_LOCALS); // We can't use compiler_nameop here because we need to generate a // STORE_DEREF in a class namespace, and compiler_nameop() won't do // that by default. PyObject *cellvars = c->u->u_metadata.u_cellvars; if (compiler_addop_o(c->u, loc, STORE_DEREF, cellvars, &_Py_ID(__classdict__)) < 0) { compiler_exit_scope(c); return ERROR; } } /* compile the body proper */ if (compiler_body(c, loc, s->v.ClassDef.body) < 0) { compiler_exit_scope(c); return ERROR; } /* The following code is artificial */ /* Set __classdictcell__ if necessary */ if (c->u->u_ste->ste_needs_classdict) { /* Store __classdictcell__ into class namespace */ int i = compiler_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__classdict__)); if (i < 0) { compiler_exit_scope(c); return ERROR; } ADDOP_I(c, NO_LOCATION, LOAD_CLOSURE, i); if (compiler_nameop(c, NO_LOCATION, &_Py_ID(__classdictcell__), Store) < 0) { compiler_exit_scope(c); return ERROR; } } /* Return __classcell__ if it is referenced, otherwise return None */ if (c->u->u_ste->ste_needs_class_closure) { /* Store __classcell__ into class namespace & return it */ int i = compiler_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__class__)); if (i < 0) { compiler_exit_scope(c); return ERROR; } ADDOP_I(c, NO_LOCATION, LOAD_CLOSURE, i); ADDOP_I(c, NO_LOCATION, COPY, 1); if (compiler_nameop(c, NO_LOCATION, &_Py_ID(__classcell__), Store) < 0) { compiler_exit_scope(c); return ERROR; } } else { /* No methods referenced __class__, so just return None */ ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); } ADDOP_IN_SCOPE(c, NO_LOCATION, RETURN_VALUE); /* create the code object */ PyCodeObject *co = optimize_and_assemble(c, 1); /* leave the new scope */ compiler_exit_scope(c); if (co == NULL) { return ERROR; } /* 2. load the 'build_class' function */ // these instructions should be attributed to the class line, // not a decorator line loc = LOC(s); ADDOP(c, loc, PUSH_NULL); ADDOP(c, loc, LOAD_BUILD_CLASS); /* 3. load a function (or closure) made from the code object */ if (compiler_make_closure(c, loc, co, 0) < 0) { Py_DECREF(co); return ERROR; } Py_DECREF(co); /* 4. load class name */ ADDOP_LOAD_CONST(c, loc, s->v.ClassDef.name); return SUCCESS; } static int compiler_class(struct compiler *c, stmt_ty s) { asdl_expr_seq *decos = s->v.ClassDef.decorator_list; RETURN_IF_ERROR(compiler_decorators(c, decos)); int firstlineno = s->lineno; if (asdl_seq_LEN(decos)) { firstlineno = ((expr_ty)asdl_seq_GET(decos, 0))->lineno; } location loc = LOC(s); asdl_type_param_seq *type_params = s->v.ClassDef.type_params; int is_generic = asdl_seq_LEN(type_params) > 0; if (is_generic) { Py_XSETREF(c->u->u_private, Py_NewRef(s->v.ClassDef.name)); ADDOP(c, loc, PUSH_NULL); PyObject *type_params_name = PyUnicode_FromFormat("", s->v.ClassDef.name); if (!type_params_name) { return ERROR; } if (compiler_enter_scope(c, type_params_name, COMPILER_SCOPE_TYPEPARAMS, (void *)type_params, firstlineno) == -1) { Py_DECREF(type_params_name); return ERROR; } Py_DECREF(type_params_name); RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, type_params)); _Py_DECLARE_STR(type_params, ".type_params"); RETURN_IF_ERROR_IN_SCOPE(c, compiler_nameop(c, loc, &_Py_STR(type_params), Store)); } if (compiler_class_body(c, s, firstlineno) < 0) { if (is_generic) { compiler_exit_scope(c); } return ERROR; } /* generate the rest of the code for the call */ if (is_generic) { _Py_DECLARE_STR(type_params, ".type_params"); _Py_DECLARE_STR(generic_base, ".generic_base"); RETURN_IF_ERROR_IN_SCOPE(c, compiler_nameop(c, loc, &_Py_STR(type_params), Load)); RETURN_IF_ERROR_IN_SCOPE( c, codegen_addop_i(INSTR_SEQUENCE(c), CALL_INTRINSIC_1, INTRINSIC_SUBSCRIPT_GENERIC, loc) ) RETURN_IF_ERROR_IN_SCOPE(c, compiler_nameop(c, loc, &_Py_STR(generic_base), Store)); Py_ssize_t original_len = asdl_seq_LEN(s->v.ClassDef.bases); asdl_expr_seq *bases = _Py_asdl_expr_seq_new( original_len + 1, c->c_arena); if (bases == NULL) { compiler_exit_scope(c); return ERROR; } for (Py_ssize_t i = 0; i < original_len; i++) { asdl_seq_SET(bases, i, asdl_seq_GET(s->v.ClassDef.bases, i)); } expr_ty name_node = _PyAST_Name( &_Py_STR(generic_base), Load, loc.lineno, loc.col_offset, loc.end_lineno, loc.end_col_offset, c->c_arena ); if (name_node == NULL) { compiler_exit_scope(c); return ERROR; } asdl_seq_SET(bases, original_len, name_node); RETURN_IF_ERROR_IN_SCOPE(c, compiler_call_helper(c, loc, 2, bases, s->v.ClassDef.keywords)); PyCodeObject *co = optimize_and_assemble(c, 0); compiler_exit_scope(c); if (co == NULL) { return ERROR; } if (compiler_make_closure(c, loc, co, 0) < 0) { Py_DECREF(co); return ERROR; } Py_DECREF(co); ADDOP_I(c, loc, CALL, 0); } else { RETURN_IF_ERROR(compiler_call_helper(c, loc, 2, s->v.ClassDef.bases, s->v.ClassDef.keywords)); } /* 6. apply decorators */ RETURN_IF_ERROR(compiler_apply_decorators(c, decos)); /* 7. store into */ RETURN_IF_ERROR(compiler_nameop(c, loc, s->v.ClassDef.name, Store)); return SUCCESS; } static int compiler_typealias_body(struct compiler *c, stmt_ty s) { location loc = LOC(s); PyObject *name = s->v.TypeAlias.name->v.Name.id; RETURN_IF_ERROR( compiler_enter_scope(c, name, COMPILER_SCOPE_FUNCTION, s, loc.lineno)); /* Make None the first constant, so the evaluate function can't have a docstring. */ RETURN_IF_ERROR(compiler_add_const(c->c_const_cache, c->u, Py_None)); VISIT_IN_SCOPE(c, expr, s->v.TypeAlias.value); ADDOP_IN_SCOPE(c, loc, RETURN_VALUE); PyCodeObject *co = optimize_and_assemble(c, 0); compiler_exit_scope(c); if (co == NULL) { return ERROR; } if (compiler_make_closure(c, loc, co, 0) < 0) { Py_DECREF(co); return ERROR; } Py_DECREF(co); ADDOP_I(c, loc, BUILD_TUPLE, 3); ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_TYPEALIAS); return SUCCESS; } static int compiler_typealias(struct compiler *c, stmt_ty s) { location loc = LOC(s); asdl_type_param_seq *type_params = s->v.TypeAlias.type_params; int is_generic = asdl_seq_LEN(type_params) > 0; PyObject *name = s->v.TypeAlias.name->v.Name.id; if (is_generic) { ADDOP(c, loc, PUSH_NULL); PyObject *type_params_name = PyUnicode_FromFormat("", name); if (!type_params_name) { return ERROR; } if (compiler_enter_scope(c, type_params_name, COMPILER_SCOPE_TYPEPARAMS, (void *)type_params, loc.lineno) == -1) { Py_DECREF(type_params_name); return ERROR; } Py_DECREF(type_params_name); RETURN_IF_ERROR_IN_SCOPE( c, compiler_addop_load_const(c->c_const_cache, c->u, loc, name) ); RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, type_params)); } else { ADDOP_LOAD_CONST(c, loc, name); ADDOP_LOAD_CONST(c, loc, Py_None); } if (compiler_typealias_body(c, s) < 0) { if (is_generic) { compiler_exit_scope(c); } return ERROR; } if (is_generic) { PyCodeObject *co = optimize_and_assemble(c, 0); compiler_exit_scope(c); if (co == NULL) { return ERROR; } if (compiler_make_closure(c, loc, co, 0) < 0) { Py_DECREF(co); return ERROR; } Py_DECREF(co); ADDOP_I(c, loc, CALL, 0); } RETURN_IF_ERROR(compiler_nameop(c, loc, name, Store)); return SUCCESS; } /* Return false if the expression is a constant value except named singletons. Return true otherwise. */ static bool check_is_arg(expr_ty e) { if (e->kind != Constant_kind) { return true; } PyObject *value = e->v.Constant.value; return (value == Py_None || value == Py_False || value == Py_True || value == Py_Ellipsis); } static PyTypeObject * infer_type(expr_ty e); /* Check operands of identity checks ("is" and "is not"). Emit a warning if any operand is a constant except named singletons. */ static int check_compare(struct compiler *c, expr_ty e) { Py_ssize_t i, n; bool left = check_is_arg(e->v.Compare.left); expr_ty left_expr = e->v.Compare.left; n = asdl_seq_LEN(e->v.Compare.ops); for (i = 0; i < n; i++) { cmpop_ty op = (cmpop_ty)asdl_seq_GET(e->v.Compare.ops, i); expr_ty right_expr = (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i); bool right = check_is_arg(right_expr); if (op == Is || op == IsNot) { if (!right || !left) { const char *msg = (op == Is) ? "\"is\" with '%.200s' literal. Did you mean \"==\"?" : "\"is not\" with '%.200s' literal. Did you mean \"!=\"?"; expr_ty literal = !left ? left_expr : right_expr; return compiler_warn( c, LOC(e), msg, infer_type(literal)->tp_name ); } } left = right; left_expr = right_expr; } return SUCCESS; } static const int compare_masks[] = { [Py_LT] = COMPARISON_LESS_THAN, [Py_LE] = COMPARISON_LESS_THAN | COMPARISON_EQUALS, [Py_EQ] = COMPARISON_EQUALS, [Py_NE] = COMPARISON_NOT_EQUALS, [Py_GT] = COMPARISON_GREATER_THAN, [Py_GE] = COMPARISON_GREATER_THAN | COMPARISON_EQUALS, }; static int compiler_addcompare(struct compiler *c, location loc, cmpop_ty op) { int cmp; switch (op) { case Eq: cmp = Py_EQ; break; case NotEq: cmp = Py_NE; break; case Lt: cmp = Py_LT; break; case LtE: cmp = Py_LE; break; case Gt: cmp = Py_GT; break; case GtE: cmp = Py_GE; break; case Is: ADDOP_I(c, loc, IS_OP, 0); return SUCCESS; case IsNot: ADDOP_I(c, loc, IS_OP, 1); return SUCCESS; case In: ADDOP_I(c, loc, CONTAINS_OP, 0); return SUCCESS; case NotIn: ADDOP_I(c, loc, CONTAINS_OP, 1); return SUCCESS; default: Py_UNREACHABLE(); } /* cmp goes in top bits of the oparg, while the low bits are used by quickened * versions of this opcode to store the comparison mask. */ ADDOP_I(c, loc, COMPARE_OP, (cmp << 4) | compare_masks[cmp]); return SUCCESS; } static int compiler_jump_if(struct compiler *c, location loc, expr_ty e, jump_target_label next, int cond) { switch (e->kind) { case UnaryOp_kind: if (e->v.UnaryOp.op == Not) { return compiler_jump_if(c, loc, e->v.UnaryOp.operand, next, !cond); } /* fallback to general implementation */ break; case BoolOp_kind: { asdl_expr_seq *s = e->v.BoolOp.values; Py_ssize_t i, n = asdl_seq_LEN(s) - 1; assert(n >= 0); int cond2 = e->v.BoolOp.op == Or; jump_target_label next2 = next; if (!cond2 != !cond) { NEW_JUMP_TARGET_LABEL(c, new_next2); next2 = new_next2; } for (i = 0; i < n; ++i) { RETURN_IF_ERROR( compiler_jump_if(c, loc, (expr_ty)asdl_seq_GET(s, i), next2, cond2)); } RETURN_IF_ERROR( compiler_jump_if(c, loc, (expr_ty)asdl_seq_GET(s, n), next, cond)); if (!SAME_LABEL(next2, next)) { USE_LABEL(c, next2); } return SUCCESS; } case IfExp_kind: { NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, next2); RETURN_IF_ERROR( compiler_jump_if(c, loc, e->v.IfExp.test, next2, 0)); RETURN_IF_ERROR( compiler_jump_if(c, loc, e->v.IfExp.body, next, cond)); ADDOP_JUMP(c, NO_LOCATION, JUMP, end); USE_LABEL(c, next2); RETURN_IF_ERROR( compiler_jump_if(c, loc, e->v.IfExp.orelse, next, cond)); USE_LABEL(c, end); return SUCCESS; } case Compare_kind: { Py_ssize_t n = asdl_seq_LEN(e->v.Compare.ops) - 1; if (n > 0) { RETURN_IF_ERROR(check_compare(c, e)); NEW_JUMP_TARGET_LABEL(c, cleanup); VISIT(c, expr, e->v.Compare.left); for (Py_ssize_t i = 0; i < n; i++) { VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); ADDOP_I(c, LOC(e), SWAP, 2); ADDOP_I(c, LOC(e), COPY, 2); ADDOP_COMPARE(c, LOC(e), asdl_seq_GET(e->v.Compare.ops, i)); ADDOP_JUMP(c, LOC(e), POP_JUMP_IF_FALSE, cleanup); } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n)); ADDOP_COMPARE(c, LOC(e), asdl_seq_GET(e->v.Compare.ops, n)); ADDOP_JUMP(c, LOC(e), cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next); NEW_JUMP_TARGET_LABEL(c, end); ADDOP_JUMP(c, NO_LOCATION, JUMP, end); USE_LABEL(c, cleanup); ADDOP(c, LOC(e), POP_TOP); if (!cond) { ADDOP_JUMP(c, NO_LOCATION, JUMP, next); } USE_LABEL(c, end); return SUCCESS; } /* fallback to general implementation */ break; } default: /* fallback to general implementation */ break; } /* general implementation */ VISIT(c, expr, e); ADDOP_JUMP(c, LOC(e), cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next); return SUCCESS; } static int compiler_ifexp(struct compiler *c, expr_ty e) { assert(e->kind == IfExp_kind); NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, next); RETURN_IF_ERROR( compiler_jump_if(c, LOC(e), e->v.IfExp.test, next, 0)); VISIT(c, expr, e->v.IfExp.body); ADDOP_JUMP(c, NO_LOCATION, JUMP, end); USE_LABEL(c, next); VISIT(c, expr, e->v.IfExp.orelse); USE_LABEL(c, end); return SUCCESS; } static int compiler_lambda(struct compiler *c, expr_ty e) { PyCodeObject *co; Py_ssize_t funcflags; arguments_ty args = e->v.Lambda.args; assert(e->kind == Lambda_kind); RETURN_IF_ERROR(compiler_check_debug_args(c, args)); location loc = LOC(e); funcflags = compiler_default_arguments(c, loc, args); if (funcflags == -1) { return ERROR; } _Py_DECLARE_STR(anon_lambda, ""); RETURN_IF_ERROR( compiler_enter_scope(c, &_Py_STR(anon_lambda), COMPILER_SCOPE_LAMBDA, (void *)e, e->lineno)); /* Make None the first constant, so the lambda can't have a docstring. */ RETURN_IF_ERROR(compiler_add_const(c->c_const_cache, c->u, Py_None)); c->u->u_metadata.u_argcount = asdl_seq_LEN(args->args); c->u->u_metadata.u_posonlyargcount = asdl_seq_LEN(args->posonlyargs); c->u->u_metadata.u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs); VISIT_IN_SCOPE(c, expr, e->v.Lambda.body); if (c->u->u_ste->ste_generator) { co = optimize_and_assemble(c, 0); } else { location loc = LOCATION(e->lineno, e->lineno, 0, 0); ADDOP_IN_SCOPE(c, loc, RETURN_VALUE); co = optimize_and_assemble(c, 1); } compiler_exit_scope(c); if (co == NULL) { return ERROR; } if (compiler_make_closure(c, loc, co, funcflags) < 0) { Py_DECREF(co); return ERROR; } Py_DECREF(co); return SUCCESS; } static int compiler_if(struct compiler *c, stmt_ty s) { jump_target_label next; assert(s->kind == If_kind); NEW_JUMP_TARGET_LABEL(c, end); if (asdl_seq_LEN(s->v.If.orelse)) { NEW_JUMP_TARGET_LABEL(c, orelse); next = orelse; } else { next = end; } RETURN_IF_ERROR( compiler_jump_if(c, LOC(s), s->v.If.test, next, 0)); VISIT_SEQ(c, stmt, s->v.If.body); if (asdl_seq_LEN(s->v.If.orelse)) { ADDOP_JUMP(c, NO_LOCATION, JUMP, end); USE_LABEL(c, next); VISIT_SEQ(c, stmt, s->v.If.orelse); } USE_LABEL(c, end); return SUCCESS; } static int compiler_for(struct compiler *c, stmt_ty s) { location loc = LOC(s); NEW_JUMP_TARGET_LABEL(c, start); NEW_JUMP_TARGET_LABEL(c, body); NEW_JUMP_TARGET_LABEL(c, cleanup); NEW_JUMP_TARGET_LABEL(c, end); RETURN_IF_ERROR(compiler_push_fblock(c, loc, FOR_LOOP, start, end, NULL)); VISIT(c, expr, s->v.For.iter); ADDOP(c, loc, GET_ITER); USE_LABEL(c, start); ADDOP_JUMP(c, loc, FOR_ITER, cleanup); USE_LABEL(c, body); VISIT(c, expr, s->v.For.target); VISIT_SEQ(c, stmt, s->v.For.body); /* Mark jump as artificial */ ADDOP_JUMP(c, NO_LOCATION, JUMP, start); USE_LABEL(c, cleanup); ADDOP(c, NO_LOCATION, END_FOR); compiler_pop_fblock(c, FOR_LOOP, start); VISIT_SEQ(c, stmt, s->v.For.orelse); USE_LABEL(c, end); return SUCCESS; } static int compiler_async_for(struct compiler *c, stmt_ty s) { location loc = LOC(s); if (IS_TOP_LEVEL_AWAIT(c)){ c->u->u_ste->ste_coroutine = 1; } else if (c->u->u_scope_type != COMPILER_SCOPE_ASYNC_FUNCTION) { return compiler_error(c, loc, "'async for' outside async function"); } NEW_JUMP_TARGET_LABEL(c, start); NEW_JUMP_TARGET_LABEL(c, except); NEW_JUMP_TARGET_LABEL(c, end); VISIT(c, expr, s->v.AsyncFor.iter); ADDOP(c, loc, GET_AITER); USE_LABEL(c, start); RETURN_IF_ERROR(compiler_push_fblock(c, loc, FOR_LOOP, start, end, NULL)); /* SETUP_FINALLY to guard the __anext__ call */ ADDOP_JUMP(c, loc, SETUP_FINALLY, except); ADDOP(c, loc, GET_ANEXT); ADDOP_LOAD_CONST(c, loc, Py_None); ADD_YIELD_FROM(c, loc, 1); ADDOP(c, loc, POP_BLOCK); /* for SETUP_FINALLY */ /* Success block for __anext__ */ VISIT(c, expr, s->v.AsyncFor.target); VISIT_SEQ(c, stmt, s->v.AsyncFor.body); /* Mark jump as artificial */ ADDOP_JUMP(c, NO_LOCATION, JUMP, start); compiler_pop_fblock(c, FOR_LOOP, start); /* Except block for __anext__ */ USE_LABEL(c, except); /* Use same line number as the iterator, * as the END_ASYNC_FOR succeeds the `for`, not the body. */ loc = LOC(s->v.AsyncFor.iter); ADDOP(c, loc, END_ASYNC_FOR); /* `else` block */ VISIT_SEQ(c, stmt, s->v.For.orelse); USE_LABEL(c, end); return SUCCESS; } static int compiler_while(struct compiler *c, stmt_ty s) { NEW_JUMP_TARGET_LABEL(c, loop); NEW_JUMP_TARGET_LABEL(c, body); NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, anchor); USE_LABEL(c, loop); RETURN_IF_ERROR(compiler_push_fblock(c, LOC(s), WHILE_LOOP, loop, end, NULL)); RETURN_IF_ERROR(compiler_jump_if(c, LOC(s), s->v.While.test, anchor, 0)); USE_LABEL(c, body); VISIT_SEQ(c, stmt, s->v.While.body); RETURN_IF_ERROR(compiler_jump_if(c, LOC(s), s->v.While.test, body, 1)); compiler_pop_fblock(c, WHILE_LOOP, loop); USE_LABEL(c, anchor); if (s->v.While.orelse) { VISIT_SEQ(c, stmt, s->v.While.orelse); } USE_LABEL(c, end); return SUCCESS; } static int compiler_return(struct compiler *c, stmt_ty s) { location loc = LOC(s); int preserve_tos = ((s->v.Return.value != NULL) && (s->v.Return.value->kind != Constant_kind)); if (!_PyST_IsFunctionLike(c->u->u_ste)) { return compiler_error(c, loc, "'return' outside function"); } if (s->v.Return.value != NULL && c->u->u_ste->ste_coroutine && c->u->u_ste->ste_generator) { return compiler_error(c, loc, "'return' with value in async generator"); } if (preserve_tos) { VISIT(c, expr, s->v.Return.value); } else { /* Emit instruction with line number for return value */ if (s->v.Return.value != NULL) { loc = LOC(s->v.Return.value); ADDOP(c, loc, NOP); } } if (s->v.Return.value == NULL || s->v.Return.value->lineno != s->lineno) { loc = LOC(s); ADDOP(c, loc, NOP); } RETURN_IF_ERROR(compiler_unwind_fblock_stack(c, &loc, preserve_tos, NULL)); if (s->v.Return.value == NULL) { ADDOP_LOAD_CONST(c, loc, Py_None); } else if (!preserve_tos) { ADDOP_LOAD_CONST(c, loc, s->v.Return.value->v.Constant.value); } ADDOP(c, loc, RETURN_VALUE); return SUCCESS; } static int compiler_break(struct compiler *c, location loc) { struct fblockinfo *loop = NULL; location origin_loc = loc; /* Emit instruction with line number */ ADDOP(c, loc, NOP); RETURN_IF_ERROR(compiler_unwind_fblock_stack(c, &loc, 0, &loop)); if (loop == NULL) { return compiler_error(c, origin_loc, "'break' outside loop"); } RETURN_IF_ERROR(compiler_unwind_fblock(c, &loc, loop, 0)); ADDOP_JUMP(c, loc, JUMP, loop->fb_exit); return SUCCESS; } static int compiler_continue(struct compiler *c, location loc) { struct fblockinfo *loop = NULL; location origin_loc = loc; /* Emit instruction with line number */ ADDOP(c, loc, NOP); RETURN_IF_ERROR(compiler_unwind_fblock_stack(c, &loc, 0, &loop)); if (loop == NULL) { return compiler_error(c, origin_loc, "'continue' not properly in loop"); } ADDOP_JUMP(c, loc, JUMP, loop->fb_block); return SUCCESS; } static location location_of_last_executing_statement(asdl_stmt_seq *stmts) { for (Py_ssize_t i = asdl_seq_LEN(stmts) - 1; i >= 0; i++) { location loc = LOC((stmt_ty)asdl_seq_GET(stmts, i)); if (loc.lineno > 0) { return loc; } } return NO_LOCATION; } /* Code generated for "try: finally: " is as follows: SETUP_FINALLY L POP_BLOCK JUMP E L: E: The special instructions use the block stack. Each block stack entry contains the instruction that created it (here SETUP_FINALLY), the level of the value stack at the time the block stack entry was created, and a label (here L). SETUP_FINALLY: Pushes the current value stack level and the label onto the block stack. POP_BLOCK: Pops en entry from the block stack. The block stack is unwound when an exception is raised: when a SETUP_FINALLY entry is found, the raised and the caught exceptions are pushed onto the value stack (and the exception condition is cleared), and the interpreter jumps to the label gotten from the block stack. */ static int compiler_try_finally(struct compiler *c, stmt_ty s) { location loc = LOC(s); NEW_JUMP_TARGET_LABEL(c, body); NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, exit); NEW_JUMP_TARGET_LABEL(c, cleanup); /* `try` block */ ADDOP_JUMP(c, loc, SETUP_FINALLY, end); USE_LABEL(c, body); RETURN_IF_ERROR( compiler_push_fblock(c, loc, FINALLY_TRY, body, end, s->v.Try.finalbody)); if (s->v.Try.handlers && asdl_seq_LEN(s->v.Try.handlers)) { RETURN_IF_ERROR(compiler_try_except(c, s)); } else { VISIT_SEQ(c, stmt, s->v.Try.body); } ADDOP(c, NO_LOCATION, POP_BLOCK); compiler_pop_fblock(c, FINALLY_TRY, body); VISIT_SEQ(c, stmt, s->v.Try.finalbody); ADDOP_JUMP(c, NO_LOCATION, JUMP, exit); /* `finally` block */ USE_LABEL(c, end); loc = NO_LOCATION; ADDOP_JUMP(c, loc, SETUP_CLEANUP, cleanup); ADDOP(c, loc, PUSH_EXC_INFO); RETURN_IF_ERROR( compiler_push_fblock(c, loc, FINALLY_END, end, NO_LABEL, NULL)); VISIT_SEQ(c, stmt, s->v.Try.finalbody); loc = location_of_last_executing_statement(s->v.Try.finalbody); compiler_pop_fblock(c, FINALLY_END, end); ADDOP_I(c, loc, RERAISE, 0); USE_LABEL(c, cleanup); POP_EXCEPT_AND_RERAISE(c, loc); USE_LABEL(c, exit); return SUCCESS; } static int compiler_try_star_finally(struct compiler *c, stmt_ty s) { location loc = LOC(s); NEW_JUMP_TARGET_LABEL(c, body); NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, exit); NEW_JUMP_TARGET_LABEL(c, cleanup); /* `try` block */ ADDOP_JUMP(c, loc, SETUP_FINALLY, end); USE_LABEL(c, body); RETURN_IF_ERROR( compiler_push_fblock(c, loc, FINALLY_TRY, body, end, s->v.TryStar.finalbody)); if (s->v.TryStar.handlers && asdl_seq_LEN(s->v.TryStar.handlers)) { RETURN_IF_ERROR(compiler_try_star_except(c, s)); } else { VISIT_SEQ(c, stmt, s->v.TryStar.body); } ADDOP(c, NO_LOCATION, POP_BLOCK); compiler_pop_fblock(c, FINALLY_TRY, body); VISIT_SEQ(c, stmt, s->v.TryStar.finalbody); ADDOP_JUMP(c, NO_LOCATION, JUMP, exit); /* `finally` block */ USE_LABEL(c, end); loc = NO_LOCATION; ADDOP_JUMP(c, loc, SETUP_CLEANUP, cleanup); ADDOP(c, loc, PUSH_EXC_INFO); RETURN_IF_ERROR( compiler_push_fblock(c, loc, FINALLY_END, end, NO_LABEL, NULL)); VISIT_SEQ(c, stmt, s->v.TryStar.finalbody); loc = location_of_last_executing_statement(s->v.Try.finalbody); compiler_pop_fblock(c, FINALLY_END, end); ADDOP_I(c, loc, RERAISE, 0); USE_LABEL(c, cleanup); POP_EXCEPT_AND_RERAISE(c, loc); USE_LABEL(c, exit); return SUCCESS; } /* Code generated for "try: S except E1 as V1: S1 except E2 as V2: S2 ...": (The contents of the value stack is shown in [], with the top at the right; 'tb' is trace-back info, 'val' the exception's associated value, and 'exc' the exception.) Value stack Label Instruction Argument [] SETUP_FINALLY L1 [] [] POP_BLOCK [] JUMP L0 [exc] L1: ) [exc, E1] CHECK_EXC_MATCH ) [exc, bool] POP_JUMP_IF_FALSE L2 ) only if E1 [exc] (or POP if no V1) [] JUMP L0 [exc] L2: .............................etc....................... [exc] Ln+1: RERAISE # re-raise exception [] L0: Of course, parts are not generated if Vi or Ei is not present. */ static int compiler_try_except(struct compiler *c, stmt_ty s) { location loc = LOC(s); Py_ssize_t i, n; NEW_JUMP_TARGET_LABEL(c, body); NEW_JUMP_TARGET_LABEL(c, except); NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, cleanup); ADDOP_JUMP(c, loc, SETUP_FINALLY, except); USE_LABEL(c, body); RETURN_IF_ERROR( compiler_push_fblock(c, loc, TRY_EXCEPT, body, NO_LABEL, NULL)); VISIT_SEQ(c, stmt, s->v.Try.body); compiler_pop_fblock(c, TRY_EXCEPT, body); ADDOP(c, NO_LOCATION, POP_BLOCK); if (s->v.Try.orelse && asdl_seq_LEN(s->v.Try.orelse)) { VISIT_SEQ(c, stmt, s->v.Try.orelse); } ADDOP_JUMP(c, NO_LOCATION, JUMP, end); n = asdl_seq_LEN(s->v.Try.handlers); USE_LABEL(c, except); ADDOP_JUMP(c, NO_LOCATION, SETUP_CLEANUP, cleanup); ADDOP(c, NO_LOCATION, PUSH_EXC_INFO); /* Runtime will push a block here, so we need to account for that */ RETURN_IF_ERROR( compiler_push_fblock(c, loc, EXCEPTION_HANDLER, NO_LABEL, NO_LABEL, NULL)); for (i = 0; i < n; i++) { excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET( s->v.Try.handlers, i); location loc = LOC(handler); if (!handler->v.ExceptHandler.type && i < n-1) { return compiler_error(c, loc, "default 'except:' must be last"); } NEW_JUMP_TARGET_LABEL(c, next_except); except = next_except; if (handler->v.ExceptHandler.type) { VISIT(c, expr, handler->v.ExceptHandler.type); ADDOP(c, loc, CHECK_EXC_MATCH); ADDOP_JUMP(c, loc, POP_JUMP_IF_FALSE, except); } if (handler->v.ExceptHandler.name) { NEW_JUMP_TARGET_LABEL(c, cleanup_end); NEW_JUMP_TARGET_LABEL(c, cleanup_body); RETURN_IF_ERROR( compiler_nameop(c, loc, handler->v.ExceptHandler.name, Store)); /* try: # body except type as name: try: # body finally: name = None # in case body contains "del name" del name */ /* second try: */ ADDOP_JUMP(c, loc, SETUP_CLEANUP, cleanup_end); USE_LABEL(c, cleanup_body); RETURN_IF_ERROR( compiler_push_fblock(c, loc, HANDLER_CLEANUP, cleanup_body, NO_LABEL, handler->v.ExceptHandler.name)); /* second # body */ VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body); compiler_pop_fblock(c, HANDLER_CLEANUP, cleanup_body); /* name = None; del name; # Mark as artificial */ ADDOP(c, NO_LOCATION, POP_BLOCK); ADDOP(c, NO_LOCATION, POP_BLOCK); ADDOP(c, NO_LOCATION, POP_EXCEPT); ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); RETURN_IF_ERROR( compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Store)); RETURN_IF_ERROR( compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Del)); ADDOP_JUMP(c, NO_LOCATION, JUMP, end); /* except: */ USE_LABEL(c, cleanup_end); /* name = None; del name; # artificial */ ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); RETURN_IF_ERROR( compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Store)); RETURN_IF_ERROR( compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Del)); ADDOP_I(c, NO_LOCATION, RERAISE, 1); } else { NEW_JUMP_TARGET_LABEL(c, cleanup_body); ADDOP(c, loc, POP_TOP); /* exc_value */ USE_LABEL(c, cleanup_body); RETURN_IF_ERROR( compiler_push_fblock(c, loc, HANDLER_CLEANUP, cleanup_body, NO_LABEL, NULL)); VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body); compiler_pop_fblock(c, HANDLER_CLEANUP, cleanup_body); ADDOP(c, NO_LOCATION, POP_BLOCK); ADDOP(c, NO_LOCATION, POP_EXCEPT); ADDOP_JUMP(c, NO_LOCATION, JUMP, end); } USE_LABEL(c, except); } /* artificial */ compiler_pop_fblock(c, EXCEPTION_HANDLER, NO_LABEL); ADDOP_I(c, NO_LOCATION, RERAISE, 0); USE_LABEL(c, cleanup); POP_EXCEPT_AND_RERAISE(c, NO_LOCATION); USE_LABEL(c, end); return SUCCESS; } /* Code generated for "try: S except* E1 as V1: S1 except* E2 as V2: S2 ...": (The contents of the value stack is shown in [], with the top at the right; 'tb' is trace-back info, 'val' the exception instance, and 'typ' the exception's type.) Value stack Label Instruction Argument [] SETUP_FINALLY L1 [] [] POP_BLOCK [] JUMP L0 [exc] L1: BUILD_LIST ) list for raised/reraised excs ("result") [orig, res] COPY 2 ) make a copy of the original EG [orig, res, exc] [orig, res, exc, E1] CHECK_EG_MATCH [orig, res, rest/exc, match?] COPY 1 [orig, res, rest/exc, match?, match?] POP_JUMP_IF_NONE C1 [orig, res, rest, match] (or POP if no V1) [orig, res, rest] SETUP_FINALLY R1 [orig, res, rest] [orig, res, rest] JUMP L2 [orig, res, rest, i, v] R1: LIST_APPEND 3 ) exc raised in except* body - add to res [orig, res, rest, i] POP [orig, res, rest] JUMP LE2 [orig, res, rest] L2: NOP ) for lineno [orig, res, rest] JUMP LE2 [orig, res, rest/exc, None] C1: POP [orig, res, rest] LE2: .............................etc....................... [orig, res, rest] Ln+1: LIST_APPEND 1 ) add unhandled exc to res (could be None) [orig, res] CALL_INTRINSIC_2 PREP_RERAISE_STAR [exc] COPY 1 [exc, exc] POP_JUMP_IF_NOT_NONE RER [exc] POP_TOP [] JUMP L0 [exc] RER: SWAP 2 [exc, prev_exc_info] POP_EXCEPT [exc] RERAISE 0 [] L0: */ static int compiler_try_star_except(struct compiler *c, stmt_ty s) { location loc = LOC(s); NEW_JUMP_TARGET_LABEL(c, body); NEW_JUMP_TARGET_LABEL(c, except); NEW_JUMP_TARGET_LABEL(c, orelse); NEW_JUMP_TARGET_LABEL(c, end); NEW_JUMP_TARGET_LABEL(c, cleanup); NEW_JUMP_TARGET_LABEL(c, reraise_star); ADDOP_JUMP(c, loc, SETUP_FINALLY, except); USE_LABEL(c, body); RETURN_IF_ERROR( compiler_push_fblock(c, loc, TRY_EXCEPT, body, NO_LABEL, NULL)); VISIT_SEQ(c, stmt, s->v.TryStar.body); compiler_pop_fblock(c, TRY_EXCEPT, body); ADDOP(c, NO_LOCATION, POP_BLOCK); ADDOP_JUMP(c, NO_LOCATION, JUMP, orelse); Py_ssize_t n = asdl_seq_LEN(s->v.TryStar.handlers); USE_LABEL(c, except); ADDOP_JUMP(c, NO_LOCATION, SETUP_CLEANUP, cleanup); ADDOP(c, NO_LOCATION, PUSH_EXC_INFO); /* Runtime will push a block here, so we need to account for that */ RETURN_IF_ERROR( compiler_push_fblock(c, loc, EXCEPTION_GROUP_HANDLER, NO_LABEL, NO_LABEL, "except handler")); for (Py_ssize_t i = 0; i < n; i++) { excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET( s->v.TryStar.handlers, i); location loc = LOC(handler); NEW_JUMP_TARGET_LABEL(c, next_except); except = next_except; NEW_JUMP_TARGET_LABEL(c, except_with_error); NEW_JUMP_TARGET_LABEL(c, no_match); if (i == 0) { /* create empty list for exceptions raised/reraise in the except* blocks */ /* [orig] BUILD_LIST */ /* Create a copy of the original EG */ /* [orig, []] COPY 2 [orig, [], exc] */ ADDOP_I(c, loc, BUILD_LIST, 0); ADDOP_I(c, loc, COPY, 2); } if (handler->v.ExceptHandler.type) { VISIT(c, expr, handler->v.ExceptHandler.type); ADDOP(c, loc, CHECK_EG_MATCH); ADDOP_I(c, loc, COPY, 1); ADDOP_JUMP(c, loc, POP_JUMP_IF_NONE, no_match); } NEW_JUMP_TARGET_LABEL(c, cleanup_end); NEW_JUMP_TARGET_LABEL(c, cleanup_body); if (handler->v.ExceptHandler.name) { RETURN_IF_ERROR( compiler_nameop(c, loc, handler->v.ExceptHandler.name, Store)); } else { ADDOP(c, loc, POP_TOP); // match } /* try: # body except type as name: try: # body finally: name = None # in case body contains "del name" del name */ /* second try: */ ADDOP_JUMP(c, loc, SETUP_CLEANUP, cleanup_end); USE_LABEL(c, cleanup_body); RETURN_IF_ERROR( compiler_push_fblock(c, loc, HANDLER_CLEANUP, cleanup_body, NO_LABEL, handler->v.ExceptHandler.name)); /* second # body */ VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body); compiler_pop_fblock(c, HANDLER_CLEANUP, cleanup_body); /* name = None; del name; # artificial */ ADDOP(c, NO_LOCATION, POP_BLOCK); if (handler->v.ExceptHandler.name) { ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); RETURN_IF_ERROR( compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Store)); RETURN_IF_ERROR( compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Del)); } ADDOP_JUMP(c, NO_LOCATION, JUMP, except); /* except: */ USE_LABEL(c, cleanup_end); /* name = None; del name; # artificial */ if (handler->v.ExceptHandler.name) { ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); RETURN_IF_ERROR( compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Store)); RETURN_IF_ERROR( compiler_nameop(c, NO_LOCATION, handler->v.ExceptHandler.name, Del)); } /* add exception raised to the res list */ ADDOP_I(c, NO_LOCATION, LIST_APPEND, 3); // exc ADDOP(c, NO_LOCATION, POP_TOP); // lasti ADDOP_JUMP(c, NO_LOCATION, JUMP, except_with_error); USE_LABEL(c, except); ADDOP(c, NO_LOCATION, NOP); // to hold a propagated location info ADDOP_JUMP(c, NO_LOCATION, JUMP, except_with_error); USE_LABEL(c, no_match); ADDOP(c, loc, POP_TOP); // match (None) USE_LABEL(c, except_with_error); if (i == n - 1) { /* Add exc to the list (if not None it's the unhandled part of the EG) */ ADDOP_I(c, NO_LOCATION, LIST_APPEND, 1); ADDOP_JUMP(c, NO_LOCATION, JUMP, reraise_star); } } /* artificial */ compiler_pop_fblock(c, EXCEPTION_GROUP_HANDLER, NO_LABEL); NEW_JUMP_TARGET_LABEL(c, reraise); USE_LABEL(c, reraise_star); ADDOP_I(c, NO_LOCATION, CALL_INTRINSIC_2, INTRINSIC_PREP_RERAISE_STAR); ADDOP_I(c, NO_LOCATION, COPY, 1); ADDOP_JUMP(c, NO_LOCATION, POP_JUMP_IF_NOT_NONE, reraise); /* Nothing to reraise */ ADDOP(c, NO_LOCATION, POP_TOP); ADDOP(c, NO_LOCATION, POP_BLOCK); ADDOP(c, NO_LOCATION, POP_EXCEPT); ADDOP_JUMP(c, NO_LOCATION, JUMP, end); USE_LABEL(c, reraise); ADDOP(c, NO_LOCATION, POP_BLOCK); ADDOP_I(c, NO_LOCATION, SWAP, 2); ADDOP(c, NO_LOCATION, POP_EXCEPT); ADDOP_I(c, NO_LOCATION, RERAISE, 0); USE_LABEL(c, cleanup); POP_EXCEPT_AND_RERAISE(c, NO_LOCATION); USE_LABEL(c, orelse); VISIT_SEQ(c, stmt, s->v.TryStar.orelse); USE_LABEL(c, end); return SUCCESS; } static int compiler_try(struct compiler *c, stmt_ty s) { if (s->v.Try.finalbody && asdl_seq_LEN(s->v.Try.finalbody)) return compiler_try_finally(c, s); else return compiler_try_except(c, s); } static int compiler_try_star(struct compiler *c, stmt_ty s) { if (s->v.TryStar.finalbody && asdl_seq_LEN(s->v.TryStar.finalbody)) { return compiler_try_star_finally(c, s); } else { return compiler_try_star_except(c, s); } } static int compiler_import_as(struct compiler *c, location loc, identifier name, identifier asname) { /* The IMPORT_NAME opcode was already generated. This function merely needs to bind the result to a name. If there is a dot in name, we need to split it and emit a IMPORT_FROM for each name. */ Py_ssize_t len = PyUnicode_GET_LENGTH(name); Py_ssize_t dot = PyUnicode_FindChar(name, '.', 0, len, 1); if (dot == -2) { return ERROR; } if (dot != -1) { /* Consume the base module name to get the first attribute */ while (1) { Py_ssize_t pos = dot + 1; PyObject *attr; dot = PyUnicode_FindChar(name, '.', pos, len, 1); if (dot == -2) { return ERROR; } attr = PyUnicode_Substring(name, pos, (dot != -1) ? dot : len); if (!attr) { return ERROR; } ADDOP_N(c, loc, IMPORT_FROM, attr, names); if (dot == -1) { break; } ADDOP_I(c, loc, SWAP, 2); ADDOP(c, loc, POP_TOP); } RETURN_IF_ERROR(compiler_nameop(c, loc, asname, Store)); ADDOP(c, loc, POP_TOP); return SUCCESS; } return compiler_nameop(c, loc, asname, Store); } static int compiler_import(struct compiler *c, stmt_ty s) { location loc = LOC(s); /* The Import node stores a module name like a.b.c as a single string. This is convenient for all cases except import a.b.c as d where we need to parse that string to extract the individual module names. XXX Perhaps change the representation to make this case simpler? */ Py_ssize_t i, n = asdl_seq_LEN(s->v.Import.names); PyObject *zero = _PyLong_GetZero(); // borrowed reference for (i = 0; i < n; i++) { alias_ty alias = (alias_ty)asdl_seq_GET(s->v.Import.names, i); int r; ADDOP_LOAD_CONST(c, loc, zero); ADDOP_LOAD_CONST(c, loc, Py_None); ADDOP_NAME(c, loc, IMPORT_NAME, alias->name, names); if (alias->asname) { r = compiler_import_as(c, loc, alias->name, alias->asname); RETURN_IF_ERROR(r); } else { identifier tmp = alias->name; Py_ssize_t dot = PyUnicode_FindChar( alias->name, '.', 0, PyUnicode_GET_LENGTH(alias->name), 1); if (dot != -1) { tmp = PyUnicode_Substring(alias->name, 0, dot); if (tmp == NULL) { return ERROR; } } r = compiler_nameop(c, loc, tmp, Store); if (dot != -1) { Py_DECREF(tmp); } RETURN_IF_ERROR(r); } } return SUCCESS; } static int compiler_from_import(struct compiler *c, stmt_ty s) { Py_ssize_t n = asdl_seq_LEN(s->v.ImportFrom.names); ADDOP_LOAD_CONST_NEW(c, LOC(s), PyLong_FromLong(s->v.ImportFrom.level)); PyObject *names = PyTuple_New(n); if (!names) { return ERROR; } /* build up the names */ for (Py_ssize_t i = 0; i < n; i++) { alias_ty alias = (alias_ty)asdl_seq_GET(s->v.ImportFrom.names, i); PyTuple_SET_ITEM(names, i, Py_NewRef(alias->name)); } if (location_is_after(LOC(s), c->c_future.ff_location) && s->v.ImportFrom.module && _PyUnicode_EqualToASCIIString(s->v.ImportFrom.module, "__future__")) { Py_DECREF(names); return compiler_error(c, LOC(s), "from __future__ imports must occur " "at the beginning of the file"); } ADDOP_LOAD_CONST_NEW(c, LOC(s), names); if (s->v.ImportFrom.module) { ADDOP_NAME(c, LOC(s), IMPORT_NAME, s->v.ImportFrom.module, names); } else { _Py_DECLARE_STR(empty, ""); ADDOP_NAME(c, LOC(s), IMPORT_NAME, &_Py_STR(empty), names); } for (Py_ssize_t i = 0; i < n; i++) { alias_ty alias = (alias_ty)asdl_seq_GET(s->v.ImportFrom.names, i); identifier store_name; if (i == 0 && PyUnicode_READ_CHAR(alias->name, 0) == '*') { assert(n == 1); ADDOP_I(c, LOC(s), CALL_INTRINSIC_1, INTRINSIC_IMPORT_STAR); ADDOP(c, NO_LOCATION, POP_TOP); return SUCCESS; } ADDOP_NAME(c, LOC(s), IMPORT_FROM, alias->name, names); store_name = alias->name; if (alias->asname) { store_name = alias->asname; } RETURN_IF_ERROR(compiler_nameop(c, LOC(s), store_name, Store)); } /* remove imported module */ ADDOP(c, LOC(s), POP_TOP); return SUCCESS; } static int compiler_assert(struct compiler *c, stmt_ty s) { /* Always emit a warning if the test is a non-zero length tuple */ if ((s->v.Assert.test->kind == Tuple_kind && asdl_seq_LEN(s->v.Assert.test->v.Tuple.elts) > 0) || (s->v.Assert.test->kind == Constant_kind && PyTuple_Check(s->v.Assert.test->v.Constant.value) && PyTuple_Size(s->v.Assert.test->v.Constant.value) > 0)) { RETURN_IF_ERROR( compiler_warn(c, LOC(s), "assertion is always true, " "perhaps remove parentheses?")); } if (c->c_optimize) { return SUCCESS; } NEW_JUMP_TARGET_LABEL(c, end); RETURN_IF_ERROR(compiler_jump_if(c, LOC(s), s->v.Assert.test, end, 1)); ADDOP(c, LOC(s), LOAD_ASSERTION_ERROR); if (s->v.Assert.msg) { VISIT(c, expr, s->v.Assert.msg); ADDOP_I(c, LOC(s), CALL, 0); } ADDOP_I(c, LOC(s), RAISE_VARARGS, 1); USE_LABEL(c, end); return SUCCESS; } static int compiler_stmt_expr(struct compiler *c, location loc, expr_ty value) { if (c->c_interactive && c->c_nestlevel <= 1) { VISIT(c, expr, value); ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_PRINT); ADDOP(c, NO_LOCATION, POP_TOP); return SUCCESS; } if (value->kind == Constant_kind) { /* ignore constant statement */ ADDOP(c, loc, NOP); return SUCCESS; } VISIT(c, expr, value); ADDOP(c, NO_LOCATION, POP_TOP); /* artificial */ return SUCCESS; } static int compiler_visit_stmt(struct compiler *c, stmt_ty s) { switch (s->kind) { case FunctionDef_kind: return compiler_function(c, s, 0); case ClassDef_kind: return compiler_class(c, s); case TypeAlias_kind: return compiler_typealias(c, s); case Return_kind: return compiler_return(c, s); case Delete_kind: VISIT_SEQ(c, expr, s->v.Delete.targets) break; case Assign_kind: { Py_ssize_t n = asdl_seq_LEN(s->v.Assign.targets); VISIT(c, expr, s->v.Assign.value); for (Py_ssize_t i = 0; i < n; i++) { if (i < n - 1) { ADDOP_I(c, LOC(s), COPY, 1); } VISIT(c, expr, (expr_ty)asdl_seq_GET(s->v.Assign.targets, i)); } break; } case AugAssign_kind: return compiler_augassign(c, s); case AnnAssign_kind: return compiler_annassign(c, s); case For_kind: return compiler_for(c, s); case While_kind: return compiler_while(c, s); case If_kind: return compiler_if(c, s); case Match_kind: return compiler_match(c, s); case Raise_kind: { Py_ssize_t n = 0; if (s->v.Raise.exc) { VISIT(c, expr, s->v.Raise.exc); n++; if (s->v.Raise.cause) { VISIT(c, expr, s->v.Raise.cause); n++; } } ADDOP_I(c, LOC(s), RAISE_VARARGS, (int)n); break; } case Try_kind: return compiler_try(c, s); case TryStar_kind: return compiler_try_star(c, s); case Assert_kind: return compiler_assert(c, s); case Import_kind: return compiler_import(c, s); case ImportFrom_kind: return compiler_from_import(c, s); case Global_kind: case Nonlocal_kind: break; case Expr_kind: { return compiler_stmt_expr(c, LOC(s), s->v.Expr.value); } case Pass_kind: { ADDOP(c, LOC(s), NOP); break; } case Break_kind: { return compiler_break(c, LOC(s)); } case Continue_kind: { return compiler_continue(c, LOC(s)); } case With_kind: return compiler_with(c, s, 0); case AsyncFunctionDef_kind: return compiler_function(c, s, 1); case AsyncWith_kind: return compiler_async_with(c, s, 0); case AsyncFor_kind: return compiler_async_for(c, s); } return SUCCESS; } static int unaryop(unaryop_ty op) { switch (op) { case Invert: return UNARY_INVERT; case Not: return UNARY_NOT; case USub: return UNARY_NEGATIVE; default: PyErr_Format(PyExc_SystemError, "unary op %d should not be possible", op); return 0; } } static int addop_binary(struct compiler *c, location loc, operator_ty binop, bool inplace) { int oparg; switch (binop) { case Add: oparg = inplace ? NB_INPLACE_ADD : NB_ADD; break; case Sub: oparg = inplace ? NB_INPLACE_SUBTRACT : NB_SUBTRACT; break; case Mult: oparg = inplace ? NB_INPLACE_MULTIPLY : NB_MULTIPLY; break; case MatMult: oparg = inplace ? NB_INPLACE_MATRIX_MULTIPLY : NB_MATRIX_MULTIPLY; break; case Div: oparg = inplace ? NB_INPLACE_TRUE_DIVIDE : NB_TRUE_DIVIDE; break; case Mod: oparg = inplace ? NB_INPLACE_REMAINDER : NB_REMAINDER; break; case Pow: oparg = inplace ? NB_INPLACE_POWER : NB_POWER; break; case LShift: oparg = inplace ? NB_INPLACE_LSHIFT : NB_LSHIFT; break; case RShift: oparg = inplace ? NB_INPLACE_RSHIFT : NB_RSHIFT; break; case BitOr: oparg = inplace ? NB_INPLACE_OR : NB_OR; break; case BitXor: oparg = inplace ? NB_INPLACE_XOR : NB_XOR; break; case BitAnd: oparg = inplace ? NB_INPLACE_AND : NB_AND; break; case FloorDiv: oparg = inplace ? NB_INPLACE_FLOOR_DIVIDE : NB_FLOOR_DIVIDE; break; default: PyErr_Format(PyExc_SystemError, "%s op %d should not be possible", inplace ? "inplace" : "binary", binop); return ERROR; } ADDOP_I(c, loc, BINARY_OP, oparg); return SUCCESS; } static int addop_yield(struct compiler *c, location loc) { if (c->u->u_ste->ste_generator && c->u->u_ste->ste_coroutine) { ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_ASYNC_GEN_WRAP); } ADDOP_I(c, loc, YIELD_VALUE, 0); ADDOP_I(c, loc, RESUME, 1); return SUCCESS; } static int compiler_nameop(struct compiler *c, location loc, identifier name, expr_context_ty ctx) { int op, scope; Py_ssize_t arg; enum { OP_FAST, OP_GLOBAL, OP_DEREF, OP_NAME } optype; PyObject *dict = c->u->u_metadata.u_names; PyObject *mangled; assert(!_PyUnicode_EqualToASCIIString(name, "None") && !_PyUnicode_EqualToASCIIString(name, "True") && !_PyUnicode_EqualToASCIIString(name, "False")); if (forbidden_name(c, loc, name, ctx)) { return ERROR; } mangled = _Py_Mangle(c->u->u_private, name); if (!mangled) { return ERROR; } op = 0; optype = OP_NAME; scope = _PyST_GetScope(c->u->u_ste, mangled); switch (scope) { case FREE: dict = c->u->u_metadata.u_freevars; optype = OP_DEREF; break; case CELL: dict = c->u->u_metadata.u_cellvars; optype = OP_DEREF; break; case LOCAL: if (_PyST_IsFunctionLike(c->u->u_ste) || (PyDict_GetItem(c->u->u_metadata.u_fasthidden, mangled) == Py_True)) optype = OP_FAST; break; case GLOBAL_IMPLICIT: if (_PyST_IsFunctionLike(c->u->u_ste)) optype = OP_GLOBAL; break; case GLOBAL_EXPLICIT: optype = OP_GLOBAL; break; default: /* scope can be 0 */ break; } /* XXX Leave assert here, but handle __doc__ and the like better */ assert(scope || PyUnicode_READ_CHAR(name, 0) == '_'); switch (optype) { case OP_DEREF: switch (ctx) { case Load: if (c->u->u_ste->ste_type == ClassBlock && !c->u->u_in_inlined_comp) { op = LOAD_FROM_DICT_OR_DEREF; // First load the locals if (codegen_addop_noarg(INSTR_SEQUENCE(c), LOAD_LOCALS, loc) < 0) { return ERROR; } } else if (c->u->u_ste->ste_can_see_class_scope) { op = LOAD_FROM_DICT_OR_DEREF; // First load the classdict if (compiler_addop_o(c->u, loc, LOAD_DEREF, c->u->u_metadata.u_freevars, &_Py_ID(__classdict__)) < 0) { return ERROR; } } else { op = LOAD_DEREF; } break; case Store: op = STORE_DEREF; break; case Del: op = DELETE_DEREF; break; } break; case OP_FAST: switch (ctx) { case Load: op = LOAD_FAST; break; case Store: op = STORE_FAST; break; case Del: op = DELETE_FAST; break; } ADDOP_N(c, loc, op, mangled, varnames); return SUCCESS; case OP_GLOBAL: switch (ctx) { case Load: if (c->u->u_ste->ste_can_see_class_scope && scope == GLOBAL_IMPLICIT) { op = LOAD_FROM_DICT_OR_GLOBALS; // First load the classdict if (compiler_addop_o(c->u, loc, LOAD_DEREF, c->u->u_metadata.u_freevars, &_Py_ID(__classdict__)) < 0) { return ERROR; } } else { op = LOAD_GLOBAL; } break; case Store: op = STORE_GLOBAL; break; case Del: op = DELETE_GLOBAL; break; } break; case OP_NAME: switch (ctx) { case Load: op = (c->u->u_ste->ste_type == ClassBlock && c->u->u_in_inlined_comp) ? LOAD_GLOBAL : LOAD_NAME; break; case Store: op = STORE_NAME; break; case Del: op = DELETE_NAME; break; } break; } assert(op); arg = dict_add_o(dict, mangled); Py_DECREF(mangled); if (arg < 0) { return ERROR; } if (op == LOAD_GLOBAL) { arg <<= 1; } return codegen_addop_i(INSTR_SEQUENCE(c), op, arg, loc); } static int compiler_boolop(struct compiler *c, expr_ty e) { int jumpi; Py_ssize_t i, n; asdl_expr_seq *s; location loc = LOC(e); assert(e->kind == BoolOp_kind); if (e->v.BoolOp.op == And) jumpi = POP_JUMP_IF_FALSE; else jumpi = POP_JUMP_IF_TRUE; NEW_JUMP_TARGET_LABEL(c, end); s = e->v.BoolOp.values; n = asdl_seq_LEN(s) - 1; assert(n >= 0); for (i = 0; i < n; ++i) { VISIT(c, expr, (expr_ty)asdl_seq_GET(s, i)); ADDOP_I(c, loc, COPY, 1); ADDOP_JUMP(c, loc, jumpi, end); ADDOP(c, loc, POP_TOP); } VISIT(c, expr, (expr_ty)asdl_seq_GET(s, n)); USE_LABEL(c, end); return SUCCESS; } static int starunpack_helper(struct compiler *c, location loc, asdl_expr_seq *elts, int pushed, int build, int add, int extend, int tuple) { Py_ssize_t n = asdl_seq_LEN(elts); if (n > 2 && are_all_items_const(elts, 0, n)) { PyObject *folded = PyTuple_New(n); if (folded == NULL) { return ERROR; } PyObject *val; for (Py_ssize_t i = 0; i < n; i++) { val = ((expr_ty)asdl_seq_GET(elts, i))->v.Constant.value; PyTuple_SET_ITEM(folded, i, Py_NewRef(val)); } if (tuple && !pushed) { ADDOP_LOAD_CONST_NEW(c, loc, folded); } else { if (add == SET_ADD) { Py_SETREF(folded, PyFrozenSet_New(folded)); if (folded == NULL) { return ERROR; } } ADDOP_I(c, loc, build, pushed); ADDOP_LOAD_CONST_NEW(c, loc, folded); ADDOP_I(c, loc, extend, 1); if (tuple) { ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_LIST_TO_TUPLE); } } return SUCCESS; } int big = n+pushed > STACK_USE_GUIDELINE; int seen_star = 0; for (Py_ssize_t i = 0; i < n; i++) { expr_ty elt = asdl_seq_GET(elts, i); if (elt->kind == Starred_kind) { seen_star = 1; break; } } if (!seen_star && !big) { for (Py_ssize_t i = 0; i < n; i++) { expr_ty elt = asdl_seq_GET(elts, i); VISIT(c, expr, elt); } if (tuple) { ADDOP_I(c, loc, BUILD_TUPLE, n+pushed); } else { ADDOP_I(c, loc, build, n+pushed); } return SUCCESS; } int sequence_built = 0; if (big) { ADDOP_I(c, loc, build, pushed); sequence_built = 1; } for (Py_ssize_t i = 0; i < n; i++) { expr_ty elt = asdl_seq_GET(elts, i); if (elt->kind == Starred_kind) { if (sequence_built == 0) { ADDOP_I(c, loc, build, i+pushed); sequence_built = 1; } VISIT(c, expr, elt->v.Starred.value); ADDOP_I(c, loc, extend, 1); } else { VISIT(c, expr, elt); if (sequence_built) { ADDOP_I(c, loc, add, 1); } } } assert(sequence_built); if (tuple) { ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_LIST_TO_TUPLE); } return SUCCESS; } static int unpack_helper(struct compiler *c, location loc, asdl_expr_seq *elts) { Py_ssize_t n = asdl_seq_LEN(elts); int seen_star = 0; for (Py_ssize_t i = 0; i < n; i++) { expr_ty elt = asdl_seq_GET(elts, i); if (elt->kind == Starred_kind && !seen_star) { if ((i >= (1 << 8)) || (n-i-1 >= (INT_MAX >> 8))) { return compiler_error(c, loc, "too many expressions in " "star-unpacking assignment"); } ADDOP_I(c, loc, UNPACK_EX, (i + ((n-i-1) << 8))); seen_star = 1; } else if (elt->kind == Starred_kind) { return compiler_error(c, loc, "multiple starred expressions in assignment"); } } if (!seen_star) { ADDOP_I(c, loc, UNPACK_SEQUENCE, n); } return SUCCESS; } static int assignment_helper(struct compiler *c, location loc, asdl_expr_seq *elts) { Py_ssize_t n = asdl_seq_LEN(elts); RETURN_IF_ERROR(unpack_helper(c, loc, elts)); for (Py_ssize_t i = 0; i < n; i++) { expr_ty elt = asdl_seq_GET(elts, i); VISIT(c, expr, elt->kind != Starred_kind ? elt : elt->v.Starred.value); } return SUCCESS; } static int compiler_list(struct compiler *c, expr_ty e) { location loc = LOC(e); asdl_expr_seq *elts = e->v.List.elts; if (e->v.List.ctx == Store) { return assignment_helper(c, loc, elts); } else if (e->v.List.ctx == Load) { return starunpack_helper(c, loc, elts, 0, BUILD_LIST, LIST_APPEND, LIST_EXTEND, 0); } else { VISIT_SEQ(c, expr, elts); } return SUCCESS; } static int compiler_tuple(struct compiler *c, expr_ty e) { location loc = LOC(e); asdl_expr_seq *elts = e->v.Tuple.elts; if (e->v.Tuple.ctx == Store) { return assignment_helper(c, loc, elts); } else if (e->v.Tuple.ctx == Load) { return starunpack_helper(c, loc, elts, 0, BUILD_LIST, LIST_APPEND, LIST_EXTEND, 1); } else { VISIT_SEQ(c, expr, elts); } return SUCCESS; } static int compiler_set(struct compiler *c, expr_ty e) { location loc = LOC(e); return starunpack_helper(c, loc, e->v.Set.elts, 0, BUILD_SET, SET_ADD, SET_UPDATE, 0); } static bool are_all_items_const(asdl_expr_seq *seq, Py_ssize_t begin, Py_ssize_t end) { for (Py_ssize_t i = begin; i < end; i++) { expr_ty key = (expr_ty)asdl_seq_GET(seq, i); if (key == NULL || key->kind != Constant_kind) { return false; } } return true; } static int compiler_subdict(struct compiler *c, expr_ty e, Py_ssize_t begin, Py_ssize_t end) { Py_ssize_t i, n = end - begin; PyObject *keys, *key; int big = n*2 > STACK_USE_GUIDELINE; location loc = LOC(e); if (n > 1 && !big && are_all_items_const(e->v.Dict.keys, begin, end)) { for (i = begin; i < end; i++) { VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.values, i)); } keys = PyTuple_New(n); if (keys == NULL) { return SUCCESS; } for (i = begin; i < end; i++) { key = ((expr_ty)asdl_seq_GET(e->v.Dict.keys, i))->v.Constant.value; PyTuple_SET_ITEM(keys, i - begin, Py_NewRef(key)); } ADDOP_LOAD_CONST_NEW(c, loc, keys); ADDOP_I(c, loc, BUILD_CONST_KEY_MAP, n); return SUCCESS; } if (big) { ADDOP_I(c, loc, BUILD_MAP, 0); } for (i = begin; i < end; i++) { VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.keys, i)); VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.values, i)); if (big) { ADDOP_I(c, loc, MAP_ADD, 1); } } if (!big) { ADDOP_I(c, loc, BUILD_MAP, n); } return SUCCESS; } static int compiler_dict(struct compiler *c, expr_ty e) { location loc = LOC(e); Py_ssize_t i, n, elements; int have_dict; int is_unpacking = 0; n = asdl_seq_LEN(e->v.Dict.values); have_dict = 0; elements = 0; for (i = 0; i < n; i++) { is_unpacking = (expr_ty)asdl_seq_GET(e->v.Dict.keys, i) == NULL; if (is_unpacking) { if (elements) { RETURN_IF_ERROR(compiler_subdict(c, e, i - elements, i)); if (have_dict) { ADDOP_I(c, loc, DICT_UPDATE, 1); } have_dict = 1; elements = 0; } if (have_dict == 0) { ADDOP_I(c, loc, BUILD_MAP, 0); have_dict = 1; } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.values, i)); ADDOP_I(c, loc, DICT_UPDATE, 1); } else { if (elements*2 > STACK_USE_GUIDELINE) { RETURN_IF_ERROR(compiler_subdict(c, e, i - elements, i + 1)); if (have_dict) { ADDOP_I(c, loc, DICT_UPDATE, 1); } have_dict = 1; elements = 0; } else { elements++; } } } if (elements) { RETURN_IF_ERROR(compiler_subdict(c, e, n - elements, n)); if (have_dict) { ADDOP_I(c, loc, DICT_UPDATE, 1); } have_dict = 1; } if (!have_dict) { ADDOP_I(c, loc, BUILD_MAP, 0); } return SUCCESS; } static int compiler_compare(struct compiler *c, expr_ty e) { location loc = LOC(e); Py_ssize_t i, n; RETURN_IF_ERROR(check_compare(c, e)); VISIT(c, expr, e->v.Compare.left); assert(asdl_seq_LEN(e->v.Compare.ops) > 0); n = asdl_seq_LEN(e->v.Compare.ops) - 1; if (n == 0) { VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, 0)); ADDOP_COMPARE(c, loc, asdl_seq_GET(e->v.Compare.ops, 0)); } else { NEW_JUMP_TARGET_LABEL(c, cleanup); for (i = 0; i < n; i++) { VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); ADDOP_I(c, loc, SWAP, 2); ADDOP_I(c, loc, COPY, 2); ADDOP_COMPARE(c, loc, asdl_seq_GET(e->v.Compare.ops, i)); ADDOP_I(c, loc, COPY, 1); ADDOP_JUMP(c, loc, POP_JUMP_IF_FALSE, cleanup); ADDOP(c, loc, POP_TOP); } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n)); ADDOP_COMPARE(c, loc, asdl_seq_GET(e->v.Compare.ops, n)); NEW_JUMP_TARGET_LABEL(c, end); ADDOP_JUMP(c, NO_LOCATION, JUMP, end); USE_LABEL(c, cleanup); ADDOP_I(c, loc, SWAP, 2); ADDOP(c, loc, POP_TOP); USE_LABEL(c, end); } return SUCCESS; } static PyTypeObject * infer_type(expr_ty e) { switch (e->kind) { case Tuple_kind: return &PyTuple_Type; case List_kind: case ListComp_kind: return &PyList_Type; case Dict_kind: case DictComp_kind: return &PyDict_Type; case Set_kind: case SetComp_kind: return &PySet_Type; case GeneratorExp_kind: return &PyGen_Type; case Lambda_kind: return &PyFunction_Type; case JoinedStr_kind: case FormattedValue_kind: return &PyUnicode_Type; case Constant_kind: return Py_TYPE(e->v.Constant.value); default: return NULL; } } static int check_caller(struct compiler *c, expr_ty e) { switch (e->kind) { case Constant_kind: case Tuple_kind: case List_kind: case ListComp_kind: case Dict_kind: case DictComp_kind: case Set_kind: case SetComp_kind: case GeneratorExp_kind: case JoinedStr_kind: case FormattedValue_kind: { location loc = LOC(e); return compiler_warn(c, loc, "'%.200s' object is not callable; " "perhaps you missed a comma?", infer_type(e)->tp_name); } default: return SUCCESS; } } static int check_subscripter(struct compiler *c, expr_ty e) { PyObject *v; switch (e->kind) { case Constant_kind: v = e->v.Constant.value; if (!(v == Py_None || v == Py_Ellipsis || PyLong_Check(v) || PyFloat_Check(v) || PyComplex_Check(v) || PyAnySet_Check(v))) { return SUCCESS; } /* fall through */ case Set_kind: case SetComp_kind: case GeneratorExp_kind: case Lambda_kind: { location loc = LOC(e); return compiler_warn(c, loc, "'%.200s' object is not subscriptable; " "perhaps you missed a comma?", infer_type(e)->tp_name); } default: return SUCCESS; } } static int check_index(struct compiler *c, expr_ty e, expr_ty s) { PyObject *v; PyTypeObject *index_type = infer_type(s); if (index_type == NULL || PyType_FastSubclass(index_type, Py_TPFLAGS_LONG_SUBCLASS) || index_type == &PySlice_Type) { return SUCCESS; } switch (e->kind) { case Constant_kind: v = e->v.Constant.value; if (!(PyUnicode_Check(v) || PyBytes_Check(v) || PyTuple_Check(v))) { return SUCCESS; } /* fall through */ case Tuple_kind: case List_kind: case ListComp_kind: case JoinedStr_kind: case FormattedValue_kind: { location loc = LOC(e); return compiler_warn(c, loc, "%.200s indices must be integers " "or slices, not %.200s; " "perhaps you missed a comma?", infer_type(e)->tp_name, index_type->tp_name); } default: return SUCCESS; } } static int is_import_originated(struct compiler *c, expr_ty e) { /* Check whether the global scope has an import named e, if it is a Name object. For not traversing all the scope stack every time this function is called, it will only check the global scope to determine whether something is imported or not. */ if (e->kind != Name_kind) { return 0; } long flags = _PyST_GetSymbol(c->c_st->st_top, e->v.Name.id); return flags & DEF_IMPORT; } static int can_optimize_super_call(struct compiler *c, expr_ty attr) { expr_ty e = attr->v.Attribute.value; if (e->kind != Call_kind || e->v.Call.func->kind != Name_kind || !_PyUnicode_EqualToASCIIString(e->v.Call.func->v.Name.id, "super") || _PyUnicode_EqualToASCIIString(attr->v.Attribute.attr, "__class__") || asdl_seq_LEN(e->v.Call.keywords) != 0) { return 0; } Py_ssize_t num_args = asdl_seq_LEN(e->v.Call.args); PyObject *super_name = e->v.Call.func->v.Name.id; // detect statically-visible shadowing of 'super' name int scope = _PyST_GetScope(c->u->u_ste, super_name); if (scope != GLOBAL_IMPLICIT) { return 0; } scope = _PyST_GetScope(c->c_st->st_top, super_name); if (scope != 0) { return 0; } if (num_args == 2) { for (Py_ssize_t i = 0; i < num_args; i++) { expr_ty elt = asdl_seq_GET(e->v.Call.args, i); if (elt->kind == Starred_kind) { return 0; } } // exactly two non-starred args; we can just load // the provided args return 1; } if (num_args != 0) { return 0; } // we need the following for zero-arg super(): // enclosing function should have at least one argument if (c->u->u_metadata.u_argcount == 0 && c->u->u_metadata.u_posonlyargcount == 0) { return 0; } // __class__ cell should be available if (get_ref_type(c, &_Py_ID(__class__)) == FREE) { return 1; } return 0; } static int load_args_for_super(struct compiler *c, expr_ty e) { location loc = LOC(e); // load super() global PyObject *super_name = e->v.Call.func->v.Name.id; RETURN_IF_ERROR(compiler_nameop(c, loc, super_name, Load)); if (asdl_seq_LEN(e->v.Call.args) == 2) { VISIT(c, expr, asdl_seq_GET(e->v.Call.args, 0)); VISIT(c, expr, asdl_seq_GET(e->v.Call.args, 1)); return SUCCESS; } // load __class__ cell PyObject *name = &_Py_ID(__class__); assert(get_ref_type(c, name) == FREE); RETURN_IF_ERROR(compiler_nameop(c, loc, name, Load)); // load self (first argument) Py_ssize_t i = 0; PyObject *key, *value; if (!PyDict_Next(c->u->u_metadata.u_varnames, &i, &key, &value)) { return ERROR; } RETURN_IF_ERROR(compiler_nameop(c, loc, key, Load)); return SUCCESS; } // If an attribute access spans multiple lines, update the current start // location to point to the attribute name. static location update_start_location_to_match_attr(struct compiler *c, location loc, expr_ty attr) { assert(attr->kind == Attribute_kind); if (loc.lineno != attr->end_lineno) { loc.lineno = attr->end_lineno; int len = (int)PyUnicode_GET_LENGTH(attr->v.Attribute.attr); if (len <= attr->end_col_offset) { loc.col_offset = attr->end_col_offset - len; } else { // GH-94694: Somebody's compiling weird ASTs. Just drop the columns: loc.col_offset = -1; loc.end_col_offset = -1; } // Make sure the end position still follows the start position, even for // weird ASTs: loc.end_lineno = Py_MAX(loc.lineno, loc.end_lineno); if (loc.lineno == loc.end_lineno) { loc.end_col_offset = Py_MAX(loc.col_offset, loc.end_col_offset); } } return loc; } // Return 1 if the method call was optimized, 0 if not, and -1 on error. static int maybe_optimize_method_call(struct compiler *c, expr_ty e) { Py_ssize_t argsl, i, kwdsl; expr_ty meth = e->v.Call.func; asdl_expr_seq *args = e->v.Call.args; asdl_keyword_seq *kwds = e->v.Call.keywords; /* Check that the call node is an attribute access */ if (meth->kind != Attribute_kind || meth->v.Attribute.ctx != Load) { return 0; } /* Check that the base object is not something that is imported */ if (is_import_originated(c, meth->v.Attribute.value)) { return 0; } /* Check that there aren't too many arguments */ argsl = asdl_seq_LEN(args); kwdsl = asdl_seq_LEN(kwds); if (argsl + kwdsl + (kwdsl != 0) >= STACK_USE_GUIDELINE) { return 0; } /* Check that there are no *varargs types of arguments. */ for (i = 0; i < argsl; i++) { expr_ty elt = asdl_seq_GET(args, i); if (elt->kind == Starred_kind) { return 0; } } for (i = 0; i < kwdsl; i++) { keyword_ty kw = asdl_seq_GET(kwds, i); if (kw->arg == NULL) { return 0; } } /* Alright, we can optimize the code. */ location loc = LOC(meth); if (can_optimize_super_call(c, meth)) { RETURN_IF_ERROR(load_args_for_super(c, meth->v.Attribute.value)); int opcode = asdl_seq_LEN(meth->v.Attribute.value->v.Call.args) ? LOAD_SUPER_METHOD : LOAD_ZERO_SUPER_METHOD; ADDOP_NAME(c, loc, opcode, meth->v.Attribute.attr, names); loc = update_start_location_to_match_attr(c, loc, meth); ADDOP(c, loc, NOP); } else { VISIT(c, expr, meth->v.Attribute.value); loc = update_start_location_to_match_attr(c, loc, meth); ADDOP_NAME(c, loc, LOAD_METHOD, meth->v.Attribute.attr, names); } VISIT_SEQ(c, expr, e->v.Call.args); if (kwdsl) { VISIT_SEQ(c, keyword, kwds); RETURN_IF_ERROR( compiler_call_simple_kw_helper(c, loc, kwds, kwdsl)); } loc = update_start_location_to_match_attr(c, LOC(e), meth); ADDOP_I(c, loc, CALL, argsl + kwdsl); return 1; } static int validate_keywords(struct compiler *c, asdl_keyword_seq *keywords) { Py_ssize_t nkeywords = asdl_seq_LEN(keywords); for (Py_ssize_t i = 0; i < nkeywords; i++) { keyword_ty key = ((keyword_ty)asdl_seq_GET(keywords, i)); if (key->arg == NULL) { continue; } location loc = LOC(key); if (forbidden_name(c, loc, key->arg, Store)) { return ERROR; } for (Py_ssize_t j = i + 1; j < nkeywords; j++) { keyword_ty other = ((keyword_ty)asdl_seq_GET(keywords, j)); if (other->arg && !PyUnicode_Compare(key->arg, other->arg)) { compiler_error(c, LOC(other), "keyword argument repeated: %U", key->arg); return ERROR; } } } return SUCCESS; } static int compiler_call(struct compiler *c, expr_ty e) { RETURN_IF_ERROR(validate_keywords(c, e->v.Call.keywords)); int ret = maybe_optimize_method_call(c, e); if (ret < 0) { return ERROR; } if (ret == 1) { return SUCCESS; } RETURN_IF_ERROR(check_caller(c, e->v.Call.func)); location loc = LOC(e->v.Call.func); ADDOP(c, loc, PUSH_NULL); VISIT(c, expr, e->v.Call.func); loc = LOC(e); return compiler_call_helper(c, loc, 0, e->v.Call.args, e->v.Call.keywords); } static int compiler_joined_str(struct compiler *c, expr_ty e) { location loc = LOC(e); Py_ssize_t value_count = asdl_seq_LEN(e->v.JoinedStr.values); if (value_count > STACK_USE_GUIDELINE) { _Py_DECLARE_STR(empty, ""); ADDOP_LOAD_CONST_NEW(c, loc, Py_NewRef(&_Py_STR(empty))); ADDOP_NAME(c, loc, LOAD_METHOD, &_Py_ID(join), names); ADDOP_I(c, loc, BUILD_LIST, 0); for (Py_ssize_t i = 0; i < asdl_seq_LEN(e->v.JoinedStr.values); i++) { VISIT(c, expr, asdl_seq_GET(e->v.JoinedStr.values, i)); ADDOP_I(c, loc, LIST_APPEND, 1); } ADDOP_I(c, loc, CALL, 1); } else { VISIT_SEQ(c, expr, e->v.JoinedStr.values); if (asdl_seq_LEN(e->v.JoinedStr.values) != 1) { ADDOP_I(c, loc, BUILD_STRING, asdl_seq_LEN(e->v.JoinedStr.values)); } } return SUCCESS; } /* Used to implement f-strings. Format a single value. */ static int compiler_formatted_value(struct compiler *c, expr_ty e) { /* Our oparg encodes 2 pieces of information: the conversion character, and whether or not a format_spec was provided. Convert the conversion char to 3 bits: : 000 0x0 FVC_NONE The default if nothing specified. !s : 001 0x1 FVC_STR !r : 010 0x2 FVC_REPR !a : 011 0x3 FVC_ASCII next bit is whether or not we have a format spec: yes : 100 0x4 no : 000 0x0 */ int conversion = e->v.FormattedValue.conversion; int oparg; /* The expression to be formatted. */ VISIT(c, expr, e->v.FormattedValue.value); switch (conversion) { case 's': oparg = FVC_STR; break; case 'r': oparg = FVC_REPR; break; case 'a': oparg = FVC_ASCII; break; case -1: oparg = FVC_NONE; break; default: PyErr_Format(PyExc_SystemError, "Unrecognized conversion character %d", conversion); return ERROR; } if (e->v.FormattedValue.format_spec) { /* Evaluate the format spec, and update our opcode arg. */ VISIT(c, expr, e->v.FormattedValue.format_spec); oparg |= FVS_HAVE_SPEC; } /* And push our opcode and oparg */ location loc = LOC(e); ADDOP_I(c, loc, FORMAT_VALUE, oparg); return SUCCESS; } static int compiler_subkwargs(struct compiler *c, location loc, asdl_keyword_seq *keywords, Py_ssize_t begin, Py_ssize_t end) { Py_ssize_t i, n = end - begin; keyword_ty kw; PyObject *keys, *key; assert(n > 0); int big = n*2 > STACK_USE_GUIDELINE; if (n > 1 && !big) { for (i = begin; i < end; i++) { kw = asdl_seq_GET(keywords, i); VISIT(c, expr, kw->value); } keys = PyTuple_New(n); if (keys == NULL) { return ERROR; } for (i = begin; i < end; i++) { key = ((keyword_ty) asdl_seq_GET(keywords, i))->arg; PyTuple_SET_ITEM(keys, i - begin, Py_NewRef(key)); } ADDOP_LOAD_CONST_NEW(c, loc, keys); ADDOP_I(c, loc, BUILD_CONST_KEY_MAP, n); return SUCCESS; } if (big) { ADDOP_I(c, NO_LOCATION, BUILD_MAP, 0); } for (i = begin; i < end; i++) { kw = asdl_seq_GET(keywords, i); ADDOP_LOAD_CONST(c, loc, kw->arg); VISIT(c, expr, kw->value); if (big) { ADDOP_I(c, NO_LOCATION, MAP_ADD, 1); } } if (!big) { ADDOP_I(c, loc, BUILD_MAP, n); } return SUCCESS; } /* Used by compiler_call_helper and maybe_optimize_method_call to emit * KW_NAMES before CALL. */ static int compiler_call_simple_kw_helper(struct compiler *c, location loc, asdl_keyword_seq *keywords, Py_ssize_t nkwelts) { PyObject *names; names = PyTuple_New(nkwelts); if (names == NULL) { return ERROR; } for (int i = 0; i < nkwelts; i++) { keyword_ty kw = asdl_seq_GET(keywords, i); PyTuple_SET_ITEM(names, i, Py_NewRef(kw->arg)); } Py_ssize_t arg = compiler_add_const(c->c_const_cache, c->u, names); if (arg < 0) { return ERROR; } Py_DECREF(names); ADDOP_I(c, loc, KW_NAMES, arg); return SUCCESS; } /* shared code between compiler_call and compiler_class */ static int compiler_call_helper(struct compiler *c, location loc, int n, /* Args already pushed */ asdl_expr_seq *args, asdl_keyword_seq *keywords) { Py_ssize_t i, nseen, nelts, nkwelts; RETURN_IF_ERROR(validate_keywords(c, keywords)); nelts = asdl_seq_LEN(args); nkwelts = asdl_seq_LEN(keywords); if (nelts + nkwelts*2 > STACK_USE_GUIDELINE) { goto ex_call; } for (i = 0; i < nelts; i++) { expr_ty elt = asdl_seq_GET(args, i); if (elt->kind == Starred_kind) { goto ex_call; } } for (i = 0; i < nkwelts; i++) { keyword_ty kw = asdl_seq_GET(keywords, i); if (kw->arg == NULL) { goto ex_call; } } /* No * or ** args, so can use faster calling sequence */ for (i = 0; i < nelts; i++) { expr_ty elt = asdl_seq_GET(args, i); assert(elt->kind != Starred_kind); VISIT(c, expr, elt); } if (nkwelts) { VISIT_SEQ(c, keyword, keywords); RETURN_IF_ERROR( compiler_call_simple_kw_helper(c, loc, keywords, nkwelts)); } ADDOP_I(c, loc, CALL, n + nelts + nkwelts); return SUCCESS; ex_call: /* Do positional arguments. */ if (n ==0 && nelts == 1 && ((expr_ty)asdl_seq_GET(args, 0))->kind == Starred_kind) { VISIT(c, expr, ((expr_ty)asdl_seq_GET(args, 0))->v.Starred.value); } else { RETURN_IF_ERROR(starunpack_helper(c, loc, args, n, BUILD_LIST, LIST_APPEND, LIST_EXTEND, 1)); } /* Then keyword arguments */ if (nkwelts) { /* Has a new dict been pushed */ int have_dict = 0; nseen = 0; /* the number of keyword arguments on the stack following */ for (i = 0; i < nkwelts; i++) { keyword_ty kw = asdl_seq_GET(keywords, i); if (kw->arg == NULL) { /* A keyword argument unpacking. */ if (nseen) { RETURN_IF_ERROR(compiler_subkwargs(c, loc, keywords, i - nseen, i)); if (have_dict) { ADDOP_I(c, loc, DICT_MERGE, 1); } have_dict = 1; nseen = 0; } if (!have_dict) { ADDOP_I(c, loc, BUILD_MAP, 0); have_dict = 1; } VISIT(c, expr, kw->value); ADDOP_I(c, loc, DICT_MERGE, 1); } else { nseen++; } } if (nseen) { /* Pack up any trailing keyword arguments. */ RETURN_IF_ERROR(compiler_subkwargs(c, loc, keywords, nkwelts - nseen, nkwelts)); if (have_dict) { ADDOP_I(c, loc, DICT_MERGE, 1); } have_dict = 1; } assert(have_dict); } ADDOP_I(c, loc, CALL_FUNCTION_EX, nkwelts > 0); return SUCCESS; } /* List and set comprehensions and generator expressions work by creating a nested function to perform the actual iteration. This means that the iteration variables don't leak into the current scope. The defined function is called immediately following its definition, with the result of that call being the result of the expression. The LC/SC version returns the populated container, while the GE version is flagged in symtable.c as a generator, so it returns the generator object when the function is called. Possible cleanups: - iterate over the generator sequence instead of using recursion */ static int compiler_comprehension_generator(struct compiler *c, location loc, asdl_comprehension_seq *generators, int gen_index, int depth, expr_ty elt, expr_ty val, int type, int iter_on_stack) { comprehension_ty gen; gen = (comprehension_ty)asdl_seq_GET(generators, gen_index); if (gen->is_async) { return compiler_async_comprehension_generator( c, loc, generators, gen_index, depth, elt, val, type, iter_on_stack); } else { return compiler_sync_comprehension_generator( c, loc, generators, gen_index, depth, elt, val, type, iter_on_stack); } } static int compiler_sync_comprehension_generator(struct compiler *c, location loc, asdl_comprehension_seq *generators, int gen_index, int depth, expr_ty elt, expr_ty val, int type, int iter_on_stack) { /* generate code for the iterator, then each of the ifs, and then write to the element */ NEW_JUMP_TARGET_LABEL(c, start); NEW_JUMP_TARGET_LABEL(c, if_cleanup); NEW_JUMP_TARGET_LABEL(c, anchor); comprehension_ty gen = (comprehension_ty)asdl_seq_GET(generators, gen_index); if (!iter_on_stack) { if (gen_index == 0) { /* Receive outermost iter as an implicit argument */ c->u->u_metadata.u_argcount = 1; ADDOP_I(c, loc, LOAD_FAST, 0); } else { /* Sub-iter - calculate on the fly */ /* Fast path for the temporary variable assignment idiom: for y in [f(x)] */ asdl_expr_seq *elts; switch (gen->iter->kind) { case List_kind: elts = gen->iter->v.List.elts; break; case Tuple_kind: elts = gen->iter->v.Tuple.elts; break; default: elts = NULL; } if (asdl_seq_LEN(elts) == 1) { expr_ty elt = asdl_seq_GET(elts, 0); if (elt->kind != Starred_kind) { VISIT(c, expr, elt); start = NO_LABEL; } } if (IS_LABEL(start)) { VISIT(c, expr, gen->iter); ADDOP(c, loc, GET_ITER); } } } if (IS_LABEL(start)) { depth++; USE_LABEL(c, start); ADDOP_JUMP(c, loc, FOR_ITER, anchor); } VISIT(c, expr, gen->target); /* XXX this needs to be cleaned up...a lot! */ Py_ssize_t n = asdl_seq_LEN(gen->ifs); for (Py_ssize_t i = 0; i < n; i++) { expr_ty e = (expr_ty)asdl_seq_GET(gen->ifs, i); RETURN_IF_ERROR(compiler_jump_if(c, loc, e, if_cleanup, 0)); } if (++gen_index < asdl_seq_LEN(generators)) { RETURN_IF_ERROR( compiler_comprehension_generator(c, loc, generators, gen_index, depth, elt, val, type, 0)); } location elt_loc = LOC(elt); /* only append after the last for generator */ if (gen_index >= asdl_seq_LEN(generators)) { /* comprehension specific code */ switch (type) { case COMP_GENEXP: VISIT(c, expr, elt); ADDOP_YIELD(c, elt_loc); ADDOP(c, elt_loc, POP_TOP); break; case COMP_LISTCOMP: VISIT(c, expr, elt); ADDOP_I(c, elt_loc, LIST_APPEND, depth + 1); break; case COMP_SETCOMP: VISIT(c, expr, elt); ADDOP_I(c, elt_loc, SET_ADD, depth + 1); break; case COMP_DICTCOMP: /* With '{k: v}', k is evaluated before v, so we do the same. */ VISIT(c, expr, elt); VISIT(c, expr, val); elt_loc = LOCATION(elt->lineno, val->end_lineno, elt->col_offset, val->end_col_offset); ADDOP_I(c, elt_loc, MAP_ADD, depth + 1); break; default: return ERROR; } } USE_LABEL(c, if_cleanup); if (IS_LABEL(start)) { ADDOP_JUMP(c, elt_loc, JUMP, start); USE_LABEL(c, anchor); ADDOP(c, NO_LOCATION, END_FOR); } return SUCCESS; } static int compiler_async_comprehension_generator(struct compiler *c, location loc, asdl_comprehension_seq *generators, int gen_index, int depth, expr_ty elt, expr_ty val, int type, int iter_on_stack) { NEW_JUMP_TARGET_LABEL(c, start); NEW_JUMP_TARGET_LABEL(c, except); NEW_JUMP_TARGET_LABEL(c, if_cleanup); comprehension_ty gen = (comprehension_ty)asdl_seq_GET(generators, gen_index); if (!iter_on_stack) { if (gen_index == 0) { /* Receive outermost iter as an implicit argument */ c->u->u_metadata.u_argcount = 1; ADDOP_I(c, loc, LOAD_FAST, 0); } else { /* Sub-iter - calculate on the fly */ VISIT(c, expr, gen->iter); ADDOP(c, loc, GET_AITER); } } USE_LABEL(c, start); /* Runtime will push a block here, so we need to account for that */ RETURN_IF_ERROR( compiler_push_fblock(c, loc, ASYNC_COMPREHENSION_GENERATOR, start, NO_LABEL, NULL)); ADDOP_JUMP(c, loc, SETUP_FINALLY, except); ADDOP(c, loc, GET_ANEXT); ADDOP_LOAD_CONST(c, loc, Py_None); ADD_YIELD_FROM(c, loc, 1); ADDOP(c, loc, POP_BLOCK); VISIT(c, expr, gen->target); Py_ssize_t n = asdl_seq_LEN(gen->ifs); for (Py_ssize_t i = 0; i < n; i++) { expr_ty e = (expr_ty)asdl_seq_GET(gen->ifs, i); RETURN_IF_ERROR(compiler_jump_if(c, loc, e, if_cleanup, 0)); } depth++; if (++gen_index < asdl_seq_LEN(generators)) { RETURN_IF_ERROR( compiler_comprehension_generator(c, loc, generators, gen_index, depth, elt, val, type, 0)); } location elt_loc = LOC(elt); /* only append after the last for generator */ if (gen_index >= asdl_seq_LEN(generators)) { /* comprehension specific code */ switch (type) { case COMP_GENEXP: VISIT(c, expr, elt); ADDOP_YIELD(c, elt_loc); ADDOP(c, elt_loc, POP_TOP); break; case COMP_LISTCOMP: VISIT(c, expr, elt); ADDOP_I(c, elt_loc, LIST_APPEND, depth + 1); break; case COMP_SETCOMP: VISIT(c, expr, elt); ADDOP_I(c, elt_loc, SET_ADD, depth + 1); break; case COMP_DICTCOMP: /* With '{k: v}', k is evaluated before v, so we do the same. */ VISIT(c, expr, elt); VISIT(c, expr, val); elt_loc = LOCATION(elt->lineno, val->end_lineno, elt->col_offset, val->end_col_offset); ADDOP_I(c, elt_loc, MAP_ADD, depth + 1); break; default: return ERROR; } } USE_LABEL(c, if_cleanup); ADDOP_JUMP(c, elt_loc, JUMP, start); compiler_pop_fblock(c, ASYNC_COMPREHENSION_GENERATOR, start); USE_LABEL(c, except); ADDOP(c, loc, END_ASYNC_FOR); return SUCCESS; } typedef struct { PyObject *pushed_locals; PyObject *temp_symbols; PyObject *fast_hidden; } inlined_comprehension_state; static int push_inlined_comprehension_state(struct compiler *c, location loc, PySTEntryObject *entry, inlined_comprehension_state *state) { int in_class_block = (c->u->u_ste->ste_type == ClassBlock) && !c->u->u_in_inlined_comp; c->u->u_in_inlined_comp++; // iterate over names bound in the comprehension and ensure we isolate // them from the outer scope as needed PyObject *k, *v; Py_ssize_t pos = 0; while (PyDict_Next(entry->ste_symbols, &pos, &k, &v)) { assert(PyLong_Check(v)); long symbol = PyLong_AS_LONG(v); // only values bound in the comprehension (DEF_LOCAL) need to be handled // at all; DEF_LOCAL | DEF_NONLOCAL can occur in the case of an // assignment expression to a nonlocal in the comprehension, these don't // need handling here since they shouldn't be isolated if ((symbol & DEF_LOCAL && !(symbol & DEF_NONLOCAL)) || in_class_block) { if (!_PyST_IsFunctionLike(c->u->u_ste)) { // non-function scope: override this name to use fast locals PyObject *orig = PyDict_GetItem(c->u->u_metadata.u_fasthidden, k); if (orig != Py_True) { if (PyDict_SetItem(c->u->u_metadata.u_fasthidden, k, Py_True) < 0) { return ERROR; } if (state->fast_hidden == NULL) { state->fast_hidden = PySet_New(NULL); if (state->fast_hidden == NULL) { return ERROR; } } if (PySet_Add(state->fast_hidden, k) < 0) { return ERROR; } } } long scope = (symbol >> SCOPE_OFFSET) & SCOPE_MASK; PyObject *outv = PyDict_GetItemWithError(c->u->u_ste->ste_symbols, k); if (outv == NULL) { outv = _PyLong_GetZero(); } assert(PyLong_Check(outv)); long outsc = (PyLong_AS_LONG(outv) >> SCOPE_OFFSET) & SCOPE_MASK; if (scope != outsc && !(scope == CELL && outsc == FREE)) { // If a name has different scope inside than outside the // comprehension, we need to temporarily handle it with the // right scope while compiling the comprehension. (If it's free // in outer scope and cell in inner scope, we can't treat it as // both cell and free in the same function, but treating it as // free throughout is fine; it's *_DEREF either way.) if (state->temp_symbols == NULL) { state->temp_symbols = PyDict_New(); if (state->temp_symbols == NULL) { return ERROR; } } // update the symbol to the in-comprehension version and save // the outer version; we'll restore it after running the // comprehension Py_INCREF(outv); if (PyDict_SetItem(c->u->u_ste->ste_symbols, k, v) < 0) { Py_DECREF(outv); return ERROR; } if (PyDict_SetItem(state->temp_symbols, k, outv) < 0) { Py_DECREF(outv); return ERROR; } Py_DECREF(outv); } // local names bound in comprehension must be isolated from // outer scope; push existing value (which may be NULL if // not defined) on stack if (state->pushed_locals == NULL) { state->pushed_locals = PyList_New(0); if (state->pushed_locals == NULL) { return ERROR; } } // in the case of a cell, this will actually push the cell // itself to the stack, then we'll create a new one for the // comprehension and restore the original one after ADDOP_NAME(c, loc, LOAD_FAST_AND_CLEAR, k, varnames); if (scope == CELL) { if (outsc == FREE) { ADDOP_NAME(c, loc, MAKE_CELL, k, freevars); } else { ADDOP_NAME(c, loc, MAKE_CELL, k, cellvars); } } if (PyList_Append(state->pushed_locals, k) < 0) { return ERROR; } } } if (state->pushed_locals) { // Outermost iterable expression was already evaluated and is on the // stack, we need to swap it back to TOS. This also rotates the order of // `pushed_locals` on the stack, but this will be reversed when we swap // out the comprehension result in pop_inlined_comprehension_state ADDOP_I(c, loc, SWAP, PyList_GET_SIZE(state->pushed_locals) + 1); } return SUCCESS; } static int pop_inlined_comprehension_state(struct compiler *c, location loc, inlined_comprehension_state state) { c->u->u_in_inlined_comp--; PyObject *k, *v; Py_ssize_t pos = 0; if (state.temp_symbols) { while (PyDict_Next(state.temp_symbols, &pos, &k, &v)) { if (PyDict_SetItem(c->u->u_ste->ste_symbols, k, v)) { return ERROR; } } Py_CLEAR(state.temp_symbols); } if (state.pushed_locals) { // pop names we pushed to stack earlier Py_ssize_t npops = PyList_GET_SIZE(state.pushed_locals); // Preserve the list/dict/set result of the comprehension as TOS. This // reverses the SWAP we did in push_inlined_comprehension_state to get // the outermost iterable to TOS, so we can still just iterate // pushed_locals in simple reverse order ADDOP_I(c, loc, SWAP, npops + 1); for (Py_ssize_t i = npops - 1; i >= 0; --i) { k = PyList_GetItem(state.pushed_locals, i); if (k == NULL) { return ERROR; } ADDOP_NAME(c, loc, STORE_FAST_MAYBE_NULL, k, varnames); } Py_CLEAR(state.pushed_locals); } if (state.fast_hidden) { while (PySet_Size(state.fast_hidden) > 0) { PyObject *k = PySet_Pop(state.fast_hidden); if (k == NULL) { return ERROR; } // we set to False instead of clearing, so we can track which names // were temporarily fast-locals and should use CO_FAST_HIDDEN if (PyDict_SetItem(c->u->u_metadata.u_fasthidden, k, Py_False)) { Py_DECREF(k); return ERROR; } Py_DECREF(k); } Py_CLEAR(state.fast_hidden); } return SUCCESS; } static inline int compiler_comprehension_iter(struct compiler *c, location loc, comprehension_ty comp) { VISIT(c, expr, comp->iter); if (comp->is_async) { ADDOP(c, loc, GET_AITER); } else { ADDOP(c, loc, GET_ITER); } return SUCCESS; } static int compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name, asdl_comprehension_seq *generators, expr_ty elt, expr_ty val) { PyCodeObject *co = NULL; inlined_comprehension_state inline_state = {NULL, NULL}; comprehension_ty outermost; int scope_type = c->u->u_scope_type; int is_top_level_await = IS_TOP_LEVEL_AWAIT(c); PySTEntryObject *entry = PySymtable_Lookup(c->c_st, (void *)e); if (entry == NULL) { goto error; } int is_inlined = entry->ste_comp_inlined; int is_async_generator = entry->ste_coroutine; location loc = LOC(e); outermost = (comprehension_ty) asdl_seq_GET(generators, 0); if (is_inlined) { if (compiler_comprehension_iter(c, loc, outermost)) { goto error; } if (push_inlined_comprehension_state(c, loc, entry, &inline_state)) { goto error; } } else { if (compiler_enter_scope(c, name, COMPILER_SCOPE_COMPREHENSION, (void *)e, e->lineno) < 0) { goto error; } } Py_CLEAR(entry); if (is_async_generator && type != COMP_GENEXP && scope_type != COMPILER_SCOPE_ASYNC_FUNCTION && scope_type != COMPILER_SCOPE_COMPREHENSION && !is_top_level_await) { compiler_error(c, loc, "asynchronous comprehension outside of " "an asynchronous function"); goto error_in_scope; } if (type != COMP_GENEXP) { int op; switch (type) { case COMP_LISTCOMP: op = BUILD_LIST; break; case COMP_SETCOMP: op = BUILD_SET; break; case COMP_DICTCOMP: op = BUILD_MAP; break; default: PyErr_Format(PyExc_SystemError, "unknown comprehension type %d", type); goto error_in_scope; } ADDOP_I(c, loc, op, 0); if (is_inlined) { ADDOP_I(c, loc, SWAP, 2); } } if (compiler_comprehension_generator(c, loc, generators, 0, 0, elt, val, type, is_inlined) < 0) { goto error_in_scope; } if (is_inlined) { if (pop_inlined_comprehension_state(c, loc, inline_state)) { goto error; } return SUCCESS; } if (type != COMP_GENEXP) { ADDOP(c, LOC(e), RETURN_VALUE); } if (type == COMP_GENEXP) { if (wrap_in_stopiteration_handler(c) < 0) { goto error_in_scope; } } co = optimize_and_assemble(c, 1); compiler_exit_scope(c); if (is_top_level_await && is_async_generator){ c->u->u_ste->ste_coroutine = 1; } if (co == NULL) { goto error; } loc = LOC(e); if (compiler_make_closure(c, loc, co, 0) < 0) { goto error; } Py_CLEAR(co); if (compiler_comprehension_iter(c, loc, outermost)) { goto error; } ADDOP_I(c, loc, CALL, 0); if (is_async_generator && type != COMP_GENEXP) { ADDOP_I(c, loc, GET_AWAITABLE, 0); ADDOP_LOAD_CONST(c, loc, Py_None); ADD_YIELD_FROM(c, loc, 1); } return SUCCESS; error_in_scope: if (!is_inlined) { compiler_exit_scope(c); } error: Py_XDECREF(co); Py_XDECREF(entry); Py_XDECREF(inline_state.pushed_locals); Py_XDECREF(inline_state.temp_symbols); Py_XDECREF(inline_state.fast_hidden); return ERROR; } static int compiler_genexp(struct compiler *c, expr_ty e) { assert(e->kind == GeneratorExp_kind); _Py_DECLARE_STR(anon_genexpr, ""); return compiler_comprehension(c, e, COMP_GENEXP, &_Py_STR(anon_genexpr), e->v.GeneratorExp.generators, e->v.GeneratorExp.elt, NULL); } static int compiler_listcomp(struct compiler *c, expr_ty e) { assert(e->kind == ListComp_kind); _Py_DECLARE_STR(anon_listcomp, ""); return compiler_comprehension(c, e, COMP_LISTCOMP, &_Py_STR(anon_listcomp), e->v.ListComp.generators, e->v.ListComp.elt, NULL); } static int compiler_setcomp(struct compiler *c, expr_ty e) { assert(e->kind == SetComp_kind); _Py_DECLARE_STR(anon_setcomp, ""); return compiler_comprehension(c, e, COMP_SETCOMP, &_Py_STR(anon_setcomp), e->v.SetComp.generators, e->v.SetComp.elt, NULL); } static int compiler_dictcomp(struct compiler *c, expr_ty e) { assert(e->kind == DictComp_kind); _Py_DECLARE_STR(anon_dictcomp, ""); return compiler_comprehension(c, e, COMP_DICTCOMP, &_Py_STR(anon_dictcomp), e->v.DictComp.generators, e->v.DictComp.key, e->v.DictComp.value); } static int compiler_visit_keyword(struct compiler *c, keyword_ty k) { VISIT(c, expr, k->value); return SUCCESS; } static int compiler_with_except_finish(struct compiler *c, jump_target_label cleanup) { NEW_JUMP_TARGET_LABEL(c, suppress); ADDOP_JUMP(c, NO_LOCATION, POP_JUMP_IF_TRUE, suppress); ADDOP_I(c, NO_LOCATION, RERAISE, 2); USE_LABEL(c, suppress); ADDOP(c, NO_LOCATION, POP_TOP); /* exc_value */ ADDOP(c, NO_LOCATION, POP_BLOCK); ADDOP(c, NO_LOCATION, POP_EXCEPT); ADDOP(c, NO_LOCATION, POP_TOP); ADDOP(c, NO_LOCATION, POP_TOP); NEW_JUMP_TARGET_LABEL(c, exit); ADDOP_JUMP(c, NO_LOCATION, JUMP, exit); USE_LABEL(c, cleanup); POP_EXCEPT_AND_RERAISE(c, NO_LOCATION); USE_LABEL(c, exit); return SUCCESS; } /* Implements the async with statement. The semantics outlined in that PEP are as follows: async with EXPR as VAR: BLOCK It is implemented roughly as: context = EXPR exit = context.__aexit__ # not calling it value = await context.__aenter__() try: VAR = value # if VAR present in the syntax BLOCK finally: if an exception was raised: exc = copy of (exception, instance, traceback) else: exc = (None, None, None) if not (await exit(*exc)): raise */ static int compiler_async_with(struct compiler *c, stmt_ty s, int pos) { location loc = LOC(s); withitem_ty item = asdl_seq_GET(s->v.AsyncWith.items, pos); assert(s->kind == AsyncWith_kind); if (IS_TOP_LEVEL_AWAIT(c)){ c->u->u_ste->ste_coroutine = 1; } else if (c->u->u_scope_type != COMPILER_SCOPE_ASYNC_FUNCTION){ return compiler_error(c, loc, "'async with' outside async function"); } NEW_JUMP_TARGET_LABEL(c, block); NEW_JUMP_TARGET_LABEL(c, final); NEW_JUMP_TARGET_LABEL(c, exit); NEW_JUMP_TARGET_LABEL(c, cleanup); /* Evaluate EXPR */ VISIT(c, expr, item->context_expr); ADDOP(c, loc, BEFORE_ASYNC_WITH); ADDOP_I(c, loc, GET_AWAITABLE, 1); ADDOP_LOAD_CONST(c, loc, Py_None); ADD_YIELD_FROM(c, loc, 1); ADDOP_JUMP(c, loc, SETUP_WITH, final); /* SETUP_WITH pushes a finally block. */ USE_LABEL(c, block); RETURN_IF_ERROR(compiler_push_fblock(c, loc, ASYNC_WITH, block, final, s)); if (item->optional_vars) { VISIT(c, expr, item->optional_vars); } else { /* Discard result from context.__aenter__() */ ADDOP(c, loc, POP_TOP); } pos++; if (pos == asdl_seq_LEN(s->v.AsyncWith.items)) { /* BLOCK code */ VISIT_SEQ(c, stmt, s->v.AsyncWith.body) } else { RETURN_IF_ERROR(compiler_async_with(c, s, pos)); } compiler_pop_fblock(c, ASYNC_WITH, block); ADDOP(c, loc, POP_BLOCK); /* End of body; start the cleanup */ /* For successful outcome: * call __exit__(None, None, None) */ RETURN_IF_ERROR(compiler_call_exit_with_nones(c, loc)); ADDOP_I(c, loc, GET_AWAITABLE, 2); ADDOP_LOAD_CONST(c, loc, Py_None); ADD_YIELD_FROM(c, loc, 1); ADDOP(c, loc, POP_TOP); ADDOP_JUMP(c, loc, JUMP, exit); /* For exceptional outcome: */ USE_LABEL(c, final); ADDOP_JUMP(c, loc, SETUP_CLEANUP, cleanup); ADDOP(c, loc, PUSH_EXC_INFO); ADDOP(c, loc, WITH_EXCEPT_START); ADDOP_I(c, loc, GET_AWAITABLE, 2); ADDOP_LOAD_CONST(c, loc, Py_None); ADD_YIELD_FROM(c, loc, 1); RETURN_IF_ERROR(compiler_with_except_finish(c, cleanup)); USE_LABEL(c, exit); return SUCCESS; } /* Implements the with statement from PEP 343. with EXPR as VAR: BLOCK is implemented as: SETUP_WITH E or POP_TOP LOAD_CONST (None, None, None) CALL_FUNCTION_EX 0 JUMP EXIT E: WITH_EXCEPT_START (calls EXPR.__exit__) POP_JUMP_IF_TRUE T: RERAISE T: POP_TOP (remove exception from stack) POP_EXCEPT POP_TOP EXIT: */ static int compiler_with(struct compiler *c, stmt_ty s, int pos) { withitem_ty item = asdl_seq_GET(s->v.With.items, pos); assert(s->kind == With_kind); NEW_JUMP_TARGET_LABEL(c, block); NEW_JUMP_TARGET_LABEL(c, final); NEW_JUMP_TARGET_LABEL(c, exit); NEW_JUMP_TARGET_LABEL(c, cleanup); /* Evaluate EXPR */ VISIT(c, expr, item->context_expr); /* Will push bound __exit__ */ location loc = LOC(s); ADDOP(c, loc, BEFORE_WITH); ADDOP_JUMP(c, loc, SETUP_WITH, final); /* SETUP_WITH pushes a finally block. */ USE_LABEL(c, block); RETURN_IF_ERROR(compiler_push_fblock(c, loc, WITH, block, final, s)); if (item->optional_vars) { VISIT(c, expr, item->optional_vars); } else { /* Discard result from context.__enter__() */ ADDOP(c, loc, POP_TOP); } pos++; if (pos == asdl_seq_LEN(s->v.With.items)) { /* BLOCK code */ VISIT_SEQ(c, stmt, s->v.With.body) } else { RETURN_IF_ERROR(compiler_with(c, s, pos)); } ADDOP(c, NO_LOCATION, POP_BLOCK); compiler_pop_fblock(c, WITH, block); /* End of body; start the cleanup. */ /* For successful outcome: * call __exit__(None, None, None) */ loc = LOC(s); RETURN_IF_ERROR(compiler_call_exit_with_nones(c, loc)); ADDOP(c, loc, POP_TOP); ADDOP_JUMP(c, loc, JUMP, exit); /* For exceptional outcome: */ USE_LABEL(c, final); ADDOP_JUMP(c, loc, SETUP_CLEANUP, cleanup); ADDOP(c, loc, PUSH_EXC_INFO); ADDOP(c, loc, WITH_EXCEPT_START); RETURN_IF_ERROR(compiler_with_except_finish(c, cleanup)); USE_LABEL(c, exit); return SUCCESS; } static int compiler_visit_expr1(struct compiler *c, expr_ty e) { location loc = LOC(e); switch (e->kind) { case NamedExpr_kind: VISIT(c, expr, e->v.NamedExpr.value); ADDOP_I(c, loc, COPY, 1); VISIT(c, expr, e->v.NamedExpr.target); break; case BoolOp_kind: return compiler_boolop(c, e); case BinOp_kind: VISIT(c, expr, e->v.BinOp.left); VISIT(c, expr, e->v.BinOp.right); ADDOP_BINARY(c, loc, e->v.BinOp.op); break; case UnaryOp_kind: VISIT(c, expr, e->v.UnaryOp.operand); if (e->v.UnaryOp.op == UAdd) { ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_UNARY_POSITIVE); } else { ADDOP(c, loc, unaryop(e->v.UnaryOp.op)); } break; case Lambda_kind: return compiler_lambda(c, e); case IfExp_kind: return compiler_ifexp(c, e); case Dict_kind: return compiler_dict(c, e); case Set_kind: return compiler_set(c, e); case GeneratorExp_kind: return compiler_genexp(c, e); case ListComp_kind: return compiler_listcomp(c, e); case SetComp_kind: return compiler_setcomp(c, e); case DictComp_kind: return compiler_dictcomp(c, e); case Yield_kind: if (!_PyST_IsFunctionLike(c->u->u_ste)) { return compiler_error(c, loc, "'yield' outside function"); } if (e->v.Yield.value) { VISIT(c, expr, e->v.Yield.value); } else { ADDOP_LOAD_CONST(c, loc, Py_None); } ADDOP_YIELD(c, loc); break; case YieldFrom_kind: if (!_PyST_IsFunctionLike(c->u->u_ste)) { return compiler_error(c, loc, "'yield' outside function"); } if (c->u->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION) { return compiler_error(c, loc, "'yield from' inside async function"); } VISIT(c, expr, e->v.YieldFrom.value); ADDOP(c, loc, GET_YIELD_FROM_ITER); ADDOP_LOAD_CONST(c, loc, Py_None); ADD_YIELD_FROM(c, loc, 0); break; case Await_kind: if (!IS_TOP_LEVEL_AWAIT(c)){ if (!_PyST_IsFunctionLike(c->u->u_ste)) { return compiler_error(c, loc, "'await' outside function"); } if (c->u->u_scope_type != COMPILER_SCOPE_ASYNC_FUNCTION && c->u->u_scope_type != COMPILER_SCOPE_COMPREHENSION) { return compiler_error(c, loc, "'await' outside async function"); } } VISIT(c, expr, e->v.Await.value); ADDOP_I(c, loc, GET_AWAITABLE, 0); ADDOP_LOAD_CONST(c, loc, Py_None); ADD_YIELD_FROM(c, loc, 1); break; case Compare_kind: return compiler_compare(c, e); case Call_kind: return compiler_call(c, e); case Constant_kind: ADDOP_LOAD_CONST(c, loc, e->v.Constant.value); break; case JoinedStr_kind: return compiler_joined_str(c, e); case FormattedValue_kind: return compiler_formatted_value(c, e); /* The following exprs can be assignment targets. */ case Attribute_kind: if (e->v.Attribute.ctx == Load && can_optimize_super_call(c, e)) { RETURN_IF_ERROR(load_args_for_super(c, e->v.Attribute.value)); int opcode = asdl_seq_LEN(e->v.Attribute.value->v.Call.args) ? LOAD_SUPER_ATTR : LOAD_ZERO_SUPER_ATTR; ADDOP_NAME(c, loc, opcode, e->v.Attribute.attr, names); loc = update_start_location_to_match_attr(c, loc, e); ADDOP(c, loc, NOP); return SUCCESS; } VISIT(c, expr, e->v.Attribute.value); loc = LOC(e); loc = update_start_location_to_match_attr(c, loc, e); switch (e->v.Attribute.ctx) { case Load: ADDOP_NAME(c, loc, LOAD_ATTR, e->v.Attribute.attr, names); break; case Store: if (forbidden_name(c, loc, e->v.Attribute.attr, e->v.Attribute.ctx)) { return ERROR; } ADDOP_NAME(c, loc, STORE_ATTR, e->v.Attribute.attr, names); break; case Del: ADDOP_NAME(c, loc, DELETE_ATTR, e->v.Attribute.attr, names); break; } break; case Subscript_kind: return compiler_subscript(c, e); case Starred_kind: switch (e->v.Starred.ctx) { case Store: /* In all legitimate cases, the Starred node was already replaced * by compiler_list/compiler_tuple. XXX: is that okay? */ return compiler_error(c, loc, "starred assignment target must be in a list or tuple"); default: return compiler_error(c, loc, "can't use starred expression here"); } break; case Slice_kind: { int n = compiler_slice(c, e); RETURN_IF_ERROR(n); ADDOP_I(c, loc, BUILD_SLICE, n); break; } case Name_kind: return compiler_nameop(c, loc, e->v.Name.id, e->v.Name.ctx); /* child nodes of List and Tuple will have expr_context set */ case List_kind: return compiler_list(c, e); case Tuple_kind: return compiler_tuple(c, e); } return SUCCESS; } static int compiler_visit_expr(struct compiler *c, expr_ty e) { int res = compiler_visit_expr1(c, e); return res; } static bool is_two_element_slice(expr_ty s) { return s->kind == Slice_kind && s->v.Slice.step == NULL; } static int compiler_augassign(struct compiler *c, stmt_ty s) { assert(s->kind == AugAssign_kind); expr_ty e = s->v.AugAssign.target; location loc = LOC(e); switch (e->kind) { case Attribute_kind: VISIT(c, expr, e->v.Attribute.value); ADDOP_I(c, loc, COPY, 1); loc = update_start_location_to_match_attr(c, loc, e); ADDOP_NAME(c, loc, LOAD_ATTR, e->v.Attribute.attr, names); break; case Subscript_kind: VISIT(c, expr, e->v.Subscript.value); if (is_two_element_slice(e->v.Subscript.slice)) { RETURN_IF_ERROR(compiler_slice(c, e->v.Subscript.slice)); ADDOP_I(c, loc, COPY, 3); ADDOP_I(c, loc, COPY, 3); ADDOP_I(c, loc, COPY, 3); ADDOP(c, loc, BINARY_SLICE); } else { VISIT(c, expr, e->v.Subscript.slice); ADDOP_I(c, loc, COPY, 2); ADDOP_I(c, loc, COPY, 2); ADDOP(c, loc, BINARY_SUBSCR); } break; case Name_kind: RETURN_IF_ERROR(compiler_nameop(c, loc, e->v.Name.id, Load)); break; default: PyErr_Format(PyExc_SystemError, "invalid node type (%d) for augmented assignment", e->kind); return ERROR; } loc = LOC(s); VISIT(c, expr, s->v.AugAssign.value); ADDOP_INPLACE(c, loc, s->v.AugAssign.op); loc = LOC(e); switch (e->kind) { case Attribute_kind: loc = update_start_location_to_match_attr(c, loc, e); ADDOP_I(c, loc, SWAP, 2); ADDOP_NAME(c, loc, STORE_ATTR, e->v.Attribute.attr, names); break; case Subscript_kind: if (is_two_element_slice(e->v.Subscript.slice)) { ADDOP_I(c, loc, SWAP, 4); ADDOP_I(c, loc, SWAP, 3); ADDOP_I(c, loc, SWAP, 2); ADDOP(c, loc, STORE_SLICE); } else { ADDOP_I(c, loc, SWAP, 3); ADDOP_I(c, loc, SWAP, 2); ADDOP(c, loc, STORE_SUBSCR); } break; case Name_kind: return compiler_nameop(c, loc, e->v.Name.id, Store); default: Py_UNREACHABLE(); } return SUCCESS; } static int check_ann_expr(struct compiler *c, expr_ty e) { VISIT(c, expr, e); ADDOP(c, LOC(e), POP_TOP); return SUCCESS; } static int check_annotation(struct compiler *c, stmt_ty s) { /* Annotations of complex targets does not produce anything under annotations future */ if (c->c_future.ff_features & CO_FUTURE_ANNOTATIONS) { return SUCCESS; } /* Annotations are only evaluated in a module or class. */ if (c->u->u_scope_type == COMPILER_SCOPE_MODULE || c->u->u_scope_type == COMPILER_SCOPE_CLASS) { return check_ann_expr(c, s->v.AnnAssign.annotation); } return SUCCESS; } static int check_ann_subscr(struct compiler *c, expr_ty e) { /* We check that everything in a subscript is defined at runtime. */ switch (e->kind) { case Slice_kind: if (e->v.Slice.lower && check_ann_expr(c, e->v.Slice.lower) < 0) { return ERROR; } if (e->v.Slice.upper && check_ann_expr(c, e->v.Slice.upper) < 0) { return ERROR; } if (e->v.Slice.step && check_ann_expr(c, e->v.Slice.step) < 0) { return ERROR; } return SUCCESS; case Tuple_kind: { /* extended slice */ asdl_expr_seq *elts = e->v.Tuple.elts; Py_ssize_t i, n = asdl_seq_LEN(elts); for (i = 0; i < n; i++) { RETURN_IF_ERROR(check_ann_subscr(c, asdl_seq_GET(elts, i))); } return SUCCESS; } default: return check_ann_expr(c, e); } } static int compiler_annassign(struct compiler *c, stmt_ty s) { location loc = LOC(s); expr_ty targ = s->v.AnnAssign.target; PyObject* mangled; assert(s->kind == AnnAssign_kind); /* We perform the actual assignment first. */ if (s->v.AnnAssign.value) { VISIT(c, expr, s->v.AnnAssign.value); VISIT(c, expr, targ); } switch (targ->kind) { case Name_kind: if (forbidden_name(c, loc, targ->v.Name.id, Store)) { return ERROR; } /* If we have a simple name in a module or class, store annotation. */ if (s->v.AnnAssign.simple && (c->u->u_scope_type == COMPILER_SCOPE_MODULE || c->u->u_scope_type == COMPILER_SCOPE_CLASS)) { if (c->c_future.ff_features & CO_FUTURE_ANNOTATIONS) { VISIT(c, annexpr, s->v.AnnAssign.annotation) } else { VISIT(c, expr, s->v.AnnAssign.annotation); } ADDOP_NAME(c, loc, LOAD_NAME, &_Py_ID(__annotations__), names); mangled = _Py_Mangle(c->u->u_private, targ->v.Name.id); ADDOP_LOAD_CONST_NEW(c, loc, mangled); ADDOP(c, loc, STORE_SUBSCR); } break; case Attribute_kind: if (forbidden_name(c, loc, targ->v.Attribute.attr, Store)) { return ERROR; } if (!s->v.AnnAssign.value && check_ann_expr(c, targ->v.Attribute.value) < 0) { return ERROR; } break; case Subscript_kind: if (!s->v.AnnAssign.value && (check_ann_expr(c, targ->v.Subscript.value) < 0 || check_ann_subscr(c, targ->v.Subscript.slice) < 0)) { return ERROR; } break; default: PyErr_Format(PyExc_SystemError, "invalid node type (%d) for annotated assignment", targ->kind); return ERROR; } /* Annotation is evaluated last. */ if (!s->v.AnnAssign.simple && check_annotation(c, s) < 0) { return ERROR; } return SUCCESS; } /* Raises a SyntaxError and returns 0. If something goes wrong, a different exception may be raised. */ static int compiler_error(struct compiler *c, location loc, const char *format, ...) { va_list vargs; va_start(vargs, format); PyObject *msg = PyUnicode_FromFormatV(format, vargs); va_end(vargs); if (msg == NULL) { return ERROR; } PyObject *loc_obj = PyErr_ProgramTextObject(c->c_filename, loc.lineno); if (loc_obj == NULL) { loc_obj = Py_None; } PyObject *args = Py_BuildValue("O(OiiOii)", msg, c->c_filename, loc.lineno, loc.col_offset + 1, loc_obj, loc.end_lineno, loc.end_col_offset + 1); Py_DECREF(msg); if (args == NULL) { goto exit; } PyErr_SetObject(PyExc_SyntaxError, args); exit: Py_DECREF(loc_obj); Py_XDECREF(args); return ERROR; } /* Emits a SyntaxWarning and returns 1 on success. If a SyntaxWarning raised as error, replaces it with a SyntaxError and returns 0. */ static int compiler_warn(struct compiler *c, location loc, const char *format, ...) { va_list vargs; va_start(vargs, format); PyObject *msg = PyUnicode_FromFormatV(format, vargs); va_end(vargs); if (msg == NULL) { return ERROR; } if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, c->c_filename, loc.lineno, NULL, NULL) < 0) { if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { /* Replace the SyntaxWarning exception with a SyntaxError to get a more accurate error report */ PyErr_Clear(); assert(PyUnicode_AsUTF8(msg) != NULL); compiler_error(c, loc, PyUnicode_AsUTF8(msg)); } Py_DECREF(msg); return ERROR; } Py_DECREF(msg); return SUCCESS; } static int compiler_subscript(struct compiler *c, expr_ty e) { location loc = LOC(e); expr_context_ty ctx = e->v.Subscript.ctx; int op = 0; if (ctx == Load) { RETURN_IF_ERROR(check_subscripter(c, e->v.Subscript.value)); RETURN_IF_ERROR(check_index(c, e->v.Subscript.value, e->v.Subscript.slice)); } VISIT(c, expr, e->v.Subscript.value); if (is_two_element_slice(e->v.Subscript.slice) && ctx != Del) { RETURN_IF_ERROR(compiler_slice(c, e->v.Subscript.slice)); if (ctx == Load) { ADDOP(c, loc, BINARY_SLICE); } else { assert(ctx == Store); ADDOP(c, loc, STORE_SLICE); } } else { VISIT(c, expr, e->v.Subscript.slice); switch (ctx) { case Load: op = BINARY_SUBSCR; break; case Store: op = STORE_SUBSCR; break; case Del: op = DELETE_SUBSCR; break; } assert(op); ADDOP(c, loc, op); } return SUCCESS; } /* Returns the number of the values emitted, * thus are needed to build the slice, or -1 if there is an error. */ static int compiler_slice(struct compiler *c, expr_ty s) { int n = 2; assert(s->kind == Slice_kind); /* only handles the cases where BUILD_SLICE is emitted */ if (s->v.Slice.lower) { VISIT(c, expr, s->v.Slice.lower); } else { ADDOP_LOAD_CONST(c, LOC(s), Py_None); } if (s->v.Slice.upper) { VISIT(c, expr, s->v.Slice.upper); } else { ADDOP_LOAD_CONST(c, LOC(s), Py_None); } if (s->v.Slice.step) { n++; VISIT(c, expr, s->v.Slice.step); } return n; } // PEP 634: Structural Pattern Matching // To keep things simple, all compiler_pattern_* and pattern_helper_* routines // follow the convention of consuming TOS (the subject for the given pattern) // and calling jump_to_fail_pop on failure (no match). // When calling into these routines, it's important that pc->on_top be kept // updated to reflect the current number of items that we are using on the top // of the stack: they will be popped on failure, and any name captures will be // stored *underneath* them on success. This lets us defer all names stores // until the *entire* pattern matches. #define WILDCARD_CHECK(N) \ ((N)->kind == MatchAs_kind && !(N)->v.MatchAs.name) #define WILDCARD_STAR_CHECK(N) \ ((N)->kind == MatchStar_kind && !(N)->v.MatchStar.name) // Limit permitted subexpressions, even if the parser & AST validator let them through #define MATCH_VALUE_EXPR(N) \ ((N)->kind == Constant_kind || (N)->kind == Attribute_kind) // Allocate or resize pc->fail_pop to allow for n items to be popped on failure. static int ensure_fail_pop(struct compiler *c, pattern_context *pc, Py_ssize_t n) { Py_ssize_t size = n + 1; if (size <= pc->fail_pop_size) { return SUCCESS; } Py_ssize_t needed = sizeof(jump_target_label) * size; jump_target_label *resized = PyObject_Realloc(pc->fail_pop, needed); if (resized == NULL) { PyErr_NoMemory(); return ERROR; } pc->fail_pop = resized; while (pc->fail_pop_size < size) { NEW_JUMP_TARGET_LABEL(c, new_block); pc->fail_pop[pc->fail_pop_size++] = new_block; } return SUCCESS; } // Use op to jump to the correct fail_pop block. static int jump_to_fail_pop(struct compiler *c, location loc, pattern_context *pc, int op) { // Pop any items on the top of the stack, plus any objects we were going to // capture on success: Py_ssize_t pops = pc->on_top + PyList_GET_SIZE(pc->stores); RETURN_IF_ERROR(ensure_fail_pop(c, pc, pops)); ADDOP_JUMP(c, loc, op, pc->fail_pop[pops]); return SUCCESS; } // Build all of the fail_pop blocks and reset fail_pop. static int emit_and_reset_fail_pop(struct compiler *c, location loc, pattern_context *pc) { if (!pc->fail_pop_size) { assert(pc->fail_pop == NULL); return SUCCESS; } while (--pc->fail_pop_size) { USE_LABEL(c, pc->fail_pop[pc->fail_pop_size]); if (codegen_addop_noarg(INSTR_SEQUENCE(c), POP_TOP, loc) < 0) { pc->fail_pop_size = 0; PyObject_Free(pc->fail_pop); pc->fail_pop = NULL; return ERROR; } } USE_LABEL(c, pc->fail_pop[0]); PyObject_Free(pc->fail_pop); pc->fail_pop = NULL; return SUCCESS; } static int compiler_error_duplicate_store(struct compiler *c, location loc, identifier n) { return compiler_error(c, loc, "multiple assignments to name %R in pattern", n); } // Duplicate the effect of 3.10's ROT_* instructions using SWAPs. static int pattern_helper_rotate(struct compiler *c, location loc, Py_ssize_t count) { while (1 < count) { ADDOP_I(c, loc, SWAP, count--); } return SUCCESS; } static int pattern_helper_store_name(struct compiler *c, location loc, identifier n, pattern_context *pc) { if (n == NULL) { ADDOP(c, loc, POP_TOP); return SUCCESS; } if (forbidden_name(c, loc, n, Store)) { return ERROR; } // Can't assign to the same name twice: int duplicate = PySequence_Contains(pc->stores, n); RETURN_IF_ERROR(duplicate); if (duplicate) { return compiler_error_duplicate_store(c, loc, n); } // Rotate this object underneath any items we need to preserve: Py_ssize_t rotations = pc->on_top + PyList_GET_SIZE(pc->stores) + 1; RETURN_IF_ERROR(pattern_helper_rotate(c, loc, rotations)); RETURN_IF_ERROR(PyList_Append(pc->stores, n)); return SUCCESS; } static int pattern_unpack_helper(struct compiler *c, location loc, asdl_pattern_seq *elts) { Py_ssize_t n = asdl_seq_LEN(elts); int seen_star = 0; for (Py_ssize_t i = 0; i < n; i++) { pattern_ty elt = asdl_seq_GET(elts, i); if (elt->kind == MatchStar_kind && !seen_star) { if ((i >= (1 << 8)) || (n-i-1 >= (INT_MAX >> 8))) { return compiler_error(c, loc, "too many expressions in " "star-unpacking sequence pattern"); } ADDOP_I(c, loc, UNPACK_EX, (i + ((n-i-1) << 8))); seen_star = 1; } else if (elt->kind == MatchStar_kind) { return compiler_error(c, loc, "multiple starred expressions in sequence pattern"); } } if (!seen_star) { ADDOP_I(c, loc, UNPACK_SEQUENCE, n); } return SUCCESS; } static int pattern_helper_sequence_unpack(struct compiler *c, location loc, asdl_pattern_seq *patterns, Py_ssize_t star, pattern_context *pc) { RETURN_IF_ERROR(pattern_unpack_helper(c, loc, patterns)); Py_ssize_t size = asdl_seq_LEN(patterns); // We've now got a bunch of new subjects on the stack. They need to remain // there after each subpattern match: pc->on_top += size; for (Py_ssize_t i = 0; i < size; i++) { // One less item to keep track of each time we loop through: pc->on_top--; pattern_ty pattern = asdl_seq_GET(patterns, i); RETURN_IF_ERROR(compiler_pattern_subpattern(c, pattern, pc)); } return SUCCESS; } // Like pattern_helper_sequence_unpack, but uses BINARY_SUBSCR instead of // UNPACK_SEQUENCE / UNPACK_EX. This is more efficient for patterns with a // starred wildcard like [first, *_] / [first, *_, last] / [*_, last] / etc. static int pattern_helper_sequence_subscr(struct compiler *c, location loc, asdl_pattern_seq *patterns, Py_ssize_t star, pattern_context *pc) { // We need to keep the subject around for extracting elements: pc->on_top++; Py_ssize_t size = asdl_seq_LEN(patterns); for (Py_ssize_t i = 0; i < size; i++) { pattern_ty pattern = asdl_seq_GET(patterns, i); if (WILDCARD_CHECK(pattern)) { continue; } if (i == star) { assert(WILDCARD_STAR_CHECK(pattern)); continue; } ADDOP_I(c, loc, COPY, 1); if (i < star) { ADDOP_LOAD_CONST_NEW(c, loc, PyLong_FromSsize_t(i)); } else { // The subject may not support negative indexing! Compute a // nonnegative index: ADDOP(c, loc, GET_LEN); ADDOP_LOAD_CONST_NEW(c, loc, PyLong_FromSsize_t(size - i)); ADDOP_BINARY(c, loc, Sub); } ADDOP(c, loc, BINARY_SUBSCR); RETURN_IF_ERROR(compiler_pattern_subpattern(c, pattern, pc)); } // Pop the subject, we're done with it: pc->on_top--; ADDOP(c, loc, POP_TOP); return SUCCESS; } // Like compiler_pattern, but turn off checks for irrefutability. static int compiler_pattern_subpattern(struct compiler *c, pattern_ty p, pattern_context *pc) { int allow_irrefutable = pc->allow_irrefutable; pc->allow_irrefutable = 1; RETURN_IF_ERROR(compiler_pattern(c, p, pc)); pc->allow_irrefutable = allow_irrefutable; return SUCCESS; } static int compiler_pattern_as(struct compiler *c, pattern_ty p, pattern_context *pc) { assert(p->kind == MatchAs_kind); if (p->v.MatchAs.pattern == NULL) { // An irrefutable match: if (!pc->allow_irrefutable) { if (p->v.MatchAs.name) { const char *e = "name capture %R makes remaining patterns unreachable"; return compiler_error(c, LOC(p), e, p->v.MatchAs.name); } const char *e = "wildcard makes remaining patterns unreachable"; return compiler_error(c, LOC(p), e); } return pattern_helper_store_name(c, LOC(p), p->v.MatchAs.name, pc); } // Need to make a copy for (possibly) storing later: pc->on_top++; ADDOP_I(c, LOC(p), COPY, 1); RETURN_IF_ERROR(compiler_pattern(c, p->v.MatchAs.pattern, pc)); // Success! Store it: pc->on_top--; RETURN_IF_ERROR(pattern_helper_store_name(c, LOC(p), p->v.MatchAs.name, pc)); return SUCCESS; } static int compiler_pattern_star(struct compiler *c, pattern_ty p, pattern_context *pc) { assert(p->kind == MatchStar_kind); RETURN_IF_ERROR( pattern_helper_store_name(c, LOC(p), p->v.MatchStar.name, pc)); return SUCCESS; } static int validate_kwd_attrs(struct compiler *c, asdl_identifier_seq *attrs, asdl_pattern_seq* patterns) { // Any errors will point to the pattern rather than the arg name as the // parser is only supplying identifiers rather than Name or keyword nodes Py_ssize_t nattrs = asdl_seq_LEN(attrs); for (Py_ssize_t i = 0; i < nattrs; i++) { identifier attr = ((identifier)asdl_seq_GET(attrs, i)); location loc = LOC((pattern_ty) asdl_seq_GET(patterns, i)); if (forbidden_name(c, loc, attr, Store)) { return ERROR; } for (Py_ssize_t j = i + 1; j < nattrs; j++) { identifier other = ((identifier)asdl_seq_GET(attrs, j)); if (!PyUnicode_Compare(attr, other)) { location loc = LOC((pattern_ty) asdl_seq_GET(patterns, j)); compiler_error(c, loc, "attribute name repeated in class pattern: %U", attr); return ERROR; } } } return SUCCESS; } static int compiler_pattern_class(struct compiler *c, pattern_ty p, pattern_context *pc) { assert(p->kind == MatchClass_kind); asdl_pattern_seq *patterns = p->v.MatchClass.patterns; asdl_identifier_seq *kwd_attrs = p->v.MatchClass.kwd_attrs; asdl_pattern_seq *kwd_patterns = p->v.MatchClass.kwd_patterns; Py_ssize_t nargs = asdl_seq_LEN(patterns); Py_ssize_t nattrs = asdl_seq_LEN(kwd_attrs); Py_ssize_t nkwd_patterns = asdl_seq_LEN(kwd_patterns); if (nattrs != nkwd_patterns) { // AST validator shouldn't let this happen, but if it does, // just fail, don't crash out of the interpreter const char * e = "kwd_attrs (%d) / kwd_patterns (%d) length mismatch in class pattern"; return compiler_error(c, LOC(p), e, nattrs, nkwd_patterns); } if (INT_MAX < nargs || INT_MAX < nargs + nattrs - 1) { const char *e = "too many sub-patterns in class pattern %R"; return compiler_error(c, LOC(p), e, p->v.MatchClass.cls); } if (nattrs) { RETURN_IF_ERROR(validate_kwd_attrs(c, kwd_attrs, kwd_patterns)); } VISIT(c, expr, p->v.MatchClass.cls); PyObject *attr_names = PyTuple_New(nattrs); if (attr_names == NULL) { return ERROR; } Py_ssize_t i; for (i = 0; i < nattrs; i++) { PyObject *name = asdl_seq_GET(kwd_attrs, i); PyTuple_SET_ITEM(attr_names, i, Py_NewRef(name)); } ADDOP_LOAD_CONST_NEW(c, LOC(p), attr_names); ADDOP_I(c, LOC(p), MATCH_CLASS, nargs); ADDOP_I(c, LOC(p), COPY, 1); ADDOP_LOAD_CONST(c, LOC(p), Py_None); ADDOP_I(c, LOC(p), IS_OP, 1); // TOS is now a tuple of (nargs + nattrs) attributes (or None): pc->on_top++; RETURN_IF_ERROR(jump_to_fail_pop(c, LOC(p), pc, POP_JUMP_IF_FALSE)); ADDOP_I(c, LOC(p), UNPACK_SEQUENCE, nargs + nattrs); pc->on_top += nargs + nattrs - 1; for (i = 0; i < nargs + nattrs; i++) { pc->on_top--; pattern_ty pattern; if (i < nargs) { // Positional: pattern = asdl_seq_GET(patterns, i); } else { // Keyword: pattern = asdl_seq_GET(kwd_patterns, i - nargs); } if (WILDCARD_CHECK(pattern)) { ADDOP(c, LOC(p), POP_TOP); continue; } RETURN_IF_ERROR(compiler_pattern_subpattern(c, pattern, pc)); } // Success! Pop the tuple of attributes: return SUCCESS; } static int compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) { assert(p->kind == MatchMapping_kind); asdl_expr_seq *keys = p->v.MatchMapping.keys; asdl_pattern_seq *patterns = p->v.MatchMapping.patterns; Py_ssize_t size = asdl_seq_LEN(keys); Py_ssize_t npatterns = asdl_seq_LEN(patterns); if (size != npatterns) { // AST validator shouldn't let this happen, but if it does, // just fail, don't crash out of the interpreter const char * e = "keys (%d) / patterns (%d) length mismatch in mapping pattern"; return compiler_error(c, LOC(p), e, size, npatterns); } // We have a double-star target if "rest" is set PyObject *star_target = p->v.MatchMapping.rest; // We need to keep the subject on top during the mapping and length checks: pc->on_top++; ADDOP(c, LOC(p), MATCH_MAPPING); RETURN_IF_ERROR(jump_to_fail_pop(c, LOC(p), pc, POP_JUMP_IF_FALSE)); if (!size && !star_target) { // If the pattern is just "{}", we're done! Pop the subject: pc->on_top--; ADDOP(c, LOC(p), POP_TOP); return SUCCESS; } if (size) { // If the pattern has any keys in it, perform a length check: ADDOP(c, LOC(p), GET_LEN); ADDOP_LOAD_CONST_NEW(c, LOC(p), PyLong_FromSsize_t(size)); ADDOP_COMPARE(c, LOC(p), GtE); RETURN_IF_ERROR(jump_to_fail_pop(c, LOC(p), pc, POP_JUMP_IF_FALSE)); } if (INT_MAX < size - 1) { return compiler_error(c, LOC(p), "too many sub-patterns in mapping pattern"); } // Collect all of the keys into a tuple for MATCH_KEYS and // **rest. They can either be dotted names or literals: // Maintaining a set of Constant_kind kind keys allows us to raise a // SyntaxError in the case of duplicates. PyObject *seen = PySet_New(NULL); if (seen == NULL) { return ERROR; } // NOTE: goto error on failure in the loop below to avoid leaking `seen` for (Py_ssize_t i = 0; i < size; i++) { expr_ty key = asdl_seq_GET(keys, i); if (key == NULL) { const char *e = "can't use NULL keys in MatchMapping " "(set 'rest' parameter instead)"; location loc = LOC((pattern_ty) asdl_seq_GET(patterns, i)); compiler_error(c, loc, e); goto error; } if (key->kind == Constant_kind) { int in_seen = PySet_Contains(seen, key->v.Constant.value); if (in_seen < 0) { goto error; } if (in_seen) { const char *e = "mapping pattern checks duplicate key (%R)"; compiler_error(c, LOC(p), e, key->v.Constant.value); goto error; } if (PySet_Add(seen, key->v.Constant.value)) { goto error; } } else if (key->kind != Attribute_kind) { const char *e = "mapping pattern keys may only match literals and attribute lookups"; compiler_error(c, LOC(p), e); goto error; } if (compiler_visit_expr(c, key) < 0) { goto error; } } // all keys have been checked; there are no duplicates Py_DECREF(seen); ADDOP_I(c, LOC(p), BUILD_TUPLE, size); ADDOP(c, LOC(p), MATCH_KEYS); // There's now a tuple of keys and a tuple of values on top of the subject: pc->on_top += 2; ADDOP_I(c, LOC(p), COPY, 1); ADDOP_LOAD_CONST(c, LOC(p), Py_None); ADDOP_I(c, LOC(p), IS_OP, 1); RETURN_IF_ERROR(jump_to_fail_pop(c, LOC(p), pc, POP_JUMP_IF_FALSE)); // So far so good. Use that tuple of values on the stack to match // sub-patterns against: ADDOP_I(c, LOC(p), UNPACK_SEQUENCE, size); pc->on_top += size - 1; for (Py_ssize_t i = 0; i < size; i++) { pc->on_top--; pattern_ty pattern = asdl_seq_GET(patterns, i); RETURN_IF_ERROR(compiler_pattern_subpattern(c, pattern, pc)); } // If we get this far, it's a match! Whatever happens next should consume // the tuple of keys and the subject: pc->on_top -= 2; if (star_target) { // If we have a starred name, bind a dict of remaining items to it (this may // seem a bit inefficient, but keys is rarely big enough to actually impact // runtime): // rest = dict(TOS1) // for key in TOS: // del rest[key] ADDOP_I(c, LOC(p), BUILD_MAP, 0); // [subject, keys, empty] ADDOP_I(c, LOC(p), SWAP, 3); // [empty, keys, subject] ADDOP_I(c, LOC(p), DICT_UPDATE, 2); // [copy, keys] ADDOP_I(c, LOC(p), UNPACK_SEQUENCE, size); // [copy, keys...] while (size) { ADDOP_I(c, LOC(p), COPY, 1 + size--); // [copy, keys..., copy] ADDOP_I(c, LOC(p), SWAP, 2); // [copy, keys..., copy, key] ADDOP(c, LOC(p), DELETE_SUBSCR); // [copy, keys...] } RETURN_IF_ERROR(pattern_helper_store_name(c, LOC(p), star_target, pc)); } else { ADDOP(c, LOC(p), POP_TOP); // Tuple of keys. ADDOP(c, LOC(p), POP_TOP); // Subject. } return SUCCESS; error: Py_DECREF(seen); return ERROR; } static int compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) { assert(p->kind == MatchOr_kind); NEW_JUMP_TARGET_LABEL(c, end); Py_ssize_t size = asdl_seq_LEN(p->v.MatchOr.patterns); assert(size > 1); // We're going to be messing with pc. Keep the original info handy: pattern_context old_pc = *pc; Py_INCREF(pc->stores); // control is the list of names bound by the first alternative. It is used // for checking different name bindings in alternatives, and for correcting // the order in which extracted elements are placed on the stack. PyObject *control = NULL; // NOTE: We can't use returning macros anymore! goto error on error. for (Py_ssize_t i = 0; i < size; i++) { pattern_ty alt = asdl_seq_GET(p->v.MatchOr.patterns, i); PyObject *pc_stores = PyList_New(0); if (pc_stores == NULL) { goto error; } Py_SETREF(pc->stores, pc_stores); // An irrefutable sub-pattern must be last, if it is allowed at all: pc->allow_irrefutable = (i == size - 1) && old_pc.allow_irrefutable; pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->on_top = 0; if (codegen_addop_i(INSTR_SEQUENCE(c), COPY, 1, LOC(alt)) < 0 || compiler_pattern(c, alt, pc) < 0) { goto error; } // Success! Py_ssize_t nstores = PyList_GET_SIZE(pc->stores); if (!i) { // This is the first alternative, so save its stores as a "control" // for the others (they can't bind a different set of names, and // might need to be reordered): assert(control == NULL); control = Py_NewRef(pc->stores); } else if (nstores != PyList_GET_SIZE(control)) { goto diff; } else if (nstores) { // There were captures. Check to see if we differ from control: Py_ssize_t icontrol = nstores; while (icontrol--) { PyObject *name = PyList_GET_ITEM(control, icontrol); Py_ssize_t istores = PySequence_Index(pc->stores, name); if (istores < 0) { PyErr_Clear(); goto diff; } if (icontrol != istores) { // Reorder the names on the stack to match the order of the // names in control. There's probably a better way of doing // this; the current solution is potentially very // inefficient when each alternative subpattern binds lots // of names in different orders. It's fine for reasonable // cases, though, and the peephole optimizer will ensure // that the final code is as efficient as possible. assert(istores < icontrol); Py_ssize_t rotations = istores + 1; // Perform the same rotation on pc->stores: PyObject *rotated = PyList_GetSlice(pc->stores, 0, rotations); if (rotated == NULL || PyList_SetSlice(pc->stores, 0, rotations, NULL) || PyList_SetSlice(pc->stores, icontrol - istores, icontrol - istores, rotated)) { Py_XDECREF(rotated); goto error; } Py_DECREF(rotated); // That just did: // rotated = pc_stores[:rotations] // del pc_stores[:rotations] // pc_stores[icontrol-istores:icontrol-istores] = rotated // Do the same thing to the stack, using several // rotations: while (rotations--) { if (pattern_helper_rotate(c, LOC(alt), icontrol + 1) < 0) { goto error; } } } } } assert(control); if (codegen_addop_j(INSTR_SEQUENCE(c), LOC(alt), JUMP, end) < 0 || emit_and_reset_fail_pop(c, LOC(alt), pc) < 0) { goto error; } } Py_DECREF(pc->stores); *pc = old_pc; Py_INCREF(pc->stores); // Need to NULL this for the PyObject_Free call in the error block. old_pc.fail_pop = NULL; // No match. Pop the remaining copy of the subject and fail: if (codegen_addop_noarg(INSTR_SEQUENCE(c), POP_TOP, LOC(p)) < 0 || jump_to_fail_pop(c, LOC(p), pc, JUMP) < 0) { goto error; } USE_LABEL(c, end); Py_ssize_t nstores = PyList_GET_SIZE(control); // There's a bunch of stuff on the stack between where the new stores // are and where they need to be: // - The other stores. // - A copy of the subject. // - Anything else that may be on top of the stack. // - Any previous stores we've already stashed away on the stack. Py_ssize_t nrots = nstores + 1 + pc->on_top + PyList_GET_SIZE(pc->stores); for (Py_ssize_t i = 0; i < nstores; i++) { // Rotate this capture to its proper place on the stack: if (pattern_helper_rotate(c, LOC(p), nrots) < 0) { goto error; } // Update the list of previous stores with this new name, checking for // duplicates: PyObject *name = PyList_GET_ITEM(control, i); int dupe = PySequence_Contains(pc->stores, name); if (dupe < 0) { goto error; } if (dupe) { compiler_error_duplicate_store(c, LOC(p), name); goto error; } if (PyList_Append(pc->stores, name)) { goto error; } } Py_DECREF(old_pc.stores); Py_DECREF(control); // NOTE: Returning macros are safe again. // Pop the copy of the subject: ADDOP(c, LOC(p), POP_TOP); return SUCCESS; diff: compiler_error(c, LOC(p), "alternative patterns bind different names"); error: PyObject_Free(old_pc.fail_pop); Py_DECREF(old_pc.stores); Py_XDECREF(control); return ERROR; } static int compiler_pattern_sequence(struct compiler *c, pattern_ty p, pattern_context *pc) { assert(p->kind == MatchSequence_kind); asdl_pattern_seq *patterns = p->v.MatchSequence.patterns; Py_ssize_t size = asdl_seq_LEN(patterns); Py_ssize_t star = -1; int only_wildcard = 1; int star_wildcard = 0; // Find a starred name, if it exists. There may be at most one: for (Py_ssize_t i = 0; i < size; i++) { pattern_ty pattern = asdl_seq_GET(patterns, i); if (pattern->kind == MatchStar_kind) { if (star >= 0) { const char *e = "multiple starred names in sequence pattern"; return compiler_error(c, LOC(p), e); } star_wildcard = WILDCARD_STAR_CHECK(pattern); only_wildcard &= star_wildcard; star = i; continue; } only_wildcard &= WILDCARD_CHECK(pattern); } // We need to keep the subject on top during the sequence and length checks: pc->on_top++; ADDOP(c, LOC(p), MATCH_SEQUENCE); RETURN_IF_ERROR(jump_to_fail_pop(c, LOC(p), pc, POP_JUMP_IF_FALSE)); if (star < 0) { // No star: len(subject) == size ADDOP(c, LOC(p), GET_LEN); ADDOP_LOAD_CONST_NEW(c, LOC(p), PyLong_FromSsize_t(size)); ADDOP_COMPARE(c, LOC(p), Eq); RETURN_IF_ERROR(jump_to_fail_pop(c, LOC(p), pc, POP_JUMP_IF_FALSE)); } else if (size > 1) { // Star: len(subject) >= size - 1 ADDOP(c, LOC(p), GET_LEN); ADDOP_LOAD_CONST_NEW(c, LOC(p), PyLong_FromSsize_t(size - 1)); ADDOP_COMPARE(c, LOC(p), GtE); RETURN_IF_ERROR(jump_to_fail_pop(c, LOC(p), pc, POP_JUMP_IF_FALSE)); } // Whatever comes next should consume the subject: pc->on_top--; if (only_wildcard) { // Patterns like: [] / [_] / [_, _] / [*_] / [_, *_] / [_, _, *_] / etc. ADDOP(c, LOC(p), POP_TOP); } else if (star_wildcard) { RETURN_IF_ERROR(pattern_helper_sequence_subscr(c, LOC(p), patterns, star, pc)); } else { RETURN_IF_ERROR(pattern_helper_sequence_unpack(c, LOC(p), patterns, star, pc)); } return SUCCESS; } static int compiler_pattern_value(struct compiler *c, pattern_ty p, pattern_context *pc) { assert(p->kind == MatchValue_kind); expr_ty value = p->v.MatchValue.value; if (!MATCH_VALUE_EXPR(value)) { const char *e = "patterns may only match literals and attribute lookups"; return compiler_error(c, LOC(p), e); } VISIT(c, expr, value); ADDOP_COMPARE(c, LOC(p), Eq); RETURN_IF_ERROR(jump_to_fail_pop(c, LOC(p), pc, POP_JUMP_IF_FALSE)); return SUCCESS; } static int compiler_pattern_singleton(struct compiler *c, pattern_ty p, pattern_context *pc) { assert(p->kind == MatchSingleton_kind); ADDOP_LOAD_CONST(c, LOC(p), p->v.MatchSingleton.value); ADDOP_COMPARE(c, LOC(p), Is); RETURN_IF_ERROR(jump_to_fail_pop(c, LOC(p), pc, POP_JUMP_IF_FALSE)); return SUCCESS; } static int compiler_pattern(struct compiler *c, pattern_ty p, pattern_context *pc) { switch (p->kind) { case MatchValue_kind: return compiler_pattern_value(c, p, pc); case MatchSingleton_kind: return compiler_pattern_singleton(c, p, pc); case MatchSequence_kind: return compiler_pattern_sequence(c, p, pc); case MatchMapping_kind: return compiler_pattern_mapping(c, p, pc); case MatchClass_kind: return compiler_pattern_class(c, p, pc); case MatchStar_kind: return compiler_pattern_star(c, p, pc); case MatchAs_kind: return compiler_pattern_as(c, p, pc); case MatchOr_kind: return compiler_pattern_or(c, p, pc); } // AST validator shouldn't let this happen, but if it does, // just fail, don't crash out of the interpreter const char *e = "invalid match pattern node in AST (kind=%d)"; return compiler_error(c, LOC(p), e, p->kind); } static int compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) { VISIT(c, expr, s->v.Match.subject); NEW_JUMP_TARGET_LABEL(c, end); Py_ssize_t cases = asdl_seq_LEN(s->v.Match.cases); assert(cases > 0); match_case_ty m = asdl_seq_GET(s->v.Match.cases, cases - 1); int has_default = WILDCARD_CHECK(m->pattern) && 1 < cases; for (Py_ssize_t i = 0; i < cases - has_default; i++) { m = asdl_seq_GET(s->v.Match.cases, i); // Only copy the subject if we're *not* on the last case: if (i != cases - has_default - 1) { ADDOP_I(c, LOC(m->pattern), COPY, 1); } pc->stores = PyList_New(0); if (pc->stores == NULL) { return ERROR; } // Irrefutable cases must be either guarded, last, or both: pc->allow_irrefutable = m->guard != NULL || i == cases - 1; pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->on_top = 0; // NOTE: Can't use returning macros here (they'll leak pc->stores)! if (compiler_pattern(c, m->pattern, pc) < 0) { Py_DECREF(pc->stores); return ERROR; } assert(!pc->on_top); // It's a match! Store all of the captured names (they're on the stack). Py_ssize_t nstores = PyList_GET_SIZE(pc->stores); for (Py_ssize_t n = 0; n < nstores; n++) { PyObject *name = PyList_GET_ITEM(pc->stores, n); if (compiler_nameop(c, LOC(m->pattern), name, Store) < 0) { Py_DECREF(pc->stores); return ERROR; } } Py_DECREF(pc->stores); // NOTE: Returning macros are safe again. if (m->guard) { RETURN_IF_ERROR(ensure_fail_pop(c, pc, 0)); RETURN_IF_ERROR(compiler_jump_if(c, LOC(m->pattern), m->guard, pc->fail_pop[0], 0)); } // Success! Pop the subject off, we're done with it: if (i != cases - has_default - 1) { ADDOP(c, LOC(m->pattern), POP_TOP); } VISIT_SEQ(c, stmt, m->body); ADDOP_JUMP(c, NO_LOCATION, JUMP, end); // If the pattern fails to match, we want the line number of the // cleanup to be associated with the failed pattern, not the last line // of the body RETURN_IF_ERROR(emit_and_reset_fail_pop(c, LOC(m->pattern), pc)); } if (has_default) { // A trailing "case _" is common, and lets us save a bit of redundant // pushing and popping in the loop above: m = asdl_seq_GET(s->v.Match.cases, cases - 1); if (cases == 1) { // No matches. Done with the subject: ADDOP(c, LOC(m->pattern), POP_TOP); } else { // Show line coverage for default case (it doesn't create bytecode) ADDOP(c, LOC(m->pattern), NOP); } if (m->guard) { RETURN_IF_ERROR(compiler_jump_if(c, LOC(m->pattern), m->guard, end, 0)); } VISIT_SEQ(c, stmt, m->body); } USE_LABEL(c, end); return SUCCESS; } static int compiler_match(struct compiler *c, stmt_ty s) { pattern_context pc; pc.fail_pop = NULL; int result = compiler_match_inner(c, s, &pc); PyObject_Free(pc.fail_pop); return result; } #undef WILDCARD_CHECK #undef WILDCARD_STAR_CHECK static PyObject * consts_dict_keys_inorder(PyObject *dict) { PyObject *consts, *k, *v; Py_ssize_t i, pos = 0, size = PyDict_GET_SIZE(dict); consts = PyList_New(size); /* PyCode_Optimize() requires a list */ if (consts == NULL) return NULL; while (PyDict_Next(dict, &pos, &k, &v)) { i = PyLong_AS_LONG(v); /* The keys of the dictionary can be tuples wrapping a constant. * (see dict_add_o and _PyCode_ConstantKey). In that case * the object we want is always second. */ if (PyTuple_CheckExact(k)) { k = PyTuple_GET_ITEM(k, 1); } assert(i < size); assert(i >= 0); PyList_SET_ITEM(consts, i, Py_NewRef(k)); } return consts; } static int compute_code_flags(struct compiler *c) { PySTEntryObject *ste = c->u->u_ste; int flags = 0; if (_PyST_IsFunctionLike(c->u->u_ste)) { flags |= CO_NEWLOCALS | CO_OPTIMIZED; if (ste->ste_nested) flags |= CO_NESTED; if (ste->ste_generator && !ste->ste_coroutine) flags |= CO_GENERATOR; if (!ste->ste_generator && ste->ste_coroutine) flags |= CO_COROUTINE; if (ste->ste_generator && ste->ste_coroutine) flags |= CO_ASYNC_GENERATOR; if (ste->ste_varargs) flags |= CO_VARARGS; if (ste->ste_varkeywords) flags |= CO_VARKEYWORDS; } /* (Only) inherit compilerflags in PyCF_MASK */ flags |= (c->c_flags.cf_flags & PyCF_MASK); if ((IS_TOP_LEVEL_AWAIT(c)) && ste->ste_coroutine && !ste->ste_generator) { flags |= CO_COROUTINE; } return flags; } // Merge *obj* with constant cache. // Unlike merge_consts_recursive(), this function doesn't work recursively. int _PyCompile_ConstCacheMergeOne(PyObject *const_cache, PyObject **obj) { assert(PyDict_CheckExact(const_cache)); PyObject *key = _PyCode_ConstantKey(*obj); if (key == NULL) { return ERROR; } // t is borrowed reference PyObject *t = PyDict_SetDefault(const_cache, key, key); Py_DECREF(key); if (t == NULL) { return ERROR; } if (t == key) { // obj is new constant. return SUCCESS; } if (PyTuple_CheckExact(t)) { // t is still borrowed reference t = PyTuple_GET_ITEM(t, 1); } Py_SETREF(*obj, Py_NewRef(t)); return SUCCESS; } static int * build_cellfixedoffsets(_PyCompile_CodeUnitMetadata *umd) { int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars); int noffsets = ncellvars + nfreevars; int *fixed = PyMem_New(int, noffsets); if (fixed == NULL) { PyErr_NoMemory(); return NULL; } for (int i = 0; i < noffsets; i++) { fixed[i] = nlocals + i; } PyObject *varname, *cellindex; Py_ssize_t pos = 0; while (PyDict_Next(umd->u_cellvars, &pos, &varname, &cellindex)) { PyObject *varindex = PyDict_GetItem(umd->u_varnames, varname); if (varindex != NULL) { assert(PyLong_AS_LONG(cellindex) < INT_MAX); assert(PyLong_AS_LONG(varindex) < INT_MAX); int oldindex = (int)PyLong_AS_LONG(cellindex); int argoffset = (int)PyLong_AS_LONG(varindex); fixed[oldindex] = argoffset; } } return fixed; } static int insert_prefix_instructions(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock, int *fixed, int nfreevars, int code_flags) { assert(umd->u_firstlineno > 0); /* Add the generator prefix instructions. */ if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { cfg_instr make_gen = { .i_opcode = RETURN_GENERATOR, .i_oparg = 0, .i_loc = LOCATION(umd->u_firstlineno, umd->u_firstlineno, -1, -1), .i_target = NULL, }; RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, &make_gen)); cfg_instr pop_top = { .i_opcode = POP_TOP, .i_oparg = 0, .i_loc = NO_LOCATION, .i_target = NULL, }; RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 1, &pop_top)); } /* Set up cells for any variable that escapes, to be put in a closure. */ const int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); if (ncellvars) { // umd->u_cellvars has the cells out of order so we sort them // before adding the MAKE_CELL instructions. Note that we // adjust for arg cells, which come first. const int nvars = ncellvars + (int)PyDict_GET_SIZE(umd->u_varnames); int *sorted = PyMem_RawCalloc(nvars, sizeof(int)); if (sorted == NULL) { PyErr_NoMemory(); return ERROR; } for (int i = 0; i < ncellvars; i++) { sorted[fixed[i]] = i + 1; } for (int i = 0, ncellsused = 0; ncellsused < ncellvars; i++) { int oldindex = sorted[i] - 1; if (oldindex == -1) { continue; } cfg_instr make_cell = { .i_opcode = MAKE_CELL, // This will get fixed in offset_derefs(). .i_oparg = oldindex, .i_loc = NO_LOCATION, .i_target = NULL, }; if (_PyBasicblock_InsertInstruction(entryblock, ncellsused, &make_cell) < 0) { PyMem_RawFree(sorted); return ERROR; } ncellsused += 1; } PyMem_RawFree(sorted); } if (nfreevars) { cfg_instr copy_frees = { .i_opcode = COPY_FREE_VARS, .i_oparg = nfreevars, .i_loc = NO_LOCATION, .i_target = NULL, }; RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, ©_frees)); } return SUCCESS; } static int fix_cell_offsets(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock, int *fixedmap) { int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars); int noffsets = ncellvars + nfreevars; // First deal with duplicates (arg cells). int numdropped = 0; for (int i = 0; i < noffsets ; i++) { if (fixedmap[i] == i + nlocals) { fixedmap[i] -= numdropped; } else { // It was a duplicate (cell/arg). numdropped += 1; } } // Then update offsets, either relative to locals or by cell2arg. for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { cfg_instr *inst = &b->b_instr[i]; // This is called before extended args are generated. assert(inst->i_opcode != EXTENDED_ARG); int oldoffset = inst->i_oparg; switch(inst->i_opcode) { case MAKE_CELL: case LOAD_CLOSURE: case LOAD_DEREF: case STORE_DEREF: case DELETE_DEREF: case LOAD_FROM_DICT_OR_DEREF: assert(oldoffset >= 0); assert(oldoffset < noffsets); assert(fixedmap[oldoffset] >= 0); inst->i_oparg = fixedmap[oldoffset]; } } } return numdropped; } static int prepare_localsplus(_PyCompile_CodeUnitMetadata *umd, cfg_builder *g, int code_flags) { assert(PyDict_GET_SIZE(umd->u_varnames) < INT_MAX); assert(PyDict_GET_SIZE(umd->u_cellvars) < INT_MAX); assert(PyDict_GET_SIZE(umd->u_freevars) < INT_MAX); int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars); assert(INT_MAX - nlocals - ncellvars > 0); assert(INT_MAX - nlocals - ncellvars - nfreevars > 0); int nlocalsplus = nlocals + ncellvars + nfreevars; int* cellfixedoffsets = build_cellfixedoffsets(umd); if (cellfixedoffsets == NULL) { return ERROR; } // This must be called before fix_cell_offsets(). if (insert_prefix_instructions(umd, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { PyMem_Free(cellfixedoffsets); return ERROR; } int numdropped = fix_cell_offsets(umd, g->g_entryblock, cellfixedoffsets); PyMem_Free(cellfixedoffsets); // At this point we're done with it. cellfixedoffsets = NULL; if (numdropped < 0) { return ERROR; } nlocalsplus -= numdropped; return nlocalsplus; } static int add_return_at_end(struct compiler *c, int addNone) { /* Make sure every instruction stream that falls off the end returns None. * This also ensures that no jump target offsets are out of bounds. */ if (addNone) { ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); } ADDOP(c, NO_LOCATION, RETURN_VALUE); return SUCCESS; } static int cfg_to_instr_sequence(cfg_builder *g, instr_sequence *seq); static PyCodeObject * optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, int code_flags, PyObject *filename) { instr_sequence optimized_instrs; memset(&optimized_instrs, 0, sizeof(instr_sequence)); PyCodeObject *co = NULL; PyObject *consts = consts_dict_keys_inorder(u->u_metadata.u_consts); if (consts == NULL) { goto error; } cfg_builder g; if (instr_sequence_to_cfg(&u->u_instr_sequence, &g) < 0) { goto error; } int nparams = (int)PyList_GET_SIZE(u->u_ste->ste_varnames); int nlocals = (int)PyDict_GET_SIZE(u->u_metadata.u_varnames); assert(u->u_metadata.u_firstlineno); if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, code_flags, nlocals, nparams, u->u_metadata.u_firstlineno) < 0) { goto error; } /** Assembly **/ int nlocalsplus = prepare_localsplus(&u->u_metadata, &g, code_flags); if (nlocalsplus < 0) { goto error; } int maxdepth = _PyCfg_Stackdepth(g.g_entryblock, code_flags); if (maxdepth < 0) { goto error; } _PyCfg_ConvertPseudoOps(g.g_entryblock); /* Order of basic blocks must have been determined by now */ if (_PyCfg_ResolveJumps(&g) < 0) { goto error; } /* Can't modify the bytecode after computing jump offsets. */ if (cfg_to_instr_sequence(&g, &optimized_instrs) < 0) { goto error; } co = _PyAssemble_MakeCodeObject(&u->u_metadata, const_cache, consts, maxdepth, &optimized_instrs, nlocalsplus, code_flags, filename); error: Py_XDECREF(consts); instr_sequence_fini(&optimized_instrs); _PyCfgBuilder_Fini(&g); return co; } static PyCodeObject * optimize_and_assemble(struct compiler *c, int addNone) { struct compiler_unit *u = c->u; PyObject *const_cache = c->c_const_cache; PyObject *filename = c->c_filename; int code_flags = compute_code_flags(c); if (code_flags < 0) { return NULL; } if (add_return_at_end(c, addNone) < 0) { return NULL; } return optimize_and_assemble_code_unit(u, const_cache, code_flags, filename); } static int cfg_to_instr_sequence(cfg_builder *g, instr_sequence *seq) { int lbl = 0; for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { b->b_label = (jump_target_label){lbl}; lbl += b->b_iused; } for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { RETURN_IF_ERROR(instr_sequence_use_label(seq, b->b_label.id)); for (int i = 0; i < b->b_iused; i++) { cfg_instr *instr = &b->b_instr[i]; RETURN_IF_ERROR( instr_sequence_addop(seq, instr->i_opcode, instr->i_oparg, instr->i_loc)); _PyCompile_ExceptHandlerInfo *hi = &seq->s_instrs[seq->s_used-1].i_except_handler_info; if (instr->i_except != NULL) { hi->h_offset = instr->i_except->b_offset; hi->h_startdepth = instr->i_except->b_startdepth; hi->h_preserve_lasti = instr->i_except->b_preserve_lasti; } else { hi->h_offset = -1; } } } return SUCCESS; } /* Access to compiler optimizations for unit tests. * * _PyCompile_CodeGen takes and AST, applies code-gen and * returns the unoptimized CFG as an instruction list. * * _PyCompile_OptimizeCfg takes an instruction list, constructs * a CFG, optimizes it and converts back to an instruction list. * * An instruction list is a PyList where each item is either * a tuple describing a single instruction: * (opcode, oparg, lineno, end_lineno, col, end_col), or * a jump target label marking the beginning of a basic block. */ static int instructions_to_instr_sequence(PyObject *instructions, instr_sequence *seq) { assert(PyList_Check(instructions)); Py_ssize_t num_insts = PyList_GET_SIZE(instructions); bool *is_target = PyMem_Calloc(num_insts, sizeof(bool)); if (is_target == NULL) { return ERROR; } for (Py_ssize_t i = 0; i < num_insts; i++) { PyObject *item = PyList_GET_ITEM(instructions, i); if (!PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 6) { PyErr_SetString(PyExc_ValueError, "expected a 6-tuple"); goto error; } int opcode = PyLong_AsLong(PyTuple_GET_ITEM(item, 0)); if (PyErr_Occurred()) { goto error; } if (HAS_TARGET(opcode)) { int oparg = PyLong_AsLong(PyTuple_GET_ITEM(item, 1)); if (PyErr_Occurred()) { goto error; } if (oparg < 0 || oparg >= num_insts) { PyErr_SetString(PyExc_ValueError, "label out of range"); goto error; } is_target[oparg] = true; } } for (int i = 0; i < num_insts; i++) { if (is_target[i]) { if (instr_sequence_use_label(seq, i) < 0) { goto error; } } PyObject *item = PyList_GET_ITEM(instructions, i); if (!PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 6) { PyErr_SetString(PyExc_ValueError, "expected a 6-tuple"); goto error; } int opcode = PyLong_AsLong(PyTuple_GET_ITEM(item, 0)); if (PyErr_Occurred()) { goto error; } int oparg; if (HAS_ARG(opcode)) { oparg = PyLong_AsLong(PyTuple_GET_ITEM(item, 1)); if (PyErr_Occurred()) { goto error; } } else { oparg = 0; } location loc; loc.lineno = PyLong_AsLong(PyTuple_GET_ITEM(item, 2)); if (PyErr_Occurred()) { goto error; } loc.end_lineno = PyLong_AsLong(PyTuple_GET_ITEM(item, 3)); if (PyErr_Occurred()) { goto error; } loc.col_offset = PyLong_AsLong(PyTuple_GET_ITEM(item, 4)); if (PyErr_Occurred()) { goto error; } loc.end_col_offset = PyLong_AsLong(PyTuple_GET_ITEM(item, 5)); if (PyErr_Occurred()) { goto error; } if (instr_sequence_addop(seq, opcode, oparg, loc) < 0) { goto error; } } PyMem_Free(is_target); return SUCCESS; error: PyMem_Free(is_target); return ERROR; } static int instructions_to_cfg(PyObject *instructions, cfg_builder *g) { instr_sequence seq; memset(&seq, 0, sizeof(instr_sequence)); if (instructions_to_instr_sequence(instructions, &seq) < 0) { goto error; } if (instr_sequence_to_cfg(&seq, g) < 0) { goto error; } instr_sequence_fini(&seq); return SUCCESS; error: instr_sequence_fini(&seq); return ERROR; } static PyObject * instr_sequence_to_instructions(instr_sequence *seq) { PyObject *instructions = PyList_New(0); if (instructions == NULL) { return NULL; } for (int i = 0; i < seq->s_used; i++) { instruction *instr = &seq->s_instrs[i]; location loc = instr->i_loc; int arg = HAS_TARGET(instr->i_opcode) ? seq->s_labelmap[instr->i_oparg] : instr->i_oparg; PyObject *inst_tuple = Py_BuildValue( "(iiiiii)", instr->i_opcode, arg, loc.lineno, loc.end_lineno, loc.col_offset, loc.end_col_offset); if (inst_tuple == NULL) { goto error; } int res = PyList_Append(instructions, inst_tuple); Py_DECREF(inst_tuple); if (res != 0) { goto error; } } return instructions; error: Py_XDECREF(instructions); return NULL; } static PyObject * cfg_to_instructions(cfg_builder *g) { PyObject *instructions = PyList_New(0); if (instructions == NULL) { return NULL; } int lbl = 0; for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { b->b_label = (jump_target_label){lbl}; lbl += b->b_iused; } for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { cfg_instr *instr = &b->b_instr[i]; location loc = instr->i_loc; int arg = HAS_TARGET(instr->i_opcode) ? instr->i_target->b_label.id : instr->i_oparg; PyObject *inst_tuple = Py_BuildValue( "(iiiiii)", instr->i_opcode, arg, loc.lineno, loc.end_lineno, loc.col_offset, loc.end_col_offset); if (inst_tuple == NULL) { goto error; } if (PyList_Append(instructions, inst_tuple) != 0) { Py_DECREF(inst_tuple); goto error; } Py_DECREF(inst_tuple); } } return instructions; error: Py_DECREF(instructions); return NULL; } PyObject * _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, int optimize, int compile_mode) { PyObject *res = NULL; PyObject *metadata = NULL; if (!PyAST_Check(ast)) { PyErr_SetString(PyExc_TypeError, "expected an AST"); return NULL; } PyArena *arena = _PyArena_New(); if (arena == NULL) { return NULL; } mod_ty mod = PyAST_obj2mod(ast, arena, compile_mode); if (mod == NULL || !_PyAST_Validate(mod)) { _PyArena_Free(arena); return NULL; } struct compiler *c = new_compiler(mod, filename, pflags, optimize, arena); if (c == NULL) { _PyArena_Free(arena); return NULL; } if (compiler_codegen(c, mod) < 0) { goto finally; } _PyCompile_CodeUnitMetadata *umd = &c->u->u_metadata; metadata = PyDict_New(); if (metadata == NULL) { goto finally; } #define SET_MATADATA_ITEM(key, value) \ if (value != NULL) { \ if (PyDict_SetItemString(metadata, key, value) < 0) goto finally; \ } SET_MATADATA_ITEM("name", umd->u_name); SET_MATADATA_ITEM("qualname", umd->u_qualname); SET_MATADATA_ITEM("consts", umd->u_consts); SET_MATADATA_ITEM("names", umd->u_names); SET_MATADATA_ITEM("varnames", umd->u_varnames); SET_MATADATA_ITEM("cellvars", umd->u_cellvars); SET_MATADATA_ITEM("freevars", umd->u_freevars); #undef SET_MATADATA_ITEM #define SET_MATADATA_INT(key, value) do { \ PyObject *v = PyLong_FromLong((long)value); \ if (v == NULL) goto finally; \ int res = PyDict_SetItemString(metadata, key, v); \ Py_XDECREF(v); \ if (res < 0) goto finally; \ } while (0); SET_MATADATA_INT("argcount", umd->u_argcount); SET_MATADATA_INT("posonlyargcount", umd->u_posonlyargcount); SET_MATADATA_INT("kwonlyargcount", umd->u_kwonlyargcount); #undef SET_MATADATA_INT int addNone = mod->kind != Expression_kind; if (add_return_at_end(c, addNone) < 0) { goto finally; } PyObject *insts = instr_sequence_to_instructions(INSTR_SEQUENCE(c)); if (insts == NULL) { goto finally; } res = PyTuple_Pack(2, insts, metadata); Py_DECREF(insts); finally: Py_XDECREF(metadata); compiler_exit_scope(c); compiler_free(c); _PyArena_Free(arena); return res; } PyObject * _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts, int nlocals) { PyObject *res = NULL; PyObject *const_cache = PyDict_New(); if (const_cache == NULL) { return NULL; } cfg_builder g; if (instructions_to_cfg(instructions, &g) < 0) { goto error; } int code_flags = 0, nparams = 0, firstlineno = 1; if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, code_flags, nlocals, nparams, firstlineno) < 0) { goto error; } res = cfg_to_instructions(&g); error: Py_DECREF(const_cache); _PyCfgBuilder_Fini(&g); return res; } int _PyCfg_JumpLabelsToTargets(basicblock *entryblock); PyCodeObject * _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, PyObject *instructions) { PyCodeObject *co = NULL; instr_sequence optimized_instrs; memset(&optimized_instrs, 0, sizeof(instr_sequence)); PyObject *const_cache = PyDict_New(); if (const_cache == NULL) { return NULL; } cfg_builder g; if (instructions_to_cfg(instructions, &g) < 0) { goto error; } if (_PyCfg_JumpLabelsToTargets(g.g_entryblock) < 0) { goto error; } int code_flags = 0; int nlocalsplus = prepare_localsplus(umd, &g, code_flags); if (nlocalsplus < 0) { goto error; } int maxdepth = _PyCfg_Stackdepth(g.g_entryblock, code_flags); if (maxdepth < 0) { goto error; } _PyCfg_ConvertPseudoOps(g.g_entryblock); /* Order of basic blocks must have been determined by now */ if (_PyCfg_ResolveJumps(&g) < 0) { goto error; } /* Can't modify the bytecode after computing jump offsets. */ if (cfg_to_instr_sequence(&g, &optimized_instrs) < 0) { goto error; } PyObject *consts = consts_dict_keys_inorder(umd->u_consts); if (consts == NULL) { goto error; } co = _PyAssemble_MakeCodeObject(umd, const_cache, consts, maxdepth, &optimized_instrs, nlocalsplus, code_flags, filename); Py_DECREF(consts); error: Py_DECREF(const_cache); _PyCfgBuilder_Fini(&g); instr_sequence_fini(&optimized_instrs); return co; } /* Retained for API compatibility. * Optimization is now done in _PyCfg_OptimizeCodeUnit */ PyObject * PyCode_Optimize(PyObject *code, PyObject* Py_UNUSED(consts), PyObject *Py_UNUSED(names), PyObject *Py_UNUSED(lnotab_obj)) { return Py_NewRef(code); } ================================================ FILE: Condvar.h ================================================ #ifndef _CONDVAR_IMPL_H_ #define _CONDVAR_IMPL_H_ #include "Python.h" #include "pycore_condvar.h" #ifdef _POSIX_THREADS /* * POSIX support */ /* These private functions are implemented in Python/thread_pthread.h */ int _PyThread_cond_init(PyCOND_T *cond); void _PyThread_cond_after(long long us, struct timespec *abs); /* The following functions return 0 on success, nonzero on error */ #define PyMUTEX_INIT(mut) pthread_mutex_init((mut), NULL) #define PyMUTEX_FINI(mut) pthread_mutex_destroy(mut) #define PyMUTEX_LOCK(mut) pthread_mutex_lock(mut) #define PyMUTEX_UNLOCK(mut) pthread_mutex_unlock(mut) #define PyCOND_INIT(cond) _PyThread_cond_init(cond) #define PyCOND_FINI(cond) pthread_cond_destroy(cond) #define PyCOND_SIGNAL(cond) pthread_cond_signal(cond) #define PyCOND_BROADCAST(cond) pthread_cond_broadcast(cond) #define PyCOND_WAIT(cond, mut) pthread_cond_wait((cond), (mut)) /* return 0 for success, 1 on timeout, -1 on error */ Py_LOCAL_INLINE(int) PyCOND_TIMEDWAIT(PyCOND_T *cond, PyMUTEX_T *mut, long long us) { struct timespec abs_timeout; _PyThread_cond_after(us, &abs_timeout); int ret = pthread_cond_timedwait(cond, mut, &abs_timeout); if (ret == ETIMEDOUT) { return 1; } if (ret) { return -1; } return 0; } #elif defined(NT_THREADS) /* * Windows (XP, 2003 server and later, as well as (hopefully) CE) support * * Emulated condition variables ones that work with XP and later, plus * example native support on VISTA and onwards. */ #if _PY_EMULATED_WIN_CV /* The mutex is a CriticalSection object and The condition variables is emulated with the help of a semaphore. This implementation still has the problem that the threads woken with a "signal" aren't necessarily those that are already waiting. It corresponds to listing 2 in: http://birrell.org/andrew/papers/ImplementingCVs.pdf Generic emulations of the pthread_cond_* API using earlier Win32 functions can be found on the web. The following read can be give background information to these issues, but the implementations are all broken in some way. http://www.cse.wustl.edu/~schmidt/win32-cv-1.html */ Py_LOCAL_INLINE(int) PyMUTEX_INIT(PyMUTEX_T *cs) { InitializeCriticalSection(cs); return 0; } Py_LOCAL_INLINE(int) PyMUTEX_FINI(PyMUTEX_T *cs) { DeleteCriticalSection(cs); return 0; } Py_LOCAL_INLINE(int) PyMUTEX_LOCK(PyMUTEX_T *cs) { EnterCriticalSection(cs); return 0; } Py_LOCAL_INLINE(int) PyMUTEX_UNLOCK(PyMUTEX_T *cs) { LeaveCriticalSection(cs); return 0; } Py_LOCAL_INLINE(int) PyCOND_INIT(PyCOND_T *cv) { /* A semaphore with a "large" max value, The positive value * is only needed to catch those "lost wakeup" events and * race conditions when a timed wait elapses. */ cv->sem = CreateSemaphore(NULL, 0, 100000, NULL); if (cv->sem==NULL) return -1; cv->waiting = 0; return 0; } Py_LOCAL_INLINE(int) PyCOND_FINI(PyCOND_T *cv) { return CloseHandle(cv->sem) ? 0 : -1; } /* this implementation can detect a timeout. Returns 1 on timeout, * 0 otherwise (and -1 on error) */ Py_LOCAL_INLINE(int) _PyCOND_WAIT_MS(PyCOND_T *cv, PyMUTEX_T *cs, DWORD ms) { DWORD wait; cv->waiting++; PyMUTEX_UNLOCK(cs); /* "lost wakeup bug" would occur if the caller were interrupted here, * but we are safe because we are using a semaphore which has an internal * count. */ wait = WaitForSingleObjectEx(cv->sem, ms, FALSE); PyMUTEX_LOCK(cs); if (wait != WAIT_OBJECT_0) --cv->waiting; /* Here we have a benign race condition with PyCOND_SIGNAL. * When failure occurs or timeout, it is possible that * PyCOND_SIGNAL also decrements this value * and signals releases the mutex. This is benign because it * just means an extra spurious wakeup for a waiting thread. * ('waiting' corresponds to the semaphore's "negative" count and * we may end up with e.g. (waiting == -1 && sem.count == 1). When * a new thread comes along, it will pass right through, having * adjusted it to (waiting == 0 && sem.count == 0). */ if (wait == WAIT_FAILED) return -1; /* return 0 on success, 1 on timeout */ return wait != WAIT_OBJECT_0; } Py_LOCAL_INLINE(int) PyCOND_WAIT(PyCOND_T *cv, PyMUTEX_T *cs) { int result = _PyCOND_WAIT_MS(cv, cs, INFINITE); return result >= 0 ? 0 : result; } Py_LOCAL_INLINE(int) PyCOND_TIMEDWAIT(PyCOND_T *cv, PyMUTEX_T *cs, long long us) { return _PyCOND_WAIT_MS(cv, cs, (DWORD)(us/1000)); } Py_LOCAL_INLINE(int) PyCOND_SIGNAL(PyCOND_T *cv) { /* this test allows PyCOND_SIGNAL to be a no-op unless required * to wake someone up, thus preventing an unbounded increase of * the semaphore's internal counter. */ if (cv->waiting > 0) { /* notifying thread decreases the cv->waiting count so that * a delay between notify and actual wakeup of the target thread * doesn't cause a number of extra ReleaseSemaphore calls. */ cv->waiting--; return ReleaseSemaphore(cv->sem, 1, NULL) ? 0 : -1; } return 0; } Py_LOCAL_INLINE(int) PyCOND_BROADCAST(PyCOND_T *cv) { int waiting = cv->waiting; if (waiting > 0) { cv->waiting = 0; return ReleaseSemaphore(cv->sem, waiting, NULL) ? 0 : -1; } return 0; } #else /* !_PY_EMULATED_WIN_CV */ Py_LOCAL_INLINE(int) PyMUTEX_INIT(PyMUTEX_T *cs) { InitializeSRWLock(cs); return 0; } Py_LOCAL_INLINE(int) PyMUTEX_FINI(PyMUTEX_T *cs) { return 0; } Py_LOCAL_INLINE(int) PyMUTEX_LOCK(PyMUTEX_T *cs) { AcquireSRWLockExclusive(cs); return 0; } Py_LOCAL_INLINE(int) PyMUTEX_UNLOCK(PyMUTEX_T *cs) { ReleaseSRWLockExclusive(cs); return 0; } Py_LOCAL_INLINE(int) PyCOND_INIT(PyCOND_T *cv) { InitializeConditionVariable(cv); return 0; } Py_LOCAL_INLINE(int) PyCOND_FINI(PyCOND_T *cv) { return 0; } Py_LOCAL_INLINE(int) PyCOND_WAIT(PyCOND_T *cv, PyMUTEX_T *cs) { return SleepConditionVariableSRW(cv, cs, INFINITE, 0) ? 0 : -1; } /* This implementation makes no distinction about timeouts. Signal * 2 to indicate that we don't know. */ Py_LOCAL_INLINE(int) PyCOND_TIMEDWAIT(PyCOND_T *cv, PyMUTEX_T *cs, long long us) { return SleepConditionVariableSRW(cv, cs, (DWORD)(us/1000), 0) ? 2 : -1; } Py_LOCAL_INLINE(int) PyCOND_SIGNAL(PyCOND_T *cv) { WakeConditionVariable(cv); return 0; } Py_LOCAL_INLINE(int) PyCOND_BROADCAST(PyCOND_T *cv) { WakeAllConditionVariable(cv); return 0; } #endif /* _PY_EMULATED_WIN_CV */ #endif /* _POSIX_THREADS, NT_THREADS */ #endif /* _CONDVAR_IMPL_H_ */ ================================================ FILE: Context.c ================================================ #include "Python.h" #include "pycore_call.h" // _PyObject_VectorcallTstate() #include "pycore_context.h" #include "pycore_gc.h" // _PyObject_GC_MAY_BE_TRACKED() #include "pycore_hamt.h" #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_object.h" #include "pycore_pyerrors.h" #include "pycore_pystate.h" // _PyThreadState_GET() #include "structmember.h" // PyMemberDef #include "clinic/context.c.h" /*[clinic input] module _contextvars [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=a0955718c8b8cea6]*/ #define ENSURE_Context(o, err_ret) \ if (!PyContext_CheckExact(o)) { \ PyErr_SetString(PyExc_TypeError, \ "an instance of Context was expected"); \ return err_ret; \ } #define ENSURE_ContextVar(o, err_ret) \ if (!PyContextVar_CheckExact(o)) { \ PyErr_SetString(PyExc_TypeError, \ "an instance of ContextVar was expected"); \ return err_ret; \ } #define ENSURE_ContextToken(o, err_ret) \ if (!PyContextToken_CheckExact(o)) { \ PyErr_SetString(PyExc_TypeError, \ "an instance of Token was expected"); \ return err_ret; \ } /////////////////////////// Context API static PyContext * context_new_empty(void); static PyContext * context_new_from_vars(PyHamtObject *vars); static inline PyContext * context_get(void); static PyContextToken * token_new(PyContext *ctx, PyContextVar *var, PyObject *val); static PyContextVar * contextvar_new(PyObject *name, PyObject *def); static int contextvar_set(PyContextVar *var, PyObject *val); static int contextvar_del(PyContextVar *var); #if PyContext_MAXFREELIST > 0 static struct _Py_context_state * get_context_state(void) { PyInterpreterState *interp = _PyInterpreterState_GET(); return &interp->context; } #endif PyObject * _PyContext_NewHamtForTests(void) { return (PyObject *)_PyHamt_New(); } PyObject * PyContext_New(void) { return (PyObject *)context_new_empty(); } PyObject * PyContext_Copy(PyObject * octx) { ENSURE_Context(octx, NULL) PyContext *ctx = (PyContext *)octx; return (PyObject *)context_new_from_vars(ctx->ctx_vars); } PyObject * PyContext_CopyCurrent(void) { PyContext *ctx = context_get(); if (ctx == NULL) { return NULL; } return (PyObject *)context_new_from_vars(ctx->ctx_vars); } static int _PyContext_Enter(PyThreadState *ts, PyObject *octx) { ENSURE_Context(octx, -1) PyContext *ctx = (PyContext *)octx; if (ctx->ctx_entered) { _PyErr_Format(ts, PyExc_RuntimeError, "cannot enter context: %R is already entered", ctx); return -1; } ctx->ctx_prev = (PyContext *)ts->context; /* borrow */ ctx->ctx_entered = 1; ts->context = Py_NewRef(ctx); ts->context_ver++; return 0; } int PyContext_Enter(PyObject *octx) { PyThreadState *ts = _PyThreadState_GET(); assert(ts != NULL); return _PyContext_Enter(ts, octx); } static int _PyContext_Exit(PyThreadState *ts, PyObject *octx) { ENSURE_Context(octx, -1) PyContext *ctx = (PyContext *)octx; if (!ctx->ctx_entered) { PyErr_Format(PyExc_RuntimeError, "cannot exit context: %R has not been entered", ctx); return -1; } if (ts->context != (PyObject *)ctx) { /* Can only happen if someone misuses the C API */ PyErr_SetString(PyExc_RuntimeError, "cannot exit context: thread state references " "a different context object"); return -1; } Py_SETREF(ts->context, (PyObject *)ctx->ctx_prev); ts->context_ver++; ctx->ctx_prev = NULL; ctx->ctx_entered = 0; return 0; } int PyContext_Exit(PyObject *octx) { PyThreadState *ts = _PyThreadState_GET(); assert(ts != NULL); return _PyContext_Exit(ts, octx); } PyObject * PyContextVar_New(const char *name, PyObject *def) { PyObject *pyname = PyUnicode_FromString(name); if (pyname == NULL) { return NULL; } PyContextVar *var = contextvar_new(pyname, def); Py_DECREF(pyname); return (PyObject *)var; } int PyContextVar_Get(PyObject *ovar, PyObject *def, PyObject **val) { ENSURE_ContextVar(ovar, -1) PyContextVar *var = (PyContextVar *)ovar; PyThreadState *ts = _PyThreadState_GET(); assert(ts != NULL); if (ts->context == NULL) { goto not_found; } if (var->var_cached != NULL && var->var_cached_tsid == ts->id && var->var_cached_tsver == ts->context_ver) { *val = var->var_cached; goto found; } assert(PyContext_CheckExact(ts->context)); PyHamtObject *vars = ((PyContext *)ts->context)->ctx_vars; PyObject *found = NULL; int res = _PyHamt_Find(vars, (PyObject*)var, &found); if (res < 0) { goto error; } if (res == 1) { assert(found != NULL); var->var_cached = found; /* borrow */ var->var_cached_tsid = ts->id; var->var_cached_tsver = ts->context_ver; *val = found; goto found; } not_found: if (def == NULL) { if (var->var_default != NULL) { *val = var->var_default; goto found; } *val = NULL; goto found; } else { *val = def; goto found; } found: Py_XINCREF(*val); return 0; error: *val = NULL; return -1; } PyObject * PyContextVar_Set(PyObject *ovar, PyObject *val) { ENSURE_ContextVar(ovar, NULL) PyContextVar *var = (PyContextVar *)ovar; if (!PyContextVar_CheckExact(var)) { PyErr_SetString( PyExc_TypeError, "an instance of ContextVar was expected"); return NULL; } PyContext *ctx = context_get(); if (ctx == NULL) { return NULL; } PyObject *old_val = NULL; int found = _PyHamt_Find(ctx->ctx_vars, (PyObject *)var, &old_val); if (found < 0) { return NULL; } Py_XINCREF(old_val); PyContextToken *tok = token_new(ctx, var, old_val); Py_XDECREF(old_val); if (contextvar_set(var, val)) { Py_DECREF(tok); return NULL; } return (PyObject *)tok; } int PyContextVar_Reset(PyObject *ovar, PyObject *otok) { ENSURE_ContextVar(ovar, -1) ENSURE_ContextToken(otok, -1) PyContextVar *var = (PyContextVar *)ovar; PyContextToken *tok = (PyContextToken *)otok; if (tok->tok_used) { PyErr_Format(PyExc_RuntimeError, "%R has already been used once", tok); return -1; } if (var != tok->tok_var) { PyErr_Format(PyExc_ValueError, "%R was created by a different ContextVar", tok); return -1; } PyContext *ctx = context_get(); if (ctx != tok->tok_ctx) { PyErr_Format(PyExc_ValueError, "%R was created in a different Context", tok); return -1; } tok->tok_used = 1; if (tok->tok_oldval == NULL) { return contextvar_del(var); } else { return contextvar_set(var, tok->tok_oldval); } } /////////////////////////// PyContext /*[clinic input] class _contextvars.Context "PyContext *" "&PyContext_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=bdf87f8e0cb580e8]*/ static inline PyContext * _context_alloc(void) { PyContext *ctx; #if PyContext_MAXFREELIST > 0 struct _Py_context_state *state = get_context_state(); #ifdef Py_DEBUG // _context_alloc() must not be called after _PyContext_Fini() assert(state->numfree != -1); #endif if (state->numfree) { state->numfree--; ctx = state->freelist; state->freelist = (PyContext *)ctx->ctx_weakreflist; OBJECT_STAT_INC(from_freelist); ctx->ctx_weakreflist = NULL; _Py_NewReference((PyObject *)ctx); } else #endif { ctx = PyObject_GC_New(PyContext, &PyContext_Type); if (ctx == NULL) { return NULL; } } ctx->ctx_vars = NULL; ctx->ctx_prev = NULL; ctx->ctx_entered = 0; ctx->ctx_weakreflist = NULL; return ctx; } static PyContext * context_new_empty(void) { PyContext *ctx = _context_alloc(); if (ctx == NULL) { return NULL; } ctx->ctx_vars = _PyHamt_New(); if (ctx->ctx_vars == NULL) { Py_DECREF(ctx); return NULL; } _PyObject_GC_TRACK(ctx); return ctx; } static PyContext * context_new_from_vars(PyHamtObject *vars) { PyContext *ctx = _context_alloc(); if (ctx == NULL) { return NULL; } ctx->ctx_vars = (PyHamtObject*)Py_NewRef(vars); _PyObject_GC_TRACK(ctx); return ctx; } static inline PyContext * context_get(void) { PyThreadState *ts = _PyThreadState_GET(); assert(ts != NULL); PyContext *current_ctx = (PyContext *)ts->context; if (current_ctx == NULL) { current_ctx = context_new_empty(); if (current_ctx == NULL) { return NULL; } ts->context = (PyObject *)current_ctx; } return current_ctx; } static int context_check_key_type(PyObject *key) { if (!PyContextVar_CheckExact(key)) { // abort(); PyErr_Format(PyExc_TypeError, "a ContextVar key was expected, got %R", key); return -1; } return 0; } static PyObject * context_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { if (PyTuple_Size(args) || (kwds != NULL && PyDict_Size(kwds))) { PyErr_SetString( PyExc_TypeError, "Context() does not accept any arguments"); return NULL; } return PyContext_New(); } static int context_tp_clear(PyContext *self) { Py_CLEAR(self->ctx_prev); Py_CLEAR(self->ctx_vars); return 0; } static int context_tp_traverse(PyContext *self, visitproc visit, void *arg) { Py_VISIT(self->ctx_prev); Py_VISIT(self->ctx_vars); return 0; } static void context_tp_dealloc(PyContext *self) { _PyObject_GC_UNTRACK(self); if (self->ctx_weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject*)self); } (void)context_tp_clear(self); #if PyContext_MAXFREELIST > 0 struct _Py_context_state *state = get_context_state(); #ifdef Py_DEBUG // _context_alloc() must not be called after _PyContext_Fini() assert(state->numfree != -1); #endif if (state->numfree < PyContext_MAXFREELIST) { state->numfree++; self->ctx_weakreflist = (PyObject *)state->freelist; state->freelist = self; OBJECT_STAT_INC(to_freelist); } else #endif { Py_TYPE(self)->tp_free(self); } } static PyObject * context_tp_iter(PyContext *self) { return _PyHamt_NewIterKeys(self->ctx_vars); } static PyObject * context_tp_richcompare(PyObject *v, PyObject *w, int op) { if (!PyContext_CheckExact(v) || !PyContext_CheckExact(w) || (op != Py_EQ && op != Py_NE)) { Py_RETURN_NOTIMPLEMENTED; } int res = _PyHamt_Eq( ((PyContext *)v)->ctx_vars, ((PyContext *)w)->ctx_vars); if (res < 0) { return NULL; } if (op == Py_NE) { res = !res; } if (res) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } static Py_ssize_t context_tp_len(PyContext *self) { return _PyHamt_Len(self->ctx_vars); } static PyObject * context_tp_subscript(PyContext *self, PyObject *key) { if (context_check_key_type(key)) { return NULL; } PyObject *val = NULL; int found = _PyHamt_Find(self->ctx_vars, key, &val); if (found < 0) { return NULL; } if (found == 0) { PyErr_SetObject(PyExc_KeyError, key); return NULL; } return Py_NewRef(val); } static int context_tp_contains(PyContext *self, PyObject *key) { if (context_check_key_type(key)) { return -1; } PyObject *val = NULL; return _PyHamt_Find(self->ctx_vars, key, &val); } /*[clinic input] _contextvars.Context.get key: object default: object = None / Return the value for `key` if `key` has the value in the context object. If `key` does not exist, return `default`. If `default` is not given, return None. [clinic start generated code]*/ static PyObject * _contextvars_Context_get_impl(PyContext *self, PyObject *key, PyObject *default_value) /*[clinic end generated code: output=0c54aa7664268189 input=c8eeb81505023995]*/ { if (context_check_key_type(key)) { return NULL; } PyObject *val = NULL; int found = _PyHamt_Find(self->ctx_vars, key, &val); if (found < 0) { return NULL; } if (found == 0) { return Py_NewRef(default_value); } return Py_NewRef(val); } /*[clinic input] _contextvars.Context.items Return all variables and their values in the context object. The result is returned as a list of 2-tuples (variable, value). [clinic start generated code]*/ static PyObject * _contextvars_Context_items_impl(PyContext *self) /*[clinic end generated code: output=fa1655c8a08502af input=00db64ae379f9f42]*/ { return _PyHamt_NewIterItems(self->ctx_vars); } /*[clinic input] _contextvars.Context.keys Return a list of all variables in the context object. [clinic start generated code]*/ static PyObject * _contextvars_Context_keys_impl(PyContext *self) /*[clinic end generated code: output=177227c6b63ec0e2 input=114b53aebca3449c]*/ { return _PyHamt_NewIterKeys(self->ctx_vars); } /*[clinic input] _contextvars.Context.values Return a list of all variables' values in the context object. [clinic start generated code]*/ static PyObject * _contextvars_Context_values_impl(PyContext *self) /*[clinic end generated code: output=d286dabfc8db6dde input=ce8075d04a6ea526]*/ { return _PyHamt_NewIterValues(self->ctx_vars); } /*[clinic input] _contextvars.Context.copy Return a shallow copy of the context object. [clinic start generated code]*/ static PyObject * _contextvars_Context_copy_impl(PyContext *self) /*[clinic end generated code: output=30ba8896c4707a15 input=ebafdbdd9c72d592]*/ { return (PyObject *)context_new_from_vars(self->ctx_vars); } static PyObject * context_run(PyContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyThreadState *ts = _PyThreadState_GET(); if (nargs < 1) { _PyErr_SetString(ts, PyExc_TypeError, "run() missing 1 required positional argument"); return NULL; } if (_PyContext_Enter(ts, (PyObject *)self)) { return NULL; } PyObject *call_result = _PyObject_VectorcallTstate( ts, args[0], args + 1, nargs - 1, kwnames); if (_PyContext_Exit(ts, (PyObject *)self)) { return NULL; } return call_result; } static PyMethodDef PyContext_methods[] = { _CONTEXTVARS_CONTEXT_GET_METHODDEF _CONTEXTVARS_CONTEXT_ITEMS_METHODDEF _CONTEXTVARS_CONTEXT_KEYS_METHODDEF _CONTEXTVARS_CONTEXT_VALUES_METHODDEF _CONTEXTVARS_CONTEXT_COPY_METHODDEF {"run", _PyCFunction_CAST(context_run), METH_FASTCALL | METH_KEYWORDS, NULL}, {NULL, NULL} }; static PySequenceMethods PyContext_as_sequence = { 0, /* sq_length */ 0, /* sq_concat */ 0, /* sq_repeat */ 0, /* sq_item */ 0, /* sq_slice */ 0, /* sq_ass_item */ 0, /* sq_ass_slice */ (objobjproc)context_tp_contains, /* sq_contains */ 0, /* sq_inplace_concat */ 0, /* sq_inplace_repeat */ }; static PyMappingMethods PyContext_as_mapping = { (lenfunc)context_tp_len, /* mp_length */ (binaryfunc)context_tp_subscript, /* mp_subscript */ }; PyTypeObject PyContext_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "_contextvars.Context", sizeof(PyContext), .tp_methods = PyContext_methods, .tp_as_mapping = &PyContext_as_mapping, .tp_as_sequence = &PyContext_as_sequence, .tp_iter = (getiterfunc)context_tp_iter, .tp_dealloc = (destructor)context_tp_dealloc, .tp_getattro = PyObject_GenericGetAttr, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_richcompare = context_tp_richcompare, .tp_traverse = (traverseproc)context_tp_traverse, .tp_clear = (inquiry)context_tp_clear, .tp_new = context_tp_new, .tp_weaklistoffset = offsetof(PyContext, ctx_weakreflist), .tp_hash = PyObject_HashNotImplemented, }; /////////////////////////// ContextVar static int contextvar_set(PyContextVar *var, PyObject *val) { var->var_cached = NULL; PyThreadState *ts = _PyThreadState_GET(); PyContext *ctx = context_get(); if (ctx == NULL) { return -1; } PyHamtObject *new_vars = _PyHamt_Assoc( ctx->ctx_vars, (PyObject *)var, val); if (new_vars == NULL) { return -1; } Py_SETREF(ctx->ctx_vars, new_vars); var->var_cached = val; /* borrow */ var->var_cached_tsid = ts->id; var->var_cached_tsver = ts->context_ver; return 0; } static int contextvar_del(PyContextVar *var) { var->var_cached = NULL; PyContext *ctx = context_get(); if (ctx == NULL) { return -1; } PyHamtObject *vars = ctx->ctx_vars; PyHamtObject *new_vars = _PyHamt_Without(vars, (PyObject *)var); if (new_vars == NULL) { return -1; } if (vars == new_vars) { Py_DECREF(new_vars); PyErr_SetObject(PyExc_LookupError, (PyObject *)var); return -1; } Py_SETREF(ctx->ctx_vars, new_vars); return 0; } static Py_hash_t contextvar_generate_hash(void *addr, PyObject *name) { /* Take hash of `name` and XOR it with the object's addr. The structure of the tree is encoded in objects' hashes, which means that sufficiently similar hashes would result in tall trees with many Collision nodes. Which would, in turn, result in slower get and set operations. The XORing helps to ensure that: (1) sequentially allocated ContextVar objects have different hashes; (2) context variables with equal names have different hashes. */ Py_hash_t name_hash = PyObject_Hash(name); if (name_hash == -1) { return -1; } Py_hash_t res = _Py_HashPointer(addr) ^ name_hash; return res == -1 ? -2 : res; } static PyContextVar * contextvar_new(PyObject *name, PyObject *def) { if (!PyUnicode_Check(name)) { PyErr_SetString(PyExc_TypeError, "context variable name must be a str"); return NULL; } PyContextVar *var = PyObject_GC_New(PyContextVar, &PyContextVar_Type); if (var == NULL) { return NULL; } var->var_hash = contextvar_generate_hash(var, name); if (var->var_hash == -1) { Py_DECREF(var); return NULL; } var->var_name = Py_NewRef(name); var->var_default = Py_XNewRef(def); var->var_cached = NULL; var->var_cached_tsid = 0; var->var_cached_tsver = 0; if (_PyObject_GC_MAY_BE_TRACKED(name) || (def != NULL && _PyObject_GC_MAY_BE_TRACKED(def))) { PyObject_GC_Track(var); } return var; } /*[clinic input] class _contextvars.ContextVar "PyContextVar *" "&PyContextVar_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=445da935fa8883c3]*/ static PyObject * contextvar_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"", "default", NULL}; PyObject *name; PyObject *def = NULL; if (!PyArg_ParseTupleAndKeywords( args, kwds, "O|$O:ContextVar", kwlist, &name, &def)) { return NULL; } return (PyObject *)contextvar_new(name, def); } static int contextvar_tp_clear(PyContextVar *self) { Py_CLEAR(self->var_name); Py_CLEAR(self->var_default); self->var_cached = NULL; self->var_cached_tsid = 0; self->var_cached_tsver = 0; return 0; } static int contextvar_tp_traverse(PyContextVar *self, visitproc visit, void *arg) { Py_VISIT(self->var_name); Py_VISIT(self->var_default); return 0; } static void contextvar_tp_dealloc(PyContextVar *self) { PyObject_GC_UnTrack(self); (void)contextvar_tp_clear(self); Py_TYPE(self)->tp_free(self); } static Py_hash_t contextvar_tp_hash(PyContextVar *self) { return self->var_hash; } static PyObject * contextvar_tp_repr(PyContextVar *self) { _PyUnicodeWriter writer; _PyUnicodeWriter_Init(&writer); if (_PyUnicodeWriter_WriteASCIIString( &writer, "", self); if (addr == NULL) { goto error; } if (_PyUnicodeWriter_WriteStr(&writer, addr) < 0) { Py_DECREF(addr); goto error; } Py_DECREF(addr); return _PyUnicodeWriter_Finish(&writer); error: _PyUnicodeWriter_Dealloc(&writer); return NULL; } /*[clinic input] _contextvars.ContextVar.get default: object = NULL / Return a value for the context variable for the current context. If there is no value for the variable in the current context, the method will: * return the value of the default argument of the method, if provided; or * return the default value for the context variable, if it was created with one; or * raise a LookupError. [clinic start generated code]*/ static PyObject * _contextvars_ContextVar_get_impl(PyContextVar *self, PyObject *default_value) /*[clinic end generated code: output=0746bd0aa2ced7bf input=30aa2ab9e433e401]*/ { if (!PyContextVar_CheckExact(self)) { PyErr_SetString( PyExc_TypeError, "an instance of ContextVar was expected"); return NULL; } PyObject *val; if (PyContextVar_Get((PyObject *)self, default_value, &val) < 0) { return NULL; } if (val == NULL) { PyErr_SetObject(PyExc_LookupError, (PyObject *)self); return NULL; } return val; } /*[clinic input] _contextvars.ContextVar.set value: object / Call to set a new value for the context variable in the current context. The required value argument is the new value for the context variable. Returns a Token object that can be used to restore the variable to its previous value via the `ContextVar.reset()` method. [clinic start generated code]*/ static PyObject * _contextvars_ContextVar_set(PyContextVar *self, PyObject *value) /*[clinic end generated code: output=446ed5e820d6d60b input=c0a6887154227453]*/ { return PyContextVar_Set((PyObject *)self, value); } /*[clinic input] _contextvars.ContextVar.reset token: object / Reset the context variable. The variable is reset to the value it had before the `ContextVar.set()` that created the token was used. [clinic start generated code]*/ static PyObject * _contextvars_ContextVar_reset(PyContextVar *self, PyObject *token) /*[clinic end generated code: output=d4ee34d0742d62ee input=ebe2881e5af4ffda]*/ { if (!PyContextToken_CheckExact(token)) { PyErr_Format(PyExc_TypeError, "expected an instance of Token, got %R", token); return NULL; } if (PyContextVar_Reset((PyObject *)self, token)) { return NULL; } Py_RETURN_NONE; } static PyMemberDef PyContextVar_members[] = { {"name", T_OBJECT, offsetof(PyContextVar, var_name), READONLY}, {NULL} }; static PyMethodDef PyContextVar_methods[] = { _CONTEXTVARS_CONTEXTVAR_GET_METHODDEF _CONTEXTVARS_CONTEXTVAR_SET_METHODDEF _CONTEXTVARS_CONTEXTVAR_RESET_METHODDEF {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, {NULL, NULL} }; PyTypeObject PyContextVar_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "_contextvars.ContextVar", sizeof(PyContextVar), .tp_methods = PyContextVar_methods, .tp_members = PyContextVar_members, .tp_dealloc = (destructor)contextvar_tp_dealloc, .tp_getattro = PyObject_GenericGetAttr, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = (traverseproc)contextvar_tp_traverse, .tp_clear = (inquiry)contextvar_tp_clear, .tp_new = contextvar_tp_new, .tp_free = PyObject_GC_Del, .tp_hash = (hashfunc)contextvar_tp_hash, .tp_repr = (reprfunc)contextvar_tp_repr, }; /////////////////////////// Token static PyObject * get_token_missing(void); /*[clinic input] class _contextvars.Token "PyContextToken *" "&PyContextToken_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=338a5e2db13d3f5b]*/ static PyObject * token_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyErr_SetString(PyExc_RuntimeError, "Tokens can only be created by ContextVars"); return NULL; } static int token_tp_clear(PyContextToken *self) { Py_CLEAR(self->tok_ctx); Py_CLEAR(self->tok_var); Py_CLEAR(self->tok_oldval); return 0; } static int token_tp_traverse(PyContextToken *self, visitproc visit, void *arg) { Py_VISIT(self->tok_ctx); Py_VISIT(self->tok_var); Py_VISIT(self->tok_oldval); return 0; } static void token_tp_dealloc(PyContextToken *self) { PyObject_GC_UnTrack(self); (void)token_tp_clear(self); Py_TYPE(self)->tp_free(self); } static PyObject * token_tp_repr(PyContextToken *self) { _PyUnicodeWriter writer; _PyUnicodeWriter_Init(&writer); if (_PyUnicodeWriter_WriteASCIIString(&writer, "tok_used) { if (_PyUnicodeWriter_WriteASCIIString(&writer, " used", 5) < 0) { goto error; } } if (_PyUnicodeWriter_WriteASCIIString(&writer, " var=", 5) < 0) { goto error; } PyObject *var = PyObject_Repr((PyObject *)self->tok_var); if (var == NULL) { goto error; } if (_PyUnicodeWriter_WriteStr(&writer, var) < 0) { Py_DECREF(var); goto error; } Py_DECREF(var); PyObject *addr = PyUnicode_FromFormat(" at %p>", self); if (addr == NULL) { goto error; } if (_PyUnicodeWriter_WriteStr(&writer, addr) < 0) { Py_DECREF(addr); goto error; } Py_DECREF(addr); return _PyUnicodeWriter_Finish(&writer); error: _PyUnicodeWriter_Dealloc(&writer); return NULL; } static PyObject * token_get_var(PyContextToken *self, void *Py_UNUSED(ignored)) { return Py_NewRef(self->tok_var);; } static PyObject * token_get_old_value(PyContextToken *self, void *Py_UNUSED(ignored)) { if (self->tok_oldval == NULL) { return get_token_missing(); } return Py_NewRef(self->tok_oldval); } static PyGetSetDef PyContextTokenType_getsetlist[] = { {"var", (getter)token_get_var, NULL, NULL}, {"old_value", (getter)token_get_old_value, NULL, NULL}, {NULL} }; static PyMethodDef PyContextTokenType_methods[] = { {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, {NULL} }; PyTypeObject PyContextToken_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "_contextvars.Token", sizeof(PyContextToken), .tp_methods = PyContextTokenType_methods, .tp_getset = PyContextTokenType_getsetlist, .tp_dealloc = (destructor)token_tp_dealloc, .tp_getattro = PyObject_GenericGetAttr, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = (traverseproc)token_tp_traverse, .tp_clear = (inquiry)token_tp_clear, .tp_new = token_tp_new, .tp_free = PyObject_GC_Del, .tp_hash = PyObject_HashNotImplemented, .tp_repr = (reprfunc)token_tp_repr, }; static PyContextToken * token_new(PyContext *ctx, PyContextVar *var, PyObject *val) { PyContextToken *tok = PyObject_GC_New(PyContextToken, &PyContextToken_Type); if (tok == NULL) { return NULL; } tok->tok_ctx = (PyContext*)Py_NewRef(ctx); tok->tok_var = (PyContextVar*)Py_NewRef(var); tok->tok_oldval = Py_XNewRef(val); tok->tok_used = 0; PyObject_GC_Track(tok); return tok; } /////////////////////////// Token.MISSING static PyObject * context_token_missing_tp_repr(PyObject *self) { return PyUnicode_FromString(""); } static void context_token_missing_tp_dealloc(_PyContextTokenMissing *Py_UNUSED(self)) { #ifdef Py_DEBUG /* The singleton is statically allocated. */ _Py_FatalRefcountError("deallocating the token missing singleton"); #else return; #endif } PyTypeObject _PyContextTokenMissing_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "Token.MISSING", sizeof(_PyContextTokenMissing), .tp_dealloc = (destructor)context_token_missing_tp_dealloc, .tp_getattro = PyObject_GenericGetAttr, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_repr = context_token_missing_tp_repr, }; static PyObject * get_token_missing(void) { return Py_NewRef(&_Py_SINGLETON(context_token_missing)); } /////////////////////////// void _PyContext_ClearFreeList(PyInterpreterState *interp) { #if PyContext_MAXFREELIST > 0 struct _Py_context_state *state = &interp->context; for (; state->numfree; state->numfree--) { PyContext *ctx = state->freelist; state->freelist = (PyContext *)ctx->ctx_weakreflist; ctx->ctx_weakreflist = NULL; PyObject_GC_Del(ctx); } #endif } void _PyContext_Fini(PyInterpreterState *interp) { _PyContext_ClearFreeList(interp); #if defined(Py_DEBUG) && PyContext_MAXFREELIST > 0 struct _Py_context_state *state = &interp->context; state->numfree = -1; #endif } PyStatus _PyContext_Init(PyInterpreterState *interp) { if (!_Py_IsMainInterpreter(interp)) { return _PyStatus_OK(); } PyObject *missing = get_token_missing(); if (PyDict_SetItemString( _PyType_GetDict(&PyContextToken_Type), "MISSING", missing)) { Py_DECREF(missing); return _PyStatus_ERR("can't init context types"); } Py_DECREF(missing); return _PyStatus_OK(); } ================================================ FILE: Dtoa.c ================================================ /**************************************************************** * This is dtoa.c by David M. Gay, downloaded from * http://www.netlib.org/fp/dtoa.c on April 15, 2009 and modified for * inclusion into the Python core by Mark E. T. Dickinson and Eric V. Smith. * * Please remember to check http://www.netlib.org/fp regularly (and especially * before any Python release) for bugfixes and updates. * * The major modifications from Gay's original code are as follows: * * 0. The original code has been specialized to Python's needs by removing * many of the #ifdef'd sections. In particular, code to support VAX and * IBM floating-point formats, hex NaNs, hex floats, locale-aware * treatment of the decimal point, and setting of the inexact flag have * been removed. * * 1. We use PyMem_Malloc and PyMem_Free in place of malloc and free. * * 2. The public functions strtod, dtoa and freedtoa all now have * a _Py_dg_ prefix. * * 3. Instead of assuming that PyMem_Malloc always succeeds, we thread * PyMem_Malloc failures through the code. The functions * * Balloc, multadd, s2b, i2b, mult, pow5mult, lshift, diff, d2b * * of return type *Bigint all return NULL to indicate a malloc failure. * Similarly, rv_alloc and nrv_alloc (return type char *) return NULL on * failure. bigcomp now has return type int (it used to be void) and * returns -1 on failure and 0 otherwise. _Py_dg_dtoa returns NULL * on failure. _Py_dg_strtod indicates failure due to malloc failure * by returning -1.0, setting errno=ENOMEM and *se to s00. * * 4. The static variable dtoa_result has been removed. Callers of * _Py_dg_dtoa are expected to call _Py_dg_freedtoa to free * the memory allocated by _Py_dg_dtoa. * * 5. The code has been reformatted to better fit with Python's * C style guide (PEP 7). * * 6. A bug in the memory allocation has been fixed: to avoid FREEing memory * that hasn't been MALLOC'ed, private_mem should only be used when k <= * Kmax. * * 7. _Py_dg_strtod has been modified so that it doesn't accept strings with * leading whitespace. * * 8. A corner case where _Py_dg_dtoa didn't strip trailing zeros has been * fixed. (bugs.python.org/issue40780) * ***************************************************************/ /* Please send bug reports for the original dtoa.c code to David M. Gay (dmg * at acm dot org, with " at " changed at "@" and " dot " changed to "."). * Please report bugs for this modified version using the Python issue tracker * (http://bugs.python.org). */ /* On a machine with IEEE extended-precision registers, it is * necessary to specify double-precision (53-bit) rounding precision * before invoking strtod or dtoa. If the machine uses (the equivalent * of) Intel 80x87 arithmetic, the call * _control87(PC_53, MCW_PC); * does this with many compilers. Whether this or another call is * appropriate depends on the compiler; for this to work, it may be * necessary to #include "float.h" or another system-dependent header * file. */ /* strtod for IEEE-, VAX-, and IBM-arithmetic machines. * * This strtod returns a nearest machine number to the input decimal * string (or sets errno to ERANGE). With IEEE arithmetic, ties are * broken by the IEEE round-even rule. Otherwise ties are broken by * biased rounding (add half and chop). * * Inspired loosely by William D. Clinger's paper "How to Read Floating * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. * * Modifications: * * 1. We only require IEEE, IBM, or VAX double-precision * arithmetic (not IEEE double-extended). * 2. We get by with floating-point arithmetic in a case that * Clinger missed -- when we're computing d * 10^n * for a small integer d and the integer n is not too * much larger than 22 (the maximum integer k for which * we can represent 10^k exactly), we may be able to * compute (d*10^k) * 10^(e-k) with just one roundoff. * 3. Rather than a bit-at-a-time adjustment of the binary * result in the hard case, we use floating-point * arithmetic to determine the adjustment to within * one bit; only in really hard cases do we need to * compute a second residual. * 4. Because of 3., we don't need a large table of powers of 10 * for ten-to-e (just some small tables, e.g. of 10^k * for 0 <= k <= 22). */ /* Linking of Python's #defines to Gay's #defines starts here. */ #include "Python.h" #include "pycore_dtoa.h" // _PY_SHORT_FLOAT_REPR #include "pycore_pystate.h" // _PyInterpreterState_GET() #include // exit() /* if _PY_SHORT_FLOAT_REPR == 0, then don't even try to compile the following code */ #if _PY_SHORT_FLOAT_REPR == 1 #include "float.h" #define MALLOC PyMem_Malloc #define FREE PyMem_Free /* This code should also work for ARM mixed-endian format on little-endian machines, where doubles have byte order 45670123 (in increasing address order, 0 being the least significant byte). */ #ifdef DOUBLE_IS_LITTLE_ENDIAN_IEEE754 # define IEEE_8087 #endif #if defined(DOUBLE_IS_BIG_ENDIAN_IEEE754) || \ defined(DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754) # define IEEE_MC68k #endif #if defined(IEEE_8087) + defined(IEEE_MC68k) != 1 #error "Exactly one of IEEE_8087 or IEEE_MC68k should be defined." #endif /* The code below assumes that the endianness of integers matches the endianness of the two 32-bit words of a double. Check this. */ #if defined(WORDS_BIGENDIAN) && (defined(DOUBLE_IS_LITTLE_ENDIAN_IEEE754) || \ defined(DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754)) #error "doubles and ints have incompatible endianness" #endif #if !defined(WORDS_BIGENDIAN) && defined(DOUBLE_IS_BIG_ENDIAN_IEEE754) #error "doubles and ints have incompatible endianness" #endif // ULong is defined in pycore_dtoa.h. typedef int32_t Long; typedef uint64_t ULLong; #undef DEBUG #ifdef Py_DEBUG #define DEBUG #endif /* End Python #define linking */ #ifdef DEBUG #define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} #endif #ifdef __cplusplus extern "C" { #endif typedef union { double d; ULong L[2]; } U; #ifdef IEEE_8087 #define word0(x) (x)->L[1] #define word1(x) (x)->L[0] #else #define word0(x) (x)->L[0] #define word1(x) (x)->L[1] #endif #define dval(x) (x)->d #ifndef STRTOD_DIGLIM #define STRTOD_DIGLIM 40 #endif /* maximum permitted exponent value for strtod; exponents larger than MAX_ABS_EXP in absolute value get truncated to +-MAX_ABS_EXP. MAX_ABS_EXP should fit into an int. */ #ifndef MAX_ABS_EXP #define MAX_ABS_EXP 1100000000U #endif /* Bound on length of pieces of input strings in _Py_dg_strtod; specifically, this is used to bound the total number of digits ignoring leading zeros and the number of digits that follow the decimal point. Ideally, MAX_DIGITS should satisfy MAX_DIGITS + 400 < MAX_ABS_EXP; that ensures that the exponent clipping in _Py_dg_strtod can't affect the value of the output. */ #ifndef MAX_DIGITS #define MAX_DIGITS 1000000000U #endif /* Guard against trying to use the above values on unusual platforms with ints * of width less than 32 bits. */ #if MAX_ABS_EXP > INT_MAX #error "MAX_ABS_EXP should fit in an int" #endif #if MAX_DIGITS > INT_MAX #error "MAX_DIGITS should fit in an int" #endif /* The following definition of Storeinc is appropriate for MIPS processors. * An alternative that might be better on some machines is * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) */ #if defined(IEEE_8087) #define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ ((unsigned short *)a)[0] = (unsigned short)c, a++) #else #define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ ((unsigned short *)a)[1] = (unsigned short)c, a++) #endif /* #define P DBL_MANT_DIG */ /* Ten_pmax = floor(P*log(2)/log(5)) */ /* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ /* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ /* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ #define Exp_shift 20 #define Exp_shift1 20 #define Exp_msk1 0x100000 #define Exp_msk11 0x100000 #define Exp_mask 0x7ff00000 #define P 53 #define Nbits 53 #define Bias 1023 #define Emax 1023 #define Emin (-1022) #define Etiny (-1074) /* smallest denormal is 2**Etiny */ #define Exp_1 0x3ff00000 #define Exp_11 0x3ff00000 #define Ebits 11 #define Frac_mask 0xfffff #define Frac_mask1 0xfffff #define Ten_pmax 22 #define Bletch 0x10 #define Bndry_mask 0xfffff #define Bndry_mask1 0xfffff #define Sign_bit 0x80000000 #define Log2P 1 #define Tiny0 0 #define Tiny1 1 #define Quick_max 14 #define Int_max 14 #ifndef Flt_Rounds #ifdef FLT_ROUNDS #define Flt_Rounds FLT_ROUNDS #else #define Flt_Rounds 1 #endif #endif /*Flt_Rounds*/ #define Rounding Flt_Rounds #define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) #define Big1 0xffffffff /* Bits of the representation of positive infinity. */ #define POSINF_WORD0 0x7ff00000 #define POSINF_WORD1 0 /* struct BCinfo is used to pass information from _Py_dg_strtod to bigcomp */ typedef struct BCinfo BCinfo; struct BCinfo { int e0, nd, nd0, scale; }; #define FFFFFFFF 0xffffffffUL /* struct Bigint is used to represent arbitrary-precision integers. These integers are stored in sign-magnitude format, with the magnitude stored as an array of base 2**32 digits. Bigints are always normalized: if x is a Bigint then x->wds >= 1, and either x->wds == 1 or x[wds-1] is nonzero. The Bigint fields are as follows: - next is a header used by Balloc and Bfree to keep track of lists of freed Bigints; it's also used for the linked list of powers of 5 of the form 5**2**i used by pow5mult. - k indicates which pool this Bigint was allocated from - maxwds is the maximum number of words space was allocated for (usually maxwds == 2**k) - sign is 1 for negative Bigints, 0 for positive. The sign is unused (ignored on inputs, set to 0 on outputs) in almost all operations involving Bigints: a notable exception is the diff function, which ignores signs on inputs but sets the sign of the output correctly. - wds is the actual number of significant words - x contains the vector of words (digits) for this Bigint, from least significant (x[0]) to most significant (x[wds-1]). */ // struct Bigint is defined in pycore_dtoa.h. typedef struct Bigint Bigint; #ifndef Py_USING_MEMORY_DEBUGGER /* Memory management: memory is allocated from, and returned to, Kmax+1 pools of memory, where pool k (0 <= k <= Kmax) is for Bigints b with b->maxwds == 1 << k. These pools are maintained as linked lists, with freelist[k] pointing to the head of the list for pool k. On allocation, if there's no free slot in the appropriate pool, MALLOC is called to get more memory. This memory is not returned to the system until Python quits. There's also a private memory pool that's allocated from in preference to using MALLOC. For Bigints with more than (1 << Kmax) digits (which implies at least 1233 decimal digits), memory is directly allocated using MALLOC, and freed using FREE. XXX: it would be easy to bypass this memory-management system and translate each call to Balloc into a call to PyMem_Malloc, and each Bfree to PyMem_Free. Investigate whether this has any significant performance on impact. */ #define freelist interp->dtoa.freelist #define private_mem interp->dtoa.preallocated #define pmem_next interp->dtoa.preallocated_next /* Allocate space for a Bigint with up to 1<next; else { x = 1 << k; len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) /sizeof(double); if (k <= Bigint_Kmax && pmem_next - private_mem + len <= (Py_ssize_t)Bigint_PREALLOC_SIZE ) { rv = (Bigint*)pmem_next; pmem_next += len; } else { rv = (Bigint*)MALLOC(len*sizeof(double)); if (rv == NULL) return NULL; } rv->k = k; rv->maxwds = x; } rv->sign = rv->wds = 0; return rv; } /* Free a Bigint allocated with Balloc */ static void Bfree(Bigint *v) { if (v) { if (v->k > Bigint_Kmax) FREE((void*)v); else { PyInterpreterState *interp = _PyInterpreterState_GET(); v->next = freelist[v->k]; freelist[v->k] = v; } } } #undef pmem_next #undef private_mem #undef freelist #else /* Alternative versions of Balloc and Bfree that use PyMem_Malloc and PyMem_Free directly in place of the custom memory allocation scheme above. These are provided for the benefit of memory debugging tools like Valgrind. */ /* Allocate space for a Bigint with up to 1<k = k; rv->maxwds = x; rv->sign = rv->wds = 0; return rv; } /* Free a Bigint allocated with Balloc */ static void Bfree(Bigint *v) { if (v) { FREE((void*)v); } } #endif /* Py_USING_MEMORY_DEBUGGER */ #define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ y->wds*sizeof(Long) + 2*sizeof(int)) /* Multiply a Bigint b by m and add a. Either modifies b in place and returns a pointer to the modified b, or Bfrees b and returns a pointer to a copy. On failure, return NULL. In this case, b will have been already freed. */ static Bigint * multadd(Bigint *b, int m, int a) /* multiply by m and add a */ { int i, wds; ULong *x; ULLong carry, y; Bigint *b1; wds = b->wds; x = b->x; i = 0; carry = a; do { y = *x * (ULLong)m + carry; carry = y >> 32; *x++ = (ULong)(y & FFFFFFFF); } while(++i < wds); if (carry) { if (wds >= b->maxwds) { b1 = Balloc(b->k+1); if (b1 == NULL){ Bfree(b); return NULL; } Bcopy(b1, b); Bfree(b); b = b1; } b->x[wds++] = (ULong)carry; b->wds = wds; } return b; } /* convert a string s containing nd decimal digits (possibly containing a decimal separator at position nd0, which is ignored) to a Bigint. This function carries on where the parsing code in _Py_dg_strtod leaves off: on entry, y9 contains the result of converting the first 9 digits. Returns NULL on failure. */ static Bigint * s2b(const char *s, int nd0, int nd, ULong y9) { Bigint *b; int i, k; Long x, y; x = (nd + 8) / 9; for(k = 0, y = 1; x > y; y <<= 1, k++) ; b = Balloc(k); if (b == NULL) return NULL; b->x[0] = y9; b->wds = 1; if (nd <= 9) return b; s += 9; for (i = 9; i < nd0; i++) { b = multadd(b, 10, *s++ - '0'); if (b == NULL) return NULL; } s++; for(; i < nd; i++) { b = multadd(b, 10, *s++ - '0'); if (b == NULL) return NULL; } return b; } /* count leading 0 bits in the 32-bit integer x. */ static int hi0bits(ULong x) { int k = 0; if (!(x & 0xffff0000)) { k = 16; x <<= 16; } if (!(x & 0xff000000)) { k += 8; x <<= 8; } if (!(x & 0xf0000000)) { k += 4; x <<= 4; } if (!(x & 0xc0000000)) { k += 2; x <<= 2; } if (!(x & 0x80000000)) { k++; if (!(x & 0x40000000)) return 32; } return k; } /* count trailing 0 bits in the 32-bit integer y, and shift y right by that number of bits. */ static int lo0bits(ULong *y) { int k; ULong x = *y; if (x & 7) { if (x & 1) return 0; if (x & 2) { *y = x >> 1; return 1; } *y = x >> 2; return 2; } k = 0; if (!(x & 0xffff)) { k = 16; x >>= 16; } if (!(x & 0xff)) { k += 8; x >>= 8; } if (!(x & 0xf)) { k += 4; x >>= 4; } if (!(x & 0x3)) { k += 2; x >>= 2; } if (!(x & 1)) { k++; x >>= 1; if (!x) return 32; } *y = x; return k; } /* convert a small nonnegative integer to a Bigint */ static Bigint * i2b(int i) { Bigint *b; b = Balloc(1); if (b == NULL) return NULL; b->x[0] = i; b->wds = 1; return b; } /* multiply two Bigints. Returns a new Bigint, or NULL on failure. Ignores the signs of a and b. */ static Bigint * mult(Bigint *a, Bigint *b) { Bigint *c; int k, wa, wb, wc; ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; ULong y; ULLong carry, z; if ((!a->x[0] && a->wds == 1) || (!b->x[0] && b->wds == 1)) { c = Balloc(0); if (c == NULL) return NULL; c->wds = 1; c->x[0] = 0; return c; } if (a->wds < b->wds) { c = a; a = b; b = c; } k = a->k; wa = a->wds; wb = b->wds; wc = wa + wb; if (wc > a->maxwds) k++; c = Balloc(k); if (c == NULL) return NULL; for(x = c->x, xa = x + wc; x < xa; x++) *x = 0; xa = a->x; xae = xa + wa; xb = b->x; xbe = xb + wb; xc0 = c->x; for(; xb < xbe; xc0++) { if ((y = *xb++)) { x = xa; xc = xc0; carry = 0; do { z = *x++ * (ULLong)y + *xc + carry; carry = z >> 32; *xc++ = (ULong)(z & FFFFFFFF); } while(x < xae); *xc = (ULong)carry; } } for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; c->wds = wc; return c; } #ifndef Py_USING_MEMORY_DEBUGGER /* multiply the Bigint b by 5**k. Returns a pointer to the result, or NULL on failure; if the returned pointer is distinct from b then the original Bigint b will have been Bfree'd. Ignores the sign of b. */ static Bigint * pow5mult(Bigint *b, int k) { Bigint *b1, *p5, *p51; int i; static const int p05[3] = { 5, 25, 125 }; if ((i = k & 3)) { b = multadd(b, p05[i-1], 0); if (b == NULL) return NULL; } if (!(k >>= 2)) return b; PyInterpreterState *interp = _PyInterpreterState_GET(); p5 = interp->dtoa.p5s; if (!p5) { /* first time */ p5 = i2b(625); if (p5 == NULL) { Bfree(b); return NULL; } interp->dtoa.p5s = p5; p5->next = 0; } for(;;) { if (k & 1) { b1 = mult(b, p5); Bfree(b); b = b1; if (b == NULL) return NULL; } if (!(k >>= 1)) break; p51 = p5->next; if (!p51) { p51 = mult(p5,p5); if (p51 == NULL) { Bfree(b); return NULL; } p51->next = 0; p5->next = p51; } p5 = p51; } return b; } #else /* Version of pow5mult that doesn't cache powers of 5. Provided for the benefit of memory debugging tools like Valgrind. */ static Bigint * pow5mult(Bigint *b, int k) { Bigint *b1, *p5, *p51; int i; static const int p05[3] = { 5, 25, 125 }; if ((i = k & 3)) { b = multadd(b, p05[i-1], 0); if (b == NULL) return NULL; } if (!(k >>= 2)) return b; p5 = i2b(625); if (p5 == NULL) { Bfree(b); return NULL; } for(;;) { if (k & 1) { b1 = mult(b, p5); Bfree(b); b = b1; if (b == NULL) { Bfree(p5); return NULL; } } if (!(k >>= 1)) break; p51 = mult(p5, p5); Bfree(p5); p5 = p51; if (p5 == NULL) { Bfree(b); return NULL; } } Bfree(p5); return b; } #endif /* Py_USING_MEMORY_DEBUGGER */ /* shift a Bigint b left by k bits. Return a pointer to the shifted result, or NULL on failure. If the returned pointer is distinct from b then the original b will have been Bfree'd. Ignores the sign of b. */ static Bigint * lshift(Bigint *b, int k) { int i, k1, n, n1; Bigint *b1; ULong *x, *x1, *xe, z; if (!k || (!b->x[0] && b->wds == 1)) return b; n = k >> 5; k1 = b->k; n1 = n + b->wds + 1; for(i = b->maxwds; n1 > i; i <<= 1) k1++; b1 = Balloc(k1); if (b1 == NULL) { Bfree(b); return NULL; } x1 = b1->x; for(i = 0; i < n; i++) *x1++ = 0; x = b->x; xe = x + b->wds; if (k &= 0x1f) { k1 = 32 - k; z = 0; do { *x1++ = *x << k | z; z = *x++ >> k1; } while(x < xe); if ((*x1 = z)) ++n1; } else do *x1++ = *x++; while(x < xe); b1->wds = n1 - 1; Bfree(b); return b1; } /* Do a three-way compare of a and b, returning -1 if a < b, 0 if a == b and 1 if a > b. Ignores signs of a and b. */ static int cmp(Bigint *a, Bigint *b) { ULong *xa, *xa0, *xb, *xb0; int i, j; i = a->wds; j = b->wds; #ifdef DEBUG if (i > 1 && !a->x[i-1]) Bug("cmp called with a->x[a->wds-1] == 0"); if (j > 1 && !b->x[j-1]) Bug("cmp called with b->x[b->wds-1] == 0"); #endif if (i -= j) return i; xa0 = a->x; xa = xa0 + j; xb0 = b->x; xb = xb0 + j; for(;;) { if (*--xa != *--xb) return *xa < *xb ? -1 : 1; if (xa <= xa0) break; } return 0; } /* Take the difference of Bigints a and b, returning a new Bigint. Returns NULL on failure. The signs of a and b are ignored, but the sign of the result is set appropriately. */ static Bigint * diff(Bigint *a, Bigint *b) { Bigint *c; int i, wa, wb; ULong *xa, *xae, *xb, *xbe, *xc; ULLong borrow, y; i = cmp(a,b); if (!i) { c = Balloc(0); if (c == NULL) return NULL; c->wds = 1; c->x[0] = 0; return c; } if (i < 0) { c = a; a = b; b = c; i = 1; } else i = 0; c = Balloc(a->k); if (c == NULL) return NULL; c->sign = i; wa = a->wds; xa = a->x; xae = xa + wa; wb = b->wds; xb = b->x; xbe = xb + wb; xc = c->x; borrow = 0; do { y = (ULLong)*xa++ - *xb++ - borrow; borrow = y >> 32 & (ULong)1; *xc++ = (ULong)(y & FFFFFFFF); } while(xb < xbe); while(xa < xae) { y = *xa++ - borrow; borrow = y >> 32 & (ULong)1; *xc++ = (ULong)(y & FFFFFFFF); } while(!*--xc) wa--; c->wds = wa; return c; } /* Given a positive normal double x, return the difference between x and the next double up. Doesn't give correct results for subnormals. */ static double ulp(U *x) { Long L; U u; L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; word0(&u) = L; word1(&u) = 0; return dval(&u); } /* Convert a Bigint to a double plus an exponent */ static double b2d(Bigint *a, int *e) { ULong *xa, *xa0, w, y, z; int k; U d; xa0 = a->x; xa = xa0 + a->wds; y = *--xa; #ifdef DEBUG if (!y) Bug("zero y in b2d"); #endif k = hi0bits(y); *e = 32 - k; if (k < Ebits) { word0(&d) = Exp_1 | y >> (Ebits - k); w = xa > xa0 ? *--xa : 0; word1(&d) = y << ((32-Ebits) + k) | w >> (Ebits - k); goto ret_d; } z = xa > xa0 ? *--xa : 0; if (k -= Ebits) { word0(&d) = Exp_1 | y << k | z >> (32 - k); y = xa > xa0 ? *--xa : 0; word1(&d) = z << k | y >> (32 - k); } else { word0(&d) = Exp_1 | y; word1(&d) = z; } ret_d: return dval(&d); } /* Convert a scaled double to a Bigint plus an exponent. Similar to d2b, except that it accepts the scale parameter used in _Py_dg_strtod (which should be either 0 or 2*P), and the normalization for the return value is different (see below). On input, d should be finite and nonnegative, and d / 2**scale should be exactly representable as an IEEE 754 double. Returns a Bigint b and an integer e such that dval(d) / 2**scale = b * 2**e. Unlike d2b, b is not necessarily odd: b and e are normalized so that either 2**(P-1) <= b < 2**P and e >= Etiny, or b < 2**P and e == Etiny. This applies equally to an input of 0.0: in that case the return values are b = 0 and e = Etiny. The above normalization ensures that for all possible inputs d, 2**e gives ulp(d/2**scale). Returns NULL on failure. */ static Bigint * sd2b(U *d, int scale, int *e) { Bigint *b; b = Balloc(1); if (b == NULL) return NULL; /* First construct b and e assuming that scale == 0. */ b->wds = 2; b->x[0] = word1(d); b->x[1] = word0(d) & Frac_mask; *e = Etiny - 1 + (int)((word0(d) & Exp_mask) >> Exp_shift); if (*e < Etiny) *e = Etiny; else b->x[1] |= Exp_msk1; /* Now adjust for scale, provided that b != 0. */ if (scale && (b->x[0] || b->x[1])) { *e -= scale; if (*e < Etiny) { scale = Etiny - *e; *e = Etiny; /* We can't shift more than P-1 bits without shifting out a 1. */ assert(0 < scale && scale <= P - 1); if (scale >= 32) { /* The bits shifted out should all be zero. */ assert(b->x[0] == 0); b->x[0] = b->x[1]; b->x[1] = 0; scale -= 32; } if (scale) { /* The bits shifted out should all be zero. */ assert(b->x[0] << (32 - scale) == 0); b->x[0] = (b->x[0] >> scale) | (b->x[1] << (32 - scale)); b->x[1] >>= scale; } } } /* Ensure b is normalized. */ if (!b->x[1]) b->wds = 1; return b; } /* Convert a double to a Bigint plus an exponent. Return NULL on failure. Given a finite nonzero double d, return an odd Bigint b and exponent *e such that fabs(d) = b * 2**e. On return, *bbits gives the number of significant bits of b; that is, 2**(*bbits-1) <= b < 2**(*bbits). If d is zero, then b == 0, *e == -1010, *bbits = 0. */ static Bigint * d2b(U *d, int *e, int *bits) { Bigint *b; int de, k; ULong *x, y, z; int i; b = Balloc(1); if (b == NULL) return NULL; x = b->x; z = word0(d) & Frac_mask; word0(d) &= 0x7fffffff; /* clear sign bit, which we ignore */ if ((de = (int)(word0(d) >> Exp_shift))) z |= Exp_msk1; if ((y = word1(d))) { if ((k = lo0bits(&y))) { x[0] = y | z << (32 - k); z >>= k; } else x[0] = y; i = b->wds = (x[1] = z) ? 2 : 1; } else { k = lo0bits(&z); x[0] = z; i = b->wds = 1; k += 32; } if (de) { *e = de - Bias - (P-1) + k; *bits = P - k; } else { *e = de - Bias - (P-1) + 1 + k; *bits = 32*i - hi0bits(x[i-1]); } return b; } /* Compute the ratio of two Bigints, as a double. The result may have an error of up to 2.5 ulps. */ static double ratio(Bigint *a, Bigint *b) { U da, db; int k, ka, kb; dval(&da) = b2d(a, &ka); dval(&db) = b2d(b, &kb); k = ka - kb + 32*(a->wds - b->wds); if (k > 0) word0(&da) += k*Exp_msk1; else { k = -k; word0(&db) += k*Exp_msk1; } return dval(&da) / dval(&db); } static const double tens[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22 }; static const double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 9007199254740992.*9007199254740992.e-256 /* = 2^106 * 1e-256 */ }; /* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ /* flag unnecessarily. It leads to a song and dance at the end of strtod. */ #define Scale_Bit 0x10 #define n_bigtens 5 #define ULbits 32 #define kshift 5 #define kmask 31 static int dshift(Bigint *b, int p2) { int rv = hi0bits(b->x[b->wds-1]) - 4; if (p2 > 0) rv -= p2; return rv & kmask; } /* special case of Bigint division. The quotient is always in the range 0 <= quotient < 10, and on entry the divisor S is normalized so that its top 4 bits (28--31) are zero and bit 27 is set. */ static int quorem(Bigint *b, Bigint *S) { int n; ULong *bx, *bxe, q, *sx, *sxe; ULLong borrow, carry, y, ys; n = S->wds; #ifdef DEBUG /*debug*/ if (b->wds > n) /*debug*/ Bug("oversize b in quorem"); #endif if (b->wds < n) return 0; sx = S->x; sxe = sx + --n; bx = b->x; bxe = bx + n; q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ #ifdef DEBUG /*debug*/ if (q > 9) /*debug*/ Bug("oversized quotient in quorem"); #endif if (q) { borrow = 0; carry = 0; do { ys = *sx++ * (ULLong)q + carry; carry = ys >> 32; y = *bx - (ys & FFFFFFFF) - borrow; borrow = y >> 32 & (ULong)1; *bx++ = (ULong)(y & FFFFFFFF); } while(sx <= sxe); if (!*bxe) { bx = b->x; while(--bxe > bx && !*bxe) --n; b->wds = n; } } if (cmp(b, S) >= 0) { q++; borrow = 0; carry = 0; bx = b->x; sx = S->x; do { ys = *sx++ + carry; carry = ys >> 32; y = *bx - (ys & FFFFFFFF) - borrow; borrow = y >> 32 & (ULong)1; *bx++ = (ULong)(y & FFFFFFFF); } while(sx <= sxe); bx = b->x; bxe = bx + n; if (!*bxe) { while(--bxe > bx && !*bxe) --n; b->wds = n; } } return q; } /* sulp(x) is a version of ulp(x) that takes bc.scale into account. Assuming that x is finite and nonnegative (positive zero is fine here) and x / 2^bc.scale is exactly representable as a double, sulp(x) is equivalent to 2^bc.scale * ulp(x / 2^bc.scale). */ static double sulp(U *x, BCinfo *bc) { U u; if (bc->scale && 2*P + 1 > (int)((word0(x) & Exp_mask) >> Exp_shift)) { /* rv/2^bc->scale is subnormal */ word0(&u) = (P+2)*Exp_msk1; word1(&u) = 0; return u.d; } else { assert(word0(x) || word1(x)); /* x != 0.0 */ return ulp(x); } } /* The bigcomp function handles some hard cases for strtod, for inputs with more than STRTOD_DIGLIM digits. It's called once an initial estimate for the double corresponding to the input string has already been obtained by the code in _Py_dg_strtod. The bigcomp function is only called after _Py_dg_strtod has found a double value rv such that either rv or rv + 1ulp represents the correctly rounded value corresponding to the original string. It determines which of these two values is the correct one by computing the decimal digits of rv + 0.5ulp and comparing them with the corresponding digits of s0. In the following, write dv for the absolute value of the number represented by the input string. Inputs: s0 points to the first significant digit of the input string. rv is a (possibly scaled) estimate for the closest double value to the value represented by the original input to _Py_dg_strtod. If bc->scale is nonzero, then rv/2^(bc->scale) is the approximation to the input value. bc is a struct containing information gathered during the parsing and estimation steps of _Py_dg_strtod. Description of fields follows: bc->e0 gives the exponent of the input value, such that dv = (integer given by the bd->nd digits of s0) * 10**e0 bc->nd gives the total number of significant digits of s0. It will be at least 1. bc->nd0 gives the number of significant digits of s0 before the decimal separator. If there's no decimal separator, bc->nd0 == bc->nd. bc->scale is the value used to scale rv to avoid doing arithmetic with subnormal values. It's either 0 or 2*P (=106). Outputs: On successful exit, rv/2^(bc->scale) is the closest double to dv. Returns 0 on success, -1 on failure (e.g., due to a failed malloc call). */ static int bigcomp(U *rv, const char *s0, BCinfo *bc) { Bigint *b, *d; int b2, d2, dd, i, nd, nd0, odd, p2, p5; nd = bc->nd; nd0 = bc->nd0; p5 = nd + bc->e0; b = sd2b(rv, bc->scale, &p2); if (b == NULL) return -1; /* record whether the lsb of rv/2^(bc->scale) is odd: in the exact halfway case, this is used for round to even. */ odd = b->x[0] & 1; /* left shift b by 1 bit and or a 1 into the least significant bit; this gives us b * 2**p2 = rv/2^(bc->scale) + 0.5 ulp. */ b = lshift(b, 1); if (b == NULL) return -1; b->x[0] |= 1; p2--; p2 -= p5; d = i2b(1); if (d == NULL) { Bfree(b); return -1; } /* Arrange for convenient computation of quotients: * shift left if necessary so divisor has 4 leading 0 bits. */ if (p5 > 0) { d = pow5mult(d, p5); if (d == NULL) { Bfree(b); return -1; } } else if (p5 < 0) { b = pow5mult(b, -p5); if (b == NULL) { Bfree(d); return -1; } } if (p2 > 0) { b2 = p2; d2 = 0; } else { b2 = 0; d2 = -p2; } i = dshift(d, d2); if ((b2 += i) > 0) { b = lshift(b, b2); if (b == NULL) { Bfree(d); return -1; } } if ((d2 += i) > 0) { d = lshift(d, d2); if (d == NULL) { Bfree(b); return -1; } } /* Compare s0 with b/d: set dd to -1, 0, or 1 according as s0 < b/d, s0 == * b/d, or s0 > b/d. Here the digits of s0 are thought of as representing * a number in the range [0.1, 1). */ if (cmp(b, d) >= 0) /* b/d >= 1 */ dd = -1; else { i = 0; for(;;) { b = multadd(b, 10, 0); if (b == NULL) { Bfree(d); return -1; } dd = s0[i < nd0 ? i : i+1] - '0' - quorem(b, d); i++; if (dd) break; if (!b->x[0] && b->wds == 1) { /* b/d == 0 */ dd = i < nd; break; } if (!(i < nd)) { /* b/d != 0, but digits of s0 exhausted */ dd = -1; break; } } } Bfree(b); Bfree(d); if (dd > 0 || (dd == 0 && odd)) dval(rv) += sulp(rv, bc); return 0; } double _Py_dg_strtod(const char *s00, char **se) { int bb2, bb5, bbe, bd2, bd5, bs2, c, dsign, e, e1, error; int esign, i, j, k, lz, nd, nd0, odd, sign; const char *s, *s0, *s1; double aadj, aadj1; U aadj2, adj, rv, rv0; ULong y, z, abs_exp; Long L; BCinfo bc; Bigint *bb = NULL, *bd = NULL, *bd0 = NULL, *bs = NULL, *delta = NULL; size_t ndigits, fraclen; double result; dval(&rv) = 0.; /* Start parsing. */ c = *(s = s00); /* Parse optional sign, if present. */ sign = 0; switch (c) { case '-': sign = 1; /* fall through */ case '+': c = *++s; } /* Skip leading zeros: lz is true iff there were leading zeros. */ s1 = s; while (c == '0') c = *++s; lz = s != s1; /* Point s0 at the first nonzero digit (if any). fraclen will be the number of digits between the decimal point and the end of the digit string. ndigits will be the total number of digits ignoring leading zeros. */ s0 = s1 = s; while ('0' <= c && c <= '9') c = *++s; ndigits = s - s1; fraclen = 0; /* Parse decimal point and following digits. */ if (c == '.') { c = *++s; if (!ndigits) { s1 = s; while (c == '0') c = *++s; lz = lz || s != s1; fraclen += (s - s1); s0 = s; } s1 = s; while ('0' <= c && c <= '9') c = *++s; ndigits += s - s1; fraclen += s - s1; } /* Now lz is true if and only if there were leading zero digits, and ndigits gives the total number of digits ignoring leading zeros. A valid input must have at least one digit. */ if (!ndigits && !lz) { if (se) *se = (char *)s00; goto parse_error; } /* Range check ndigits and fraclen to make sure that they, and values computed with them, can safely fit in an int. */ if (ndigits > MAX_DIGITS || fraclen > MAX_DIGITS) { if (se) *se = (char *)s00; goto parse_error; } nd = (int)ndigits; nd0 = (int)ndigits - (int)fraclen; /* Parse exponent. */ e = 0; if (c == 'e' || c == 'E') { s00 = s; c = *++s; /* Exponent sign. */ esign = 0; switch (c) { case '-': esign = 1; /* fall through */ case '+': c = *++s; } /* Skip zeros. lz is true iff there are leading zeros. */ s1 = s; while (c == '0') c = *++s; lz = s != s1; /* Get absolute value of the exponent. */ s1 = s; abs_exp = 0; while ('0' <= c && c <= '9') { abs_exp = 10*abs_exp + (c - '0'); c = *++s; } /* abs_exp will be correct modulo 2**32. But 10**9 < 2**32, so if there are at most 9 significant exponent digits then overflow is impossible. */ if (s - s1 > 9 || abs_exp > MAX_ABS_EXP) e = (int)MAX_ABS_EXP; else e = (int)abs_exp; if (esign) e = -e; /* A valid exponent must have at least one digit. */ if (s == s1 && !lz) s = s00; } /* Adjust exponent to take into account position of the point. */ e -= nd - nd0; if (nd0 <= 0) nd0 = nd; /* Finished parsing. Set se to indicate how far we parsed */ if (se) *se = (char *)s; /* If all digits were zero, exit with return value +-0.0. Otherwise, strip trailing zeros: scan back until we hit a nonzero digit. */ if (!nd) goto ret; for (i = nd; i > 0; ) { --i; if (s0[i < nd0 ? i : i+1] != '0') { ++i; break; } } e += nd - i; nd = i; if (nd0 > nd) nd0 = nd; /* Summary of parsing results. After parsing, and dealing with zero * inputs, we have values s0, nd0, nd, e, sign, where: * * - s0 points to the first significant digit of the input string * * - nd is the total number of significant digits (here, and * below, 'significant digits' means the set of digits of the * significand of the input that remain after ignoring leading * and trailing zeros). * * - nd0 indicates the position of the decimal point, if present; it * satisfies 1 <= nd0 <= nd. The nd significant digits are in * s0[0:nd0] and s0[nd0+1:nd+1] using the usual Python half-open slice * notation. (If nd0 < nd, then s0[nd0] contains a '.' character; if * nd0 == nd, then s0[nd0] could be any non-digit character.) * * - e is the adjusted exponent: the absolute value of the number * represented by the original input string is n * 10**e, where * n is the integer represented by the concatenation of * s0[0:nd0] and s0[nd0+1:nd+1] * * - sign gives the sign of the input: 1 for negative, 0 for positive * * - the first and last significant digits are nonzero */ /* put first DBL_DIG+1 digits into integer y and z. * * - y contains the value represented by the first min(9, nd) * significant digits * * - if nd > 9, z contains the value represented by significant digits * with indices in [9, min(16, nd)). So y * 10**(min(16, nd) - 9) + z * gives the value represented by the first min(16, nd) sig. digits. */ bc.e0 = e1 = e; y = z = 0; for (i = 0; i < nd; i++) { if (i < 9) y = 10*y + s0[i < nd0 ? i : i+1] - '0'; else if (i < DBL_DIG+1) z = 10*z + s0[i < nd0 ? i : i+1] - '0'; else break; } k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; dval(&rv) = y; if (k > 9) { dval(&rv) = tens[k - 9] * dval(&rv) + z; } if (nd <= DBL_DIG && Flt_Rounds == 1 ) { if (!e) goto ret; if (e > 0) { if (e <= Ten_pmax) { dval(&rv) *= tens[e]; goto ret; } i = DBL_DIG - nd; if (e <= Ten_pmax + i) { /* A fancier test would sometimes let us do * this for larger i values. */ e -= i; dval(&rv) *= tens[i]; dval(&rv) *= tens[e]; goto ret; } } else if (e >= -Ten_pmax) { dval(&rv) /= tens[-e]; goto ret; } } e1 += nd - k; bc.scale = 0; /* Get starting approximation = rv * 10**e1 */ if (e1 > 0) { if ((i = e1 & 15)) dval(&rv) *= tens[i]; if (e1 &= ~15) { if (e1 > DBL_MAX_10_EXP) goto ovfl; e1 >>= 4; for(j = 0; e1 > 1; j++, e1 >>= 1) if (e1 & 1) dval(&rv) *= bigtens[j]; /* The last multiplication could overflow. */ word0(&rv) -= P*Exp_msk1; dval(&rv) *= bigtens[j]; if ((z = word0(&rv) & Exp_mask) > Exp_msk1*(DBL_MAX_EXP+Bias-P)) goto ovfl; if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { /* set to largest number */ /* (Can't trust DBL_MAX) */ word0(&rv) = Big0; word1(&rv) = Big1; } else word0(&rv) += P*Exp_msk1; } } else if (e1 < 0) { /* The input decimal value lies in [10**e1, 10**(e1+16)). If e1 <= -512, underflow immediately. If e1 <= -256, set bc.scale to 2*P. So for input value < 1e-256, bc.scale is always set; for input value >= 1e-240, bc.scale is never set. For input values in [1e-256, 1e-240), bc.scale may or may not be set. */ e1 = -e1; if ((i = e1 & 15)) dval(&rv) /= tens[i]; if (e1 >>= 4) { if (e1 >= 1 << n_bigtens) goto undfl; if (e1 & Scale_Bit) bc.scale = 2*P; for(j = 0; e1 > 0; j++, e1 >>= 1) if (e1 & 1) dval(&rv) *= tinytens[j]; if (bc.scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask) >> Exp_shift)) > 0) { /* scaled rv is denormal; clear j low bits */ if (j >= 32) { word1(&rv) = 0; if (j >= 53) word0(&rv) = (P+2)*Exp_msk1; else word0(&rv) &= 0xffffffff << (j-32); } else word1(&rv) &= 0xffffffff << j; } if (!dval(&rv)) goto undfl; } } /* Now the hard part -- adjusting rv to the correct value.*/ /* Put digits into bd: true value = bd * 10^e */ bc.nd = nd; bc.nd0 = nd0; /* Only needed if nd > STRTOD_DIGLIM, but done here */ /* to silence an erroneous warning about bc.nd0 */ /* possibly not being initialized. */ if (nd > STRTOD_DIGLIM) { /* ASSERT(STRTOD_DIGLIM >= 18); 18 == one more than the */ /* minimum number of decimal digits to distinguish double values */ /* in IEEE arithmetic. */ /* Truncate input to 18 significant digits, then discard any trailing zeros on the result by updating nd, nd0, e and y suitably. (There's no need to update z; it's not reused beyond this point.) */ for (i = 18; i > 0; ) { /* scan back until we hit a nonzero digit. significant digit 'i' is s0[i] if i < nd0, s0[i+1] if i >= nd0. */ --i; if (s0[i < nd0 ? i : i+1] != '0') { ++i; break; } } e += nd - i; nd = i; if (nd0 > nd) nd0 = nd; if (nd < 9) { /* must recompute y */ y = 0; for(i = 0; i < nd0; ++i) y = 10*y + s0[i] - '0'; for(; i < nd; ++i) y = 10*y + s0[i+1] - '0'; } } bd0 = s2b(s0, nd0, nd, y); if (bd0 == NULL) goto failed_malloc; /* Notation for the comments below. Write: - dv for the absolute value of the number represented by the original decimal input string. - if we've truncated dv, write tdv for the truncated value. Otherwise, set tdv == dv. - srv for the quantity rv/2^bc.scale; so srv is the current binary approximation to tdv (and dv). It should be exactly representable in an IEEE 754 double. */ for(;;) { /* This is the main correction loop for _Py_dg_strtod. We've got a decimal value tdv, and a floating-point approximation srv=rv/2^bc.scale to tdv. The aim is to determine whether srv is close enough (i.e., within 0.5 ulps) to tdv, and to compute a new approximation if not. To determine whether srv is close enough to tdv, compute integers bd, bb and bs proportional to tdv, srv and 0.5 ulp(srv) respectively, and then use integer arithmetic to determine whether |tdv - srv| is less than, equal to, or greater than 0.5 ulp(srv). */ bd = Balloc(bd0->k); if (bd == NULL) { goto failed_malloc; } Bcopy(bd, bd0); bb = sd2b(&rv, bc.scale, &bbe); /* srv = bb * 2^bbe */ if (bb == NULL) { goto failed_malloc; } /* Record whether lsb of bb is odd, in case we need this for the round-to-even step later. */ odd = bb->x[0] & 1; /* tdv = bd * 10**e; srv = bb * 2**bbe */ bs = i2b(1); if (bs == NULL) { goto failed_malloc; } if (e >= 0) { bb2 = bb5 = 0; bd2 = bd5 = e; } else { bb2 = bb5 = -e; bd2 = bd5 = 0; } if (bbe >= 0) bb2 += bbe; else bd2 -= bbe; bs2 = bb2; bb2++; bd2++; /* At this stage bd5 - bb5 == e == bd2 - bb2 + bbe, bb2 - bs2 == 1, and bs == 1, so: tdv == bd * 10**e = bd * 2**(bbe - bb2 + bd2) * 5**(bd5 - bb5) srv == bb * 2**bbe = bb * 2**(bbe - bb2 + bb2) 0.5 ulp(srv) == 2**(bbe-1) = bs * 2**(bbe - bb2 + bs2) It follows that: M * tdv = bd * 2**bd2 * 5**bd5 M * srv = bb * 2**bb2 * 5**bb5 M * 0.5 ulp(srv) = bs * 2**bs2 * 5**bb5 for some constant M. (Actually, M == 2**(bb2 - bbe) * 5**bb5, but this fact is not needed below.) */ /* Remove factor of 2**i, where i = min(bb2, bd2, bs2). */ i = bb2 < bd2 ? bb2 : bd2; if (i > bs2) i = bs2; if (i > 0) { bb2 -= i; bd2 -= i; bs2 -= i; } /* Scale bb, bd, bs by the appropriate powers of 2 and 5. */ if (bb5 > 0) { bs = pow5mult(bs, bb5); if (bs == NULL) { goto failed_malloc; } Bigint *bb1 = mult(bs, bb); Bfree(bb); bb = bb1; if (bb == NULL) { goto failed_malloc; } } if (bb2 > 0) { bb = lshift(bb, bb2); if (bb == NULL) { goto failed_malloc; } } if (bd5 > 0) { bd = pow5mult(bd, bd5); if (bd == NULL) { goto failed_malloc; } } if (bd2 > 0) { bd = lshift(bd, bd2); if (bd == NULL) { goto failed_malloc; } } if (bs2 > 0) { bs = lshift(bs, bs2); if (bs == NULL) { goto failed_malloc; } } /* Now bd, bb and bs are scaled versions of tdv, srv and 0.5 ulp(srv), respectively. Compute the difference |tdv - srv|, and compare with 0.5 ulp(srv). */ delta = diff(bb, bd); if (delta == NULL) { goto failed_malloc; } dsign = delta->sign; delta->sign = 0; i = cmp(delta, bs); if (bc.nd > nd && i <= 0) { if (dsign) break; /* Must use bigcomp(). */ /* Here rv overestimates the truncated decimal value by at most 0.5 ulp(rv). Hence rv either overestimates the true decimal value by <= 0.5 ulp(rv), or underestimates it by some small amount (< 0.1 ulp(rv)); either way, rv is within 0.5 ulps of the true decimal value, so it's possible to exit. Exception: if scaled rv is a normal exact power of 2, but not DBL_MIN, then rv - 0.5 ulp(rv) takes us all the way down to the next double, so the correctly rounded result is either rv - 0.5 ulp(rv) or rv; in this case, use bigcomp to distinguish. */ if (!word1(&rv) && !(word0(&rv) & Bndry_mask)) { /* rv can't be 0, since it's an overestimate for some nonzero value. So rv is a normal power of 2. */ j = (int)(word0(&rv) & Exp_mask) >> Exp_shift; /* rv / 2^bc.scale = 2^(j - 1023 - bc.scale); use bigcomp if rv / 2^bc.scale >= 2^-1021. */ if (j - bc.scale >= 2) { dval(&rv) -= 0.5 * sulp(&rv, &bc); break; /* Use bigcomp. */ } } { bc.nd = nd; i = -1; /* Discarded digits make delta smaller. */ } } if (i < 0) { /* Error is less than half an ulp -- check for * special case of mantissa a power of two. */ if (dsign || word1(&rv) || word0(&rv) & Bndry_mask || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1 ) { break; } if (!delta->x[0] && delta->wds <= 1) { /* exact result */ break; } delta = lshift(delta,Log2P); if (delta == NULL) { goto failed_malloc; } if (cmp(delta, bs) > 0) goto drop_down; break; } if (i == 0) { /* exactly half-way between */ if (dsign) { if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 && word1(&rv) == ( (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : 0xffffffff)) { /*boundary case -- increment exponent*/ word0(&rv) = (word0(&rv) & Exp_mask) + Exp_msk1 ; word1(&rv) = 0; /* dsign = 0; */ break; } } else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { drop_down: /* boundary case -- decrement exponent */ if (bc.scale) { L = word0(&rv) & Exp_mask; if (L <= (2*P+1)*Exp_msk1) { if (L > (P+2)*Exp_msk1) /* round even ==> */ /* accept rv */ break; /* rv = smallest denormal */ if (bc.nd > nd) break; goto undfl; } } L = (word0(&rv) & Exp_mask) - Exp_msk1; word0(&rv) = L | Bndry_mask1; word1(&rv) = 0xffffffff; break; } if (!odd) break; if (dsign) dval(&rv) += sulp(&rv, &bc); else { dval(&rv) -= sulp(&rv, &bc); if (!dval(&rv)) { if (bc.nd >nd) break; goto undfl; } } /* dsign = 1 - dsign; */ break; } if ((aadj = ratio(delta, bs)) <= 2.) { if (dsign) aadj = aadj1 = 1.; else if (word1(&rv) || word0(&rv) & Bndry_mask) { if (word1(&rv) == Tiny1 && !word0(&rv)) { if (bc.nd >nd) break; goto undfl; } aadj = 1.; aadj1 = -1.; } else { /* special case -- power of FLT_RADIX to be */ /* rounded down... */ if (aadj < 2./FLT_RADIX) aadj = 1./FLT_RADIX; else aadj *= 0.5; aadj1 = -aadj; } } else { aadj *= 0.5; aadj1 = dsign ? aadj : -aadj; if (Flt_Rounds == 0) aadj1 += 0.5; } y = word0(&rv) & Exp_mask; /* Check for overflow */ if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { dval(&rv0) = dval(&rv); word0(&rv) -= P*Exp_msk1; adj.d = aadj1 * ulp(&rv); dval(&rv) += adj.d; if ((word0(&rv) & Exp_mask) >= Exp_msk1*(DBL_MAX_EXP+Bias-P)) { if (word0(&rv0) == Big0 && word1(&rv0) == Big1) { goto ovfl; } word0(&rv) = Big0; word1(&rv) = Big1; goto cont; } else word0(&rv) += P*Exp_msk1; } else { if (bc.scale && y <= 2*P*Exp_msk1) { if (aadj <= 0x7fffffff) { if ((z = (ULong)aadj) <= 0) z = 1; aadj = z; aadj1 = dsign ? aadj : -aadj; } dval(&aadj2) = aadj1; word0(&aadj2) += (2*P+1)*Exp_msk1 - y; aadj1 = dval(&aadj2); } adj.d = aadj1 * ulp(&rv); dval(&rv) += adj.d; } z = word0(&rv) & Exp_mask; if (bc.nd == nd) { if (!bc.scale) if (y == z) { /* Can we stop now? */ L = (Long)aadj; aadj -= L; /* The tolerances below are conservative. */ if (dsign || word1(&rv) || word0(&rv) & Bndry_mask) { if (aadj < .4999999 || aadj > .5000001) break; } else if (aadj < .4999999/FLT_RADIX) break; } } cont: Bfree(bb); bb = NULL; Bfree(bd); bd = NULL; Bfree(bs); bs = NULL; Bfree(delta); delta = NULL; } if (bc.nd > nd) { error = bigcomp(&rv, s0, &bc); if (error) goto failed_malloc; } if (bc.scale) { word0(&rv0) = Exp_1 - 2*P*Exp_msk1; word1(&rv0) = 0; dval(&rv) *= dval(&rv0); } ret: result = sign ? -dval(&rv) : dval(&rv); goto done; parse_error: result = 0.0; goto done; failed_malloc: errno = ENOMEM; result = -1.0; goto done; undfl: result = sign ? -0.0 : 0.0; goto done; ovfl: errno = ERANGE; /* Can't trust HUGE_VAL */ word0(&rv) = Exp_mask; word1(&rv) = 0; result = sign ? -dval(&rv) : dval(&rv); goto done; done: Bfree(bb); Bfree(bd); Bfree(bs); Bfree(bd0); Bfree(delta); return result; } static char * rv_alloc(int i) { int j, k, *r; j = sizeof(ULong); for(k = 0; sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (unsigned)i; j <<= 1) k++; r = (int*)Balloc(k); if (r == NULL) return NULL; *r = k; return (char *)(r+1); } static char * nrv_alloc(const char *s, char **rve, int n) { char *rv, *t; rv = rv_alloc(n); if (rv == NULL) return NULL; t = rv; while((*t = *s++)) t++; if (rve) *rve = t; return rv; } /* freedtoa(s) must be used to free values s returned by dtoa * when MULTIPLE_THREADS is #defined. It should be used in all cases, * but for consistency with earlier versions of dtoa, it is optional * when MULTIPLE_THREADS is not defined. */ void _Py_dg_freedtoa(char *s) { Bigint *b = (Bigint *)((int *)s - 1); b->maxwds = 1 << (b->k = *(int*)b); Bfree(b); } /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. * * Inspired by "How to Print Floating-Point Numbers Accurately" by * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. * * Modifications: * 1. Rather than iterating, we use a simple numeric overestimate * to determine k = floor(log10(d)). We scale relevant * quantities using O(log2(k)) rather than O(k) multiplications. * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't * try to generate digits strictly left to right. Instead, we * compute with fewer bits and propagate the carry if necessary * when rounding the final digit up. This is often faster. * 3. Under the assumption that input will be rounded nearest, * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. * That is, we allow equality in stopping tests when the * round-nearest rule will give the same floating-point value * as would satisfaction of the stopping test with strict * inequality. * 4. We remove common factors of powers of 2 from relevant * quantities. * 5. When converting floating-point integers less than 1e16, * we use floating-point arithmetic rather than resorting * to multiple-precision integers. * 6. When asked to produce fewer than 15 digits, we first try * to get by with floating-point arithmetic; we resort to * multiple-precision integer arithmetic only if we cannot * guarantee that the floating-point calculation has given * the correctly rounded result. For k requested digits and * "uniformly" distributed input, the probability is * something like 10^(k-15) that we must resort to the Long * calculation. */ /* Additional notes (METD): (1) returns NULL on failure. (2) to avoid memory leakage, a successful call to _Py_dg_dtoa should always be matched by a call to _Py_dg_freedtoa. */ char * _Py_dg_dtoa(double dd, int mode, int ndigits, int *decpt, int *sign, char **rve) { /* Arguments ndigits, decpt, sign are similar to those of ecvt and fcvt; trailing zeros are suppressed from the returned string. If not null, *rve is set to point to the end of the return value. If d is +-Infinity or NaN, then *decpt is set to 9999. mode: 0 ==> shortest string that yields d when read in and rounded to nearest. 1 ==> like 0, but with Steele & White stopping rule; e.g. with IEEE P754 arithmetic , mode 0 gives 1e23 whereas mode 1 gives 9.999999999999999e22. 2 ==> max(1,ndigits) significant digits. This gives a return value similar to that of ecvt, except that trailing zeros are suppressed. 3 ==> through ndigits past the decimal point. This gives a return value similar to that from fcvt, except that trailing zeros are suppressed, and ndigits can be negative. 4,5 ==> similar to 2 and 3, respectively, but (in round-nearest mode) with the tests of mode 0 to possibly return a shorter string that rounds to d. With IEEE arithmetic and compilation with -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same as modes 2 and 3 when FLT_ROUNDS != 1. 6-9 ==> Debugging modes similar to mode - 4: don't try fast floating-point estimate (if applicable). Values of mode other than 0-9 are treated as mode 0. Sufficient space is allocated to the return value to hold the suppressed trailing zeros. */ int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, spec_case, try_quick; Long L; int denorm; ULong x; Bigint *b, *b1, *delta, *mlo, *mhi, *S; U d2, eps, u; double ds; char *s, *s0; /* set pointers to NULL, to silence gcc compiler warnings and make cleanup easier on error */ mlo = mhi = S = 0; s0 = 0; u.d = dd; if (word0(&u) & Sign_bit) { /* set sign for everything, including 0's and NaNs */ *sign = 1; word0(&u) &= ~Sign_bit; /* clear sign bit */ } else *sign = 0; /* quick return for Infinities, NaNs and zeros */ if ((word0(&u) & Exp_mask) == Exp_mask) { /* Infinity or NaN */ *decpt = 9999; if (!word1(&u) && !(word0(&u) & 0xfffff)) return nrv_alloc("Infinity", rve, 8); return nrv_alloc("NaN", rve, 3); } if (!dval(&u)) { *decpt = 1; return nrv_alloc("0", rve, 1); } /* compute k = floor(log10(d)). The computation may leave k one too large, but should never leave k too small. */ b = d2b(&u, &be, &bbits); if (b == NULL) goto failed_malloc; if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) { dval(&d2) = dval(&u); word0(&d2) &= Frac_mask1; word0(&d2) |= Exp_11; /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 * log10(x) = log(x) / log(10) * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) * * This suggests computing an approximation k to log10(d) by * * k = (i - Bias)*0.301029995663981 * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); * * We want k to be too large rather than too small. * The error in the first-order Taylor series approximation * is in our favor, so we just round up the constant enough * to compensate for any error in the multiplication of * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, * adding 1e-13 to the constant term more than suffices. * Hence we adjust the constant term to 0.1760912590558. * (We could get a more accurate k by invoking log10, * but this is probably not worthwhile.) */ i -= Bias; denorm = 0; } else { /* d is denormalized */ i = bbits + be + (Bias + (P-1) - 1); x = i > 32 ? word0(&u) << (64 - i) | word1(&u) >> (i - 32) : word1(&u) << (32 - i); dval(&d2) = x; word0(&d2) -= 31*Exp_msk1; /* adjust exponent */ i -= (Bias + (P-1) - 1) + 1; denorm = 1; } ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; k = (int)ds; if (ds < 0. && ds != k) k--; /* want k = floor(ds) */ k_check = 1; if (k >= 0 && k <= Ten_pmax) { if (dval(&u) < tens[k]) k--; k_check = 0; } j = bbits - i - 1; if (j >= 0) { b2 = 0; s2 = j; } else { b2 = -j; s2 = 0; } if (k >= 0) { b5 = 0; s5 = k; s2 += k; } else { b2 -= k; b5 = -k; s5 = 0; } if (mode < 0 || mode > 9) mode = 0; try_quick = 1; if (mode > 5) { mode -= 4; try_quick = 0; } leftright = 1; ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */ /* silence erroneous "gcc -Wall" warning. */ switch(mode) { case 0: case 1: i = 18; ndigits = 0; break; case 2: leftright = 0; /* fall through */ case 4: if (ndigits <= 0) ndigits = 1; ilim = ilim1 = i = ndigits; break; case 3: leftright = 0; /* fall through */ case 5: i = ndigits + k + 1; ilim = i; ilim1 = i - 1; if (i <= 0) i = 1; } s0 = rv_alloc(i); if (s0 == NULL) goto failed_malloc; s = s0; if (ilim >= 0 && ilim <= Quick_max && try_quick) { /* Try to get by with floating-point arithmetic. */ i = 0; dval(&d2) = dval(&u); k0 = k; ilim0 = ilim; ieps = 2; /* conservative */ if (k > 0) { ds = tens[k&0xf]; j = k >> 4; if (j & Bletch) { /* prevent overflows */ j &= Bletch - 1; dval(&u) /= bigtens[n_bigtens-1]; ieps++; } for(; j; j >>= 1, i++) if (j & 1) { ieps++; ds *= bigtens[i]; } dval(&u) /= ds; } else if ((j1 = -k)) { dval(&u) *= tens[j1 & 0xf]; for(j = j1 >> 4; j; j >>= 1, i++) if (j & 1) { ieps++; dval(&u) *= bigtens[i]; } } if (k_check && dval(&u) < 1. && ilim > 0) { if (ilim1 <= 0) goto fast_failed; ilim = ilim1; k--; dval(&u) *= 10.; ieps++; } dval(&eps) = ieps*dval(&u) + 7.; word0(&eps) -= (P-1)*Exp_msk1; if (ilim == 0) { S = mhi = 0; dval(&u) -= 5.; if (dval(&u) > dval(&eps)) goto one_digit; if (dval(&u) < -dval(&eps)) goto no_digits; goto fast_failed; } if (leftright) { /* Use Steele & White method of only * generating digits needed. */ dval(&eps) = 0.5/tens[ilim-1] - dval(&eps); for(i = 0;;) { L = (Long)dval(&u); dval(&u) -= L; *s++ = '0' + (int)L; if (dval(&u) < dval(&eps)) goto ret1; if (1. - dval(&u) < dval(&eps)) goto bump_up; if (++i >= ilim) break; dval(&eps) *= 10.; dval(&u) *= 10.; } } else { /* Generate ilim digits, then fix them up. */ dval(&eps) *= tens[ilim-1]; for(i = 1;; i++, dval(&u) *= 10.) { L = (Long)(dval(&u)); if (!(dval(&u) -= L)) ilim = i; *s++ = '0' + (int)L; if (i == ilim) { if (dval(&u) > 0.5 + dval(&eps)) goto bump_up; else if (dval(&u) < 0.5 - dval(&eps)) { while(*--s == '0'); s++; goto ret1; } break; } } } fast_failed: s = s0; dval(&u) = dval(&d2); k = k0; ilim = ilim0; } /* Do we have a "small" integer? */ if (be >= 0 && k <= Int_max) { /* Yes. */ ds = tens[k]; if (ndigits < 0 && ilim <= 0) { S = mhi = 0; if (ilim < 0 || dval(&u) <= 5*ds) goto no_digits; goto one_digit; } for(i = 1;; i++, dval(&u) *= 10.) { L = (Long)(dval(&u) / ds); dval(&u) -= L*ds; *s++ = '0' + (int)L; if (!dval(&u)) { break; } if (i == ilim) { dval(&u) += dval(&u); if (dval(&u) > ds || (dval(&u) == ds && L & 1)) { bump_up: while(*--s == '9') if (s == s0) { k++; *s = '0'; break; } ++*s++; } else { /* Strip trailing zeros. This branch was missing from the original dtoa.c, leading to surplus trailing zeros in some cases. See bugs.python.org/issue40780. */ while (s > s0 && s[-1] == '0') { --s; } } break; } } goto ret1; } m2 = b2; m5 = b5; if (leftright) { i = denorm ? be + (Bias + (P-1) - 1 + 1) : 1 + P - bbits; b2 += i; s2 += i; mhi = i2b(1); if (mhi == NULL) goto failed_malloc; } if (m2 > 0 && s2 > 0) { i = m2 < s2 ? m2 : s2; b2 -= i; m2 -= i; s2 -= i; } if (b5 > 0) { if (leftright) { if (m5 > 0) { mhi = pow5mult(mhi, m5); if (mhi == NULL) goto failed_malloc; b1 = mult(mhi, b); Bfree(b); b = b1; if (b == NULL) goto failed_malloc; } if ((j = b5 - m5)) { b = pow5mult(b, j); if (b == NULL) goto failed_malloc; } } else { b = pow5mult(b, b5); if (b == NULL) goto failed_malloc; } } S = i2b(1); if (S == NULL) goto failed_malloc; if (s5 > 0) { S = pow5mult(S, s5); if (S == NULL) goto failed_malloc; } /* Check for special case that d is a normalized power of 2. */ spec_case = 0; if ((mode < 2 || leftright) ) { if (!word1(&u) && !(word0(&u) & Bndry_mask) && word0(&u) & (Exp_mask & ~Exp_msk1) ) { /* The special case */ b2 += Log2P; s2 += Log2P; spec_case = 1; } } /* Arrange for convenient computation of quotients: * shift left if necessary so divisor has 4 leading 0 bits. * * Perhaps we should just compute leading 28 bits of S once * and for all and pass them and a shift to quorem, so it * can do shifts and ors to compute the numerator for q. */ #define iInc 28 i = dshift(S, s2); b2 += i; m2 += i; s2 += i; if (b2 > 0) { b = lshift(b, b2); if (b == NULL) goto failed_malloc; } if (s2 > 0) { S = lshift(S, s2); if (S == NULL) goto failed_malloc; } if (k_check) { if (cmp(b,S) < 0) { k--; b = multadd(b, 10, 0); /* we botched the k estimate */ if (b == NULL) goto failed_malloc; if (leftright) { mhi = multadd(mhi, 10, 0); if (mhi == NULL) goto failed_malloc; } ilim = ilim1; } } if (ilim <= 0 && (mode == 3 || mode == 5)) { if (ilim < 0) { /* no digits, fcvt style */ no_digits: k = -1 - ndigits; goto ret; } else { S = multadd(S, 5, 0); if (S == NULL) goto failed_malloc; if (cmp(b, S) <= 0) goto no_digits; } one_digit: *s++ = '1'; k++; goto ret; } if (leftright) { if (m2 > 0) { mhi = lshift(mhi, m2); if (mhi == NULL) goto failed_malloc; } /* Compute mlo -- check for special case * that d is a normalized power of 2. */ mlo = mhi; if (spec_case) { mhi = Balloc(mhi->k); if (mhi == NULL) goto failed_malloc; Bcopy(mhi, mlo); mhi = lshift(mhi, Log2P); if (mhi == NULL) goto failed_malloc; } for(i = 1;;i++) { dig = quorem(b,S) + '0'; /* Do we yet have the shortest decimal string * that will round to d? */ j = cmp(b, mlo); delta = diff(S, mhi); if (delta == NULL) goto failed_malloc; j1 = delta->sign ? 1 : cmp(b, delta); Bfree(delta); if (j1 == 0 && mode != 1 && !(word1(&u) & 1) ) { if (dig == '9') goto round_9_up; if (j > 0) dig++; *s++ = dig; goto ret; } if (j < 0 || (j == 0 && mode != 1 && !(word1(&u) & 1) )) { if (!b->x[0] && b->wds <= 1) { goto accept_dig; } if (j1 > 0) { b = lshift(b, 1); if (b == NULL) goto failed_malloc; j1 = cmp(b, S); if ((j1 > 0 || (j1 == 0 && dig & 1)) && dig++ == '9') goto round_9_up; } accept_dig: *s++ = dig; goto ret; } if (j1 > 0) { if (dig == '9') { /* possible if i == 1 */ round_9_up: *s++ = '9'; goto roundoff; } *s++ = dig + 1; goto ret; } *s++ = dig; if (i == ilim) break; b = multadd(b, 10, 0); if (b == NULL) goto failed_malloc; if (mlo == mhi) { mlo = mhi = multadd(mhi, 10, 0); if (mlo == NULL) goto failed_malloc; } else { mlo = multadd(mlo, 10, 0); if (mlo == NULL) goto failed_malloc; mhi = multadd(mhi, 10, 0); if (mhi == NULL) goto failed_malloc; } } } else for(i = 1;; i++) { *s++ = dig = quorem(b,S) + '0'; if (!b->x[0] && b->wds <= 1) { goto ret; } if (i >= ilim) break; b = multadd(b, 10, 0); if (b == NULL) goto failed_malloc; } /* Round off last digit */ b = lshift(b, 1); if (b == NULL) goto failed_malloc; j = cmp(b, S); if (j > 0 || (j == 0 && dig & 1)) { roundoff: while(*--s == '9') if (s == s0) { k++; *s++ = '1'; goto ret; } ++*s++; } else { while(*--s == '0'); s++; } ret: Bfree(S); if (mhi) { if (mlo && mlo != mhi) Bfree(mlo); Bfree(mhi); } ret1: Bfree(b); *s = 0; *decpt = k + 1; if (rve) *rve = s; return s0; failed_malloc: if (S) Bfree(S); if (mlo && mlo != mhi) Bfree(mlo); if (mhi) Bfree(mhi); if (b) Bfree(b); if (s0) _Py_dg_freedtoa(s0); return NULL; } #ifdef __cplusplus } #endif #endif // _PY_SHORT_FLOAT_REPR == 1 ================================================ FILE: Dup2.c ================================================ #include #include #include #define BADEXIT -1 int dup2(int fd1, int fd2) { if (fd1 != fd2) { #ifdef F_DUPFD if (fcntl(fd1, F_GETFL) < 0) return BADEXIT; if (fcntl(fd2, F_GETFL) >= 0) close(fd2); if (fcntl(fd1, F_DUPFD, fd2) < 0) return BADEXIT; #else errno = ENOTSUP; return BADEXIT; #endif } return fd2; } ================================================ FILE: Dynamic_Annotations.c ================================================ #ifdef _MSC_VER # include #endif #ifdef __cplusplus # error "This file should be built as pure C to avoid name mangling" #endif #include #include #include "dynamic_annotations.h" /* Each function is empty and called (via a macro) only in debug mode. The arguments are captured by dynamic tools at runtime. */ #if DYNAMIC_ANNOTATIONS_ENABLED == 1 void AnnotateRWLockCreate(const char *file, int line, const volatile void *lock){} void AnnotateRWLockDestroy(const char *file, int line, const volatile void *lock){} void AnnotateRWLockAcquired(const char *file, int line, const volatile void *lock, long is_w){} void AnnotateRWLockReleased(const char *file, int line, const volatile void *lock, long is_w){} void AnnotateBarrierInit(const char *file, int line, const volatile void *barrier, long count, long reinitialization_allowed) {} void AnnotateBarrierWaitBefore(const char *file, int line, const volatile void *barrier) {} void AnnotateBarrierWaitAfter(const char *file, int line, const volatile void *barrier) {} void AnnotateBarrierDestroy(const char *file, int line, const volatile void *barrier) {} void AnnotateCondVarWait(const char *file, int line, const volatile void *cv, const volatile void *lock){} void AnnotateCondVarSignal(const char *file, int line, const volatile void *cv){} void AnnotateCondVarSignalAll(const char *file, int line, const volatile void *cv){} void AnnotatePublishMemoryRange(const char *file, int line, const volatile void *address, long size){} void AnnotateUnpublishMemoryRange(const char *file, int line, const volatile void *address, long size){} void AnnotatePCQCreate(const char *file, int line, const volatile void *pcq){} void AnnotatePCQDestroy(const char *file, int line, const volatile void *pcq){} void AnnotatePCQPut(const char *file, int line, const volatile void *pcq){} void AnnotatePCQGet(const char *file, int line, const volatile void *pcq){} void AnnotateNewMemory(const char *file, int line, const volatile void *mem, long size){} void AnnotateExpectRace(const char *file, int line, const volatile void *mem, const char *description){} void AnnotateBenignRace(const char *file, int line, const volatile void *mem, const char *description){} void AnnotateBenignRaceSized(const char *file, int line, const volatile void *mem, long size, const char *description) {} void AnnotateMutexIsUsedAsCondVar(const char *file, int line, const volatile void *mu){} void AnnotateTraceMemory(const char *file, int line, const volatile void *arg){} void AnnotateThreadName(const char *file, int line, const char *name){} void AnnotateIgnoreReadsBegin(const char *file, int line){} void AnnotateIgnoreReadsEnd(const char *file, int line){} void AnnotateIgnoreWritesBegin(const char *file, int line){} void AnnotateIgnoreWritesEnd(const char *file, int line){} void AnnotateIgnoreSyncBegin(const char *file, int line){} void AnnotateIgnoreSyncEnd(const char *file, int line){} void AnnotateEnableRaceDetection(const char *file, int line, int enable){} void AnnotateNoOp(const char *file, int line, const volatile void *arg){} void AnnotateFlushState(const char *file, int line){} static int GetRunningOnValgrind(void) { #ifdef RUNNING_ON_VALGRIND if (RUNNING_ON_VALGRIND) return 1; #endif #ifndef _MSC_VER const char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND"); if (running_on_valgrind_str) { return strcmp(running_on_valgrind_str, "0") != 0; } #else /* Visual Studio issues warnings if we use getenv, * so we use GetEnvironmentVariableA instead. */ char value[100] = "1"; int res = GetEnvironmentVariableA("RUNNING_ON_VALGRIND", value, sizeof(value)); /* value will remain "1" if res == 0 or res >= sizeof(value). The latter * can happen only if the given value is long, in this case it can't be "0". */ if (res > 0 && !strcmp(value, "0")) return 1; #endif return 0; } /* See the comments in dynamic_annotations.h */ int RunningOnValgrind(void) { static volatile int running_on_valgrind = -1; /* C doesn't have thread-safe initialization of statics, and we don't want to depend on pthread_once here, so hack it. */ int local_running_on_valgrind = running_on_valgrind; if (local_running_on_valgrind == -1) running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind(); return local_running_on_valgrind; } #endif /* DYNAMIC_ANNOTATIONS_ENABLED == 1 */ ================================================ FILE: Dynload_Hpux.c ================================================ /* Support for dynamic loading of extension modules */ #include "dl.h" #include #include "Python.h" #include "importdl.h" #if defined(__hp9000s300) #define FUNCNAME_PATTERN "_%.20s_%.200s" #else #define FUNCNAME_PATTERN "%.20s_%.200s" #endif const char *_PyImport_DynLoadFiletab[] = {SHLIB_EXT, ".sl", NULL}; dl_funcptr _PyImport_FindSharedFuncptr(const char *prefix, const char *shortname, const char *pathname, FILE *fp) { int flags = BIND_FIRST | BIND_DEFERRED; int verbose = _Py_GetConfig()->verbose; if (verbose) { flags = BIND_FIRST | BIND_IMMEDIATE | BIND_NONFATAL | BIND_VERBOSE; printf("shl_load %s\n",pathname); } shl_t lib = shl_load(pathname, flags, 0); /* XXX Chuck Blake once wrote that 0 should be BIND_NOSTART? */ if (lib == NULL) { if (verbose) { perror(pathname); } char buf[256]; PyOS_snprintf(buf, sizeof(buf), "Failed to load %.200s", pathname); PyObject *buf_ob = PyUnicode_DecodeFSDefault(buf); if (buf_ob == NULL) return NULL; PyObject *shortname_ob = PyUnicode_FromString(shortname); if (shortname_ob == NULL) { Py_DECREF(buf_ob); return NULL; } PyObject *pathname_ob = PyUnicode_DecodeFSDefault(pathname); if (pathname_ob == NULL) { Py_DECREF(buf_ob); Py_DECREF(shortname_ob); return NULL; } PyErr_SetImportError(buf_ob, shortname_ob, pathname_ob); Py_DECREF(buf_ob); Py_DECREF(shortname_ob); Py_DECREF(pathname_ob); return NULL; } char funcname[258]; PyOS_snprintf(funcname, sizeof(funcname), FUNCNAME_PATTERN, prefix, shortname); if (verbose) { printf("shl_findsym %s\n", funcname); } dl_funcptr p; if (shl_findsym(&lib, funcname, TYPE_UNDEFINED, (void *) &p) == -1) { shl_unload(lib); p = NULL; } if (p == NULL && verbose) { perror(funcname); } return p; } ================================================ FILE: Dynload_Shlib.c ================================================ /* Support for dynamic loading of extension modules */ #include "Python.h" #include "pycore_interp.h" // _PyInterpreterState.dlopenflags #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "importdl.h" #include #include #if defined(__NetBSD__) #include #if (NetBSD < 199712) #include #include #define dlerror() "error in dynamic linking" #endif #endif /* NetBSD */ #ifdef HAVE_DLFCN_H #include #endif #if (defined(__OpenBSD__) || defined(__NetBSD__)) && !defined(__ELF__) #define LEAD_UNDERSCORE "_" #else #define LEAD_UNDERSCORE "" #endif /* The .so extension module ABI tag, supplied by the Makefile via Makefile.pre.in and configure. This is used to discriminate between incompatible .so files so that extensions for different Python builds can live in the same directory. E.g. foomodule.cpython-32.so */ const char *_PyImport_DynLoadFiletab[] = { #ifdef __CYGWIN__ ".dll", #else /* !__CYGWIN__ */ "." SOABI ".so", #ifdef ALT_SOABI "." ALT_SOABI ".so", #endif ".abi" PYTHON_ABI_STRING ".so", ".so", #endif /* __CYGWIN__ */ NULL, }; dl_funcptr _PyImport_FindSharedFuncptr(const char *prefix, const char *shortname, const char *pathname, FILE *fp) { dl_funcptr p; void *handle; char funcname[258]; char pathbuf[260]; int dlopenflags=0; if (strchr(pathname, '/') == NULL) { /* Prefix bare filename with "./" */ PyOS_snprintf(pathbuf, sizeof(pathbuf), "./%-.255s", pathname); pathname = pathbuf; } PyOS_snprintf(funcname, sizeof(funcname), LEAD_UNDERSCORE "%.20s_%.200s", prefix, shortname); if (fp != NULL) { struct _Py_stat_struct status; if (_Py_fstat(fileno(fp), &status) == -1) return NULL; } dlopenflags = _PyImport_GetDLOpenFlags(_PyInterpreterState_GET()); handle = dlopen(pathname, dlopenflags); if (handle == NULL) { PyObject *mod_name; PyObject *path; PyObject *error_ob; const char *error = dlerror(); if (error == NULL) error = "unknown dlopen() error"; error_ob = PyUnicode_DecodeLocale(error, "surrogateescape"); if (error_ob == NULL) return NULL; mod_name = PyUnicode_FromString(shortname); if (mod_name == NULL) { Py_DECREF(error_ob); return NULL; } path = PyUnicode_DecodeFSDefault(pathname); if (path == NULL) { Py_DECREF(error_ob); Py_DECREF(mod_name); return NULL; } PyErr_SetImportError(error_ob, mod_name, path); Py_DECREF(error_ob); Py_DECREF(mod_name); Py_DECREF(path); return NULL; } p = (dl_funcptr) dlsym(handle, funcname); return p; } ================================================ FILE: Dynload_Stub.c ================================================ /* This module provides the necessary stubs for when dynamic loading is not present. */ #include "Python.h" #include "importdl.h" const char *_PyImport_DynLoadFiletab[] = {NULL}; ================================================ FILE: Dynload_Win.c ================================================ /* Support for dynamic loading of extension modules */ #include "Python.h" #include "pycore_fileutils.h" // _Py_add_relfile() #include "pycore_pystate.h" // _PyInterpreterState_GET() #ifdef HAVE_DIRECT_H #include #endif #include #include "importdl.h" #include "patchlevel.h" #include #ifdef _DEBUG #define PYD_DEBUG_SUFFIX "_d" #else #define PYD_DEBUG_SUFFIX "" #endif #ifdef PYD_PLATFORM_TAG #define PYD_TAGGED_SUFFIX PYD_DEBUG_SUFFIX ".cp" Py_STRINGIFY(PY_MAJOR_VERSION) Py_STRINGIFY(PY_MINOR_VERSION) "-" PYD_PLATFORM_TAG ".pyd" #else #define PYD_TAGGED_SUFFIX PYD_DEBUG_SUFFIX ".cp" Py_STRINGIFY(PY_MAJOR_VERSION) Py_STRINGIFY(PY_MINOR_VERSION) ".pyd" #endif #define PYD_UNTAGGED_SUFFIX PYD_DEBUG_SUFFIX ".pyd" const char *_PyImport_DynLoadFiletab[] = { PYD_TAGGED_SUFFIX, PYD_UNTAGGED_SUFFIX, NULL }; /* Function to return the name of the "python" DLL that the supplied module directly imports. Looks through the list of imported modules and returns the first entry that starts with "python" (case sensitive) and is followed by nothing but numbers until the separator (period). Returns a pointer to the import name, or NULL if no matching name was located. This function parses through the PE header for the module as loaded in memory by the system loader. The PE header is accessed as documented by Microsoft in the MSDN PE and COFF specification (2/99), and handles both PE32 and PE32+. It only worries about the direct import table and not the delay load import table since it's unlikely an extension is going to be delay loading Python (after all, it's already loaded). If any magic values are not found (e.g., the PE header or optional header magic), then this function simply returns NULL. */ #define DWORD_AT(mem) (*(DWORD *)(mem)) #define WORD_AT(mem) (*(WORD *)(mem)) static char *GetPythonImport (HINSTANCE hModule) { unsigned char *dllbase, *import_data, *import_name; DWORD pe_offset, opt_offset; WORD opt_magic; int num_dict_off, import_off; /* Safety check input */ if (hModule == NULL) { return NULL; } /* Module instance is also the base load address. First portion of memory is the MS-DOS loader, which holds the offset to the PE header (from the load base) at 0x3C */ dllbase = (unsigned char *)hModule; pe_offset = DWORD_AT(dllbase + 0x3C); /* The PE signature must be "PE\0\0" */ if (memcmp(dllbase+pe_offset,"PE\0\0",4)) { return NULL; } /* Following the PE signature is the standard COFF header (20 bytes) and then the optional header. The optional header starts with a magic value of 0x10B for PE32 or 0x20B for PE32+ (PE32+ uses 64-bits for some fields). It might also be 0x107 for a ROM image, but we don't process that here. The optional header ends with a data dictionary that directly points to certain types of data, among them the import entries (in the second table entry). Based on the header type, we determine offsets for the data dictionary count and the entry within the dictionary pointing to the imports. */ opt_offset = pe_offset + 4 + 20; opt_magic = WORD_AT(dllbase+opt_offset); if (opt_magic == 0x10B) { /* PE32 */ num_dict_off = 92; import_off = 104; } else if (opt_magic == 0x20B) { /* PE32+ */ num_dict_off = 108; import_off = 120; } else { /* Unsupported */ return NULL; } /* Now if an import table exists, offset to it and walk the list of imports. The import table is an array (ending when an entry has empty values) of structures (20 bytes each), which contains (at offset 12) a relative address (to the module base) at which a string constant holding the import name is located. */ if (DWORD_AT(dllbase + opt_offset + num_dict_off) >= 2) { /* We have at least 2 tables - the import table is the second one. But still it may be that the table size is zero */ if (0 == DWORD_AT(dllbase + opt_offset + import_off + sizeof(DWORD))) return NULL; import_data = dllbase + DWORD_AT(dllbase + opt_offset + import_off); while (DWORD_AT(import_data)) { import_name = dllbase + DWORD_AT(import_data+12); if (strlen(import_name) >= 6 && !strncmp(import_name,"python",6)) { char *pch; /* Don't claim that python3.dll is a Python DLL. */ #ifdef _DEBUG if (strcmp(import_name, "python3_d.dll") == 0) { #else if (strcmp(import_name, "python3.dll") == 0) { #endif import_data += 20; continue; } /* Ensure python prefix is followed only by numbers to the end of the basename */ pch = import_name + 6; #ifdef _DEBUG while (*pch && pch[0] != '_' && pch[1] != 'd' && pch[2] != '.') { #else while (*pch && *pch != '.') { #endif if (*pch >= '0' && *pch <= '9') { pch++; } else { pch = NULL; break; } } if (pch) { /* Found it - return the name */ return import_name; } } import_data += 20; } } return NULL; } #ifdef Py_ENABLE_SHARED /* Load python3.dll before loading any extension module that might refer to it. That way, we can be sure that always the python3.dll corresponding to this python DLL is loaded, not a python3.dll that might be on the path by chance. Return whether the DLL was found. */ extern HMODULE PyWin_DLLhModule; static int _Py_CheckPython3(void) { static int python3_checked = 0; static HANDLE hPython3; #define MAXPATHLEN 512 wchar_t py3path[MAXPATHLEN+1]; if (python3_checked) { return hPython3 != NULL; } python3_checked = 1; /* If there is a python3.dll next to the python3y.dll, use that DLL */ if (PyWin_DLLhModule && GetModuleFileNameW(PyWin_DLLhModule, py3path, MAXPATHLEN)) { wchar_t *p = wcsrchr(py3path, L'\\'); if (p) { wcscpy(p + 1, PY3_DLLNAME); hPython3 = LoadLibraryExW(py3path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); if (hPython3 != NULL) { return 1; } } } /* If we can locate python3.dll in our application dir, use that DLL */ hPython3 = LoadLibraryExW(PY3_DLLNAME, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR); if (hPython3 != NULL) { return 1; } /* For back-compat, also search {sys.prefix}\DLLs, though that has not been a normal install layout for a while */ PyInterpreterState *interp = _PyInterpreterState_GET(); PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(interp); assert(config->prefix); if (config->prefix) { wcscpy_s(py3path, MAXPATHLEN, config->prefix); if (py3path[0] && _Py_add_relfile(py3path, L"DLLs\\" PY3_DLLNAME, MAXPATHLEN) >= 0) { hPython3 = LoadLibraryExW(py3path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); } } return hPython3 != NULL; #undef MAXPATHLEN } #endif /* Py_ENABLE_SHARED */ dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix, const char *shortname, PyObject *pathname, FILE *fp) { dl_funcptr p; char funcname[258], *import_python; #ifdef Py_ENABLE_SHARED _Py_CheckPython3(); #endif /* Py_ENABLE_SHARED */ wchar_t *wpathname = PyUnicode_AsWideCharString(pathname, NULL); if (wpathname == NULL) return NULL; PyOS_snprintf(funcname, sizeof(funcname), "%.20s_%.200s", prefix, shortname); { HINSTANCE hDLL = NULL; #ifdef MS_WINDOWS_DESKTOP unsigned int old_mode; /* Don't display a message box when Python can't load a DLL */ old_mode = SetErrorMode(SEM_FAILCRITICALERRORS); #endif /* bpo-36085: We use LoadLibraryEx with restricted search paths to avoid DLL preloading attacks and enable use of the AddDllDirectory function. We add SEARCH_DLL_LOAD_DIR to ensure DLLs adjacent to the PYD are preferred. */ Py_BEGIN_ALLOW_THREADS hDLL = LoadLibraryExW(wpathname, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); Py_END_ALLOW_THREADS PyMem_Free(wpathname); #ifdef MS_WINDOWS_DESKTOP /* restore old error mode settings */ SetErrorMode(old_mode); #endif if (hDLL==NULL){ PyObject *message; unsigned int errorCode; /* Get an error string from Win32 error code */ wchar_t theInfo[256]; /* Pointer to error text from system */ int theLength; /* Length of error text */ errorCode = GetLastError(); theLength = FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, /* flags */ NULL, /* message source */ errorCode, /* the message (error) ID */ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ theInfo, /* the buffer */ sizeof(theInfo) / sizeof(wchar_t), /* size in wchars */ NULL); /* no additional format args. */ /* Problem: could not get the error message. This should not happen if called correctly. */ if (theLength == 0) { message = PyUnicode_FromFormat( "DLL load failed with error code %u while importing %s", errorCode, shortname); } else { /* For some reason a \r\n is appended to the text */ if (theLength >= 2 && theInfo[theLength-2] == '\r' && theInfo[theLength-1] == '\n') { theLength -= 2; theInfo[theLength] = '\0'; } message = PyUnicode_FromFormat( "DLL load failed while importing %s: ", shortname); PyUnicode_AppendAndDel(&message, PyUnicode_FromWideChar( theInfo, theLength)); } if (message != NULL) { PyObject *shortname_obj = PyUnicode_FromString(shortname); PyErr_SetImportError(message, shortname_obj, pathname); Py_XDECREF(shortname_obj); Py_DECREF(message); } return NULL; } else { char buffer[256]; PyOS_snprintf(buffer, sizeof(buffer), #ifdef _DEBUG "python%d%d_d.dll", #else "python%d%d.dll", #endif PY_MAJOR_VERSION,PY_MINOR_VERSION); import_python = GetPythonImport(hDLL); if (import_python && _stricmp(buffer,import_python)) { PyErr_Format(PyExc_ImportError, "Module use of %.150s conflicts " "with this version of Python.", import_python); Py_BEGIN_ALLOW_THREADS FreeLibrary(hDLL); Py_END_ALLOW_THREADS return NULL; } } Py_BEGIN_ALLOW_THREADS p = GetProcAddress(hDLL, funcname); Py_END_ALLOW_THREADS } return p; } ================================================ FILE: Emscripten_Signal.c ================================================ // To enable signal handling, the embedder should: // 1. set Module.Py_EmscriptenSignalBuffer = some_shared_array_buffer; // 2. set the Py_EMSCRIPTEN_SIGNAL_HANDLING flag to 1 as follows: // Module.HEAP8[Module._Py_EMSCRIPTEN_SIGNAL_HANDLING] = 1 // // The address &Py_EMSCRIPTEN_SIGNAL_HANDLING is exported as // Module._Py_EMSCRIPTEN_SIGNAL_HANDLING. #include #include "Python.h" EM_JS(int, _Py_CheckEmscriptenSignals_Helper, (void), { if (!Module.Py_EmscriptenSignalBuffer) { return 0; } try { let result = Module.Py_EmscriptenSignalBuffer[0]; Module.Py_EmscriptenSignalBuffer[0] = 0; return result; } catch(e) { #if !defined(NDEBUG) console.warn("Error occurred while trying to read signal buffer:", e); #endif return 0; } }); EMSCRIPTEN_KEEPALIVE int Py_EMSCRIPTEN_SIGNAL_HANDLING = 0; void _Py_CheckEmscriptenSignals(void) { if (!Py_EMSCRIPTEN_SIGNAL_HANDLING) { return; } int signal = _Py_CheckEmscriptenSignals_Helper(); if (signal) { PyErr_SetInterruptEx(signal); } } #define PY_EMSCRIPTEN_SIGNAL_INTERVAL 50 static int emscripten_signal_clock = PY_EMSCRIPTEN_SIGNAL_INTERVAL; void _Py_CheckEmscriptenSignalsPeriodically(void) { if (!Py_EMSCRIPTEN_SIGNAL_HANDLING) { return; } emscripten_signal_clock--; if (emscripten_signal_clock == 0) { emscripten_signal_clock = PY_EMSCRIPTEN_SIGNAL_INTERVAL; _Py_CheckEmscriptenSignals(); } } ================================================ FILE: Errors.c ================================================ /* Error handling */ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_initconfig.h" // _PyStatus_ERR() #include "pycore_pyerrors.h" // _PyErr_Format() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() #include "pycore_sysmodule.h" // _PySys_Audit() #include "pycore_traceback.h" // _PyTraceBack_FromFrame() #include #ifdef MS_WINDOWS # include # include # include // _sys_nerr #endif #ifdef __cplusplus extern "C" { #endif /* Forward declarations */ static PyObject * _PyErr_FormatV(PyThreadState *tstate, PyObject *exception, const char *format, va_list vargs); void _PyErr_SetRaisedException(PyThreadState *tstate, PyObject *exc) { PyObject *old_exc = tstate->current_exception; tstate->current_exception = exc; Py_XDECREF(old_exc); } static PyObject* _PyErr_CreateException(PyObject *exception_type, PyObject *value) { PyObject *exc; if (value == NULL || value == Py_None) { exc = _PyObject_CallNoArgs(exception_type); } else if (PyTuple_Check(value)) { exc = PyObject_Call(exception_type, value, NULL); } else { exc = PyObject_CallOneArg(exception_type, value); } if (exc != NULL && !PyExceptionInstance_Check(exc)) { PyErr_Format(PyExc_TypeError, "calling %R should have returned an instance of " "BaseException, not %s", exception_type, Py_TYPE(exc)->tp_name); Py_CLEAR(exc); } return exc; } void _PyErr_Restore(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *traceback) { if (type == NULL) { assert(value == NULL); assert(traceback == NULL); _PyErr_SetRaisedException(tstate, NULL); return; } assert(PyExceptionClass_Check(type)); if (value != NULL && type == (PyObject *)Py_TYPE(value)) { /* Already normalized */ assert(((PyBaseExceptionObject *)value)->traceback != Py_None); } else { PyObject *exc = _PyErr_CreateException(type, value); Py_XDECREF(value); if (exc == NULL) { Py_DECREF(type); Py_XDECREF(traceback); return; } value = exc; } assert(PyExceptionInstance_Check(value)); if (traceback != NULL && !PyTraceBack_Check(traceback)) { if (traceback == Py_None) { Py_DECREF(Py_None); traceback = NULL; } else { PyErr_SetString(PyExc_TypeError, "traceback must be a Traceback or None"); Py_XDECREF(value); Py_DECREF(type); Py_XDECREF(traceback); return; } } PyObject *old_traceback = ((PyBaseExceptionObject *)value)->traceback; ((PyBaseExceptionObject *)value)->traceback = traceback; Py_XDECREF(old_traceback); _PyErr_SetRaisedException(tstate, value); Py_DECREF(type); } void PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback) { PyThreadState *tstate = _PyThreadState_GET(); _PyErr_Restore(tstate, type, value, traceback); } void PyErr_SetRaisedException(PyObject *exc) { PyThreadState *tstate = _PyThreadState_GET(); _PyErr_SetRaisedException(tstate, exc); } _PyErr_StackItem * _PyErr_GetTopmostException(PyThreadState *tstate) { _PyErr_StackItem *exc_info = tstate->exc_info; assert(exc_info); while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) && exc_info->previous_item != NULL) { exc_info = exc_info->previous_item; } return exc_info; } static PyObject * get_normalization_failure_note(PyThreadState *tstate, PyObject *exception, PyObject *value) { PyObject *args = PyObject_Repr(value); if (args == NULL) { _PyErr_Clear(tstate); args = PyUnicode_FromFormat(""); } PyObject *note; const char *tpname = ((PyTypeObject*)exception)->tp_name; if (args == NULL) { _PyErr_Clear(tstate); note = PyUnicode_FromFormat("Normalization failed: type=%s", tpname); } else { note = PyUnicode_FromFormat("Normalization failed: type=%s args=%S", tpname, args); Py_DECREF(args); } return note; } void _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value) { PyObject *exc_value; PyObject *tb = NULL; if (exception != NULL && !PyExceptionClass_Check(exception)) { _PyErr_Format(tstate, PyExc_SystemError, "_PyErr_SetObject: " "exception %R is not a BaseException subclass", exception); return; } /* Normalize the exception */ int is_subclass = 0; if (value != NULL && PyExceptionInstance_Check(value)) { is_subclass = PyObject_IsSubclass((PyObject *)Py_TYPE(value), exception); if (is_subclass < 0) { return; } } Py_XINCREF(value); if (!is_subclass) { /* We must normalize the value right now */ /* Issue #23571: functions must not be called with an exception set */ _PyErr_Clear(tstate); PyObject *fixed_value = _PyErr_CreateException(exception, value); if (fixed_value == NULL) { PyObject *exc = _PyErr_GetRaisedException(tstate); assert(PyExceptionInstance_Check(exc)); PyObject *note = get_normalization_failure_note(tstate, exception, value); Py_XDECREF(value); if (note != NULL) { /* ignore errors in _PyException_AddNote - they will be overwritten below */ _PyException_AddNote(exc, note); Py_DECREF(note); } _PyErr_SetRaisedException(tstate, exc); return; } Py_XSETREF(value, fixed_value); } exc_value = _PyErr_GetTopmostException(tstate)->exc_value; if (exc_value != NULL && exc_value != Py_None) { /* Implicit exception chaining */ Py_INCREF(exc_value); /* Avoid creating new reference cycles through the context chain, while taking care not to hang on pre-existing ones. This is O(chain length) but context chains are usually very short. Sensitive readers may try to inline the call to PyException_GetContext. */ if (exc_value != value) { PyObject *o = exc_value, *context; PyObject *slow_o = o; /* Floyd's cycle detection algo */ int slow_update_toggle = 0; while ((context = PyException_GetContext(o))) { Py_DECREF(context); if (context == value) { PyException_SetContext(o, NULL); break; } o = context; if (o == slow_o) { /* pre-existing cycle - all exceptions on the path were visited and checked. */ break; } if (slow_update_toggle) { slow_o = PyException_GetContext(slow_o); Py_DECREF(slow_o); } slow_update_toggle = !slow_update_toggle; } PyException_SetContext(value, exc_value); } else { Py_DECREF(exc_value); } } assert(value != NULL); if (PyExceptionInstance_Check(value)) tb = PyException_GetTraceback(value); _PyErr_Restore(tstate, Py_NewRef(Py_TYPE(value)), value, tb); } void PyErr_SetObject(PyObject *exception, PyObject *value) { PyThreadState *tstate = _PyThreadState_GET(); _PyErr_SetObject(tstate, exception, value); } /* Set a key error with the specified argument, wrapping it in a * tuple automatically so that tuple keys are not unpacked as the * exception arguments. */ void _PyErr_SetKeyError(PyObject *arg) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *tup = PyTuple_Pack(1, arg); if (!tup) { /* caller will expect error to be set anyway */ return; } _PyErr_SetObject(tstate, PyExc_KeyError, tup); Py_DECREF(tup); } void _PyErr_SetNone(PyThreadState *tstate, PyObject *exception) { _PyErr_SetObject(tstate, exception, (PyObject *)NULL); } void PyErr_SetNone(PyObject *exception) { PyThreadState *tstate = _PyThreadState_GET(); _PyErr_SetNone(tstate, exception); } void _PyErr_SetString(PyThreadState *tstate, PyObject *exception, const char *string) { PyObject *value = PyUnicode_FromString(string); _PyErr_SetObject(tstate, exception, value); Py_XDECREF(value); } void PyErr_SetString(PyObject *exception, const char *string) { PyThreadState *tstate = _PyThreadState_GET(); _PyErr_SetString(tstate, exception, string); } PyObject* _Py_HOT_FUNCTION PyErr_Occurred(void) { /* The caller must hold the GIL. */ assert(PyGILState_Check()); PyThreadState *tstate = _PyThreadState_GET(); return _PyErr_Occurred(tstate); } int PyErr_GivenExceptionMatches(PyObject *err, PyObject *exc) { if (err == NULL || exc == NULL) { /* maybe caused by "import exceptions" that failed early on */ return 0; } if (PyTuple_Check(exc)) { Py_ssize_t i, n; n = PyTuple_Size(exc); for (i = 0; i < n; i++) { /* Test recursively */ if (PyErr_GivenExceptionMatches( err, PyTuple_GET_ITEM(exc, i))) { return 1; } } return 0; } /* err might be an instance, so check its class. */ if (PyExceptionInstance_Check(err)) err = PyExceptionInstance_Class(err); if (PyExceptionClass_Check(err) && PyExceptionClass_Check(exc)) { return PyType_IsSubtype((PyTypeObject *)err, (PyTypeObject *)exc); } return err == exc; } int _PyErr_ExceptionMatches(PyThreadState *tstate, PyObject *exc) { return PyErr_GivenExceptionMatches(_PyErr_Occurred(tstate), exc); } int PyErr_ExceptionMatches(PyObject *exc) { PyThreadState *tstate = _PyThreadState_GET(); return _PyErr_ExceptionMatches(tstate, exc); } #ifndef Py_NORMALIZE_RECURSION_LIMIT #define Py_NORMALIZE_RECURSION_LIMIT 32 #endif /* Used in many places to normalize a raised exception, including in eval_code2(), do_raise(), and PyErr_Print() XXX: should PyErr_NormalizeException() also call PyException_SetTraceback() with the resulting value and tb? */ void _PyErr_NormalizeException(PyThreadState *tstate, PyObject **exc, PyObject **val, PyObject **tb) { int recursion_depth = 0; tstate->recursion_headroom++; PyObject *type, *value, *initial_tb; restart: type = *exc; if (type == NULL) { /* There was no exception, so nothing to do. */ tstate->recursion_headroom--; return; } value = *val; /* If PyErr_SetNone() was used, the value will have been actually set to NULL. */ if (!value) { value = Py_NewRef(Py_None); } /* Normalize the exception so that if the type is a class, the value will be an instance. */ if (PyExceptionClass_Check(type)) { PyObject *inclass = NULL; int is_subclass = 0; if (PyExceptionInstance_Check(value)) { inclass = PyExceptionInstance_Class(value); is_subclass = PyObject_IsSubclass(inclass, type); if (is_subclass < 0) { goto error; } } /* If the value was not an instance, or is not an instance whose class is (or is derived from) type, then use the value as an argument to instantiation of the type class. */ if (!is_subclass) { PyObject *fixed_value = _PyErr_CreateException(type, value); if (fixed_value == NULL) { goto error; } Py_SETREF(value, fixed_value); } /* If the class of the instance doesn't exactly match the class of the type, believe the instance. */ else if (inclass != type) { Py_SETREF(type, Py_NewRef(inclass)); } } *exc = type; *val = value; tstate->recursion_headroom--; return; error: Py_DECREF(type); Py_DECREF(value); recursion_depth++; if (recursion_depth == Py_NORMALIZE_RECURSION_LIMIT) { _PyErr_SetString(tstate, PyExc_RecursionError, "maximum recursion depth exceeded " "while normalizing an exception"); } /* If the new exception doesn't set a traceback and the old exception had a traceback, use the old traceback for the new exception. It's better than nothing. */ initial_tb = *tb; _PyErr_Fetch(tstate, exc, val, tb); assert(*exc != NULL); if (initial_tb != NULL) { if (*tb == NULL) *tb = initial_tb; else Py_DECREF(initial_tb); } /* Abort when Py_NORMALIZE_RECURSION_LIMIT has been exceeded, and the corresponding RecursionError could not be normalized, and the MemoryError raised when normalize this RecursionError could not be normalized. */ if (recursion_depth >= Py_NORMALIZE_RECURSION_LIMIT + 2) { if (PyErr_GivenExceptionMatches(*exc, PyExc_MemoryError)) { Py_FatalError("Cannot recover from MemoryErrors " "while normalizing exceptions."); } else { Py_FatalError("Cannot recover from the recursive normalization " "of an exception."); } } goto restart; } void PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb) { PyThreadState *tstate = _PyThreadState_GET(); _PyErr_NormalizeException(tstate, exc, val, tb); } PyObject * _PyErr_GetRaisedException(PyThreadState *tstate) { PyObject *exc = tstate->current_exception; tstate->current_exception = NULL; return exc; } PyObject * PyErr_GetRaisedException(void) { PyThreadState *tstate = _PyThreadState_GET(); return _PyErr_GetRaisedException(tstate); } void _PyErr_Fetch(PyThreadState *tstate, PyObject **p_type, PyObject **p_value, PyObject **p_traceback) { PyObject *exc = _PyErr_GetRaisedException(tstate); *p_value = exc; if (exc == NULL) { *p_type = NULL; *p_traceback = NULL; } else { *p_type = Py_NewRef(Py_TYPE(exc)); *p_traceback = Py_XNewRef(((PyBaseExceptionObject *)exc)->traceback); } } void PyErr_Fetch(PyObject **p_type, PyObject **p_value, PyObject **p_traceback) { PyThreadState *tstate = _PyThreadState_GET(); _PyErr_Fetch(tstate, p_type, p_value, p_traceback); } void _PyErr_Clear(PyThreadState *tstate) { _PyErr_Restore(tstate, NULL, NULL, NULL); } void PyErr_Clear(void) { PyThreadState *tstate = _PyThreadState_GET(); _PyErr_Clear(tstate); } static PyObject* get_exc_type(PyObject *exc_value) /* returns a borrowed ref */ { if (exc_value == NULL || exc_value == Py_None) { return Py_None; } else { assert(PyExceptionInstance_Check(exc_value)); PyObject *type = PyExceptionInstance_Class(exc_value); assert(type != NULL); return type; } } static PyObject* get_exc_traceback(PyObject *exc_value) /* returns a borrowed ref */ { if (exc_value == NULL || exc_value == Py_None) { return Py_None; } else { assert(PyExceptionInstance_Check(exc_value)); PyObject *tb = PyException_GetTraceback(exc_value); Py_XDECREF(tb); return tb ? tb : Py_None; } } void _PyErr_GetExcInfo(PyThreadState *tstate, PyObject **p_type, PyObject **p_value, PyObject **p_traceback) { _PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate); *p_type = Py_XNewRef(get_exc_type(exc_info->exc_value)); *p_value = Py_XNewRef(exc_info->exc_value); *p_traceback = Py_XNewRef(get_exc_traceback(exc_info->exc_value)); } PyObject* _PyErr_GetHandledException(PyThreadState *tstate) { _PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate); PyObject *exc = exc_info->exc_value; if (exc == NULL || exc == Py_None) { return NULL; } return Py_NewRef(exc); } PyObject* PyErr_GetHandledException(void) { PyThreadState *tstate = _PyThreadState_GET(); return _PyErr_GetHandledException(tstate); } void _PyErr_SetHandledException(PyThreadState *tstate, PyObject *exc) { Py_XSETREF(tstate->exc_info->exc_value, Py_XNewRef(exc)); } void PyErr_SetHandledException(PyObject *exc) { PyThreadState *tstate = _PyThreadState_GET(); _PyErr_SetHandledException(tstate, exc); } void PyErr_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback) { PyThreadState *tstate = _PyThreadState_GET(); _PyErr_GetExcInfo(tstate, p_type, p_value, p_traceback); } void PyErr_SetExcInfo(PyObject *type, PyObject *value, PyObject *traceback) { PyErr_SetHandledException(value); Py_XDECREF(value); /* These args are no longer used, but we still need to steal a ref */ Py_XDECREF(type); Py_XDECREF(traceback); } PyObject* _PyErr_StackItemToExcInfoTuple(_PyErr_StackItem *err_info) { PyObject *exc_value = err_info->exc_value; assert(exc_value == NULL || exc_value == Py_None || PyExceptionInstance_Check(exc_value)); PyObject *exc_type = get_exc_type(exc_value); PyObject *exc_traceback = get_exc_traceback(exc_value); return Py_BuildValue( "(OOO)", exc_type ? exc_type : Py_None, exc_value ? exc_value : Py_None, exc_traceback ? exc_traceback : Py_None); } /* Like PyErr_Restore(), but if an exception is already set, set the context associated with it. The caller is responsible for ensuring that this call won't create any cycles in the exception context chain. */ void _PyErr_ChainExceptions(PyObject *typ, PyObject *val, PyObject *tb) { if (typ == NULL) return; PyThreadState *tstate = _PyThreadState_GET(); if (!PyExceptionClass_Check(typ)) { _PyErr_Format(tstate, PyExc_SystemError, "_PyErr_ChainExceptions: " "exception %R is not a BaseException subclass", typ); return; } if (_PyErr_Occurred(tstate)) { _PyErr_NormalizeException(tstate, &typ, &val, &tb); if (tb != NULL) { PyException_SetTraceback(val, tb); Py_DECREF(tb); } Py_DECREF(typ); PyObject *exc2 = _PyErr_GetRaisedException(tstate); PyException_SetContext(exc2, val); _PyErr_SetRaisedException(tstate, exc2); } else { _PyErr_Restore(tstate, typ, val, tb); } } /* Like PyErr_SetRaisedException(), but if an exception is already set, set the context associated with it. The caller is responsible for ensuring that this call won't create any cycles in the exception context chain. */ void _PyErr_ChainExceptions1(PyObject *exc) { if (exc == NULL) { return; } PyThreadState *tstate = _PyThreadState_GET(); if (_PyErr_Occurred(tstate)) { PyObject *exc2 = _PyErr_GetRaisedException(tstate); PyException_SetContext(exc2, exc); _PyErr_SetRaisedException(tstate, exc2); } else { _PyErr_SetRaisedException(tstate, exc); } } /* If the current thread is handling an exception (exc_info is ), set this exception as the context of the current raised exception. This function can only be called when _PyErr_Occurred() is true. Also, this function won't create any cycles in the exception context chain to the extent that _PyErr_SetObject ensures this. */ void _PyErr_ChainStackItem(void) { PyThreadState *tstate = _PyThreadState_GET(); assert(_PyErr_Occurred(tstate)); _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value == NULL || exc_info->exc_value == Py_None) { return; } PyObject *exc = _PyErr_GetRaisedException(tstate); /* _PyErr_SetObject sets the context from PyThreadState. */ _PyErr_SetObject(tstate, (PyObject *) Py_TYPE(exc), exc); Py_DECREF(exc); // since _PyErr_Occurred was true } static PyObject * _PyErr_FormatVFromCause(PyThreadState *tstate, PyObject *exception, const char *format, va_list vargs) { assert(_PyErr_Occurred(tstate)); PyObject *exc = _PyErr_GetRaisedException(tstate); assert(!_PyErr_Occurred(tstate)); _PyErr_FormatV(tstate, exception, format, vargs); PyObject *exc2 = _PyErr_GetRaisedException(tstate); PyException_SetCause(exc2, Py_NewRef(exc)); PyException_SetContext(exc2, Py_NewRef(exc)); Py_DECREF(exc); _PyErr_SetRaisedException(tstate, exc2); return NULL; } PyObject * _PyErr_FormatFromCauseTstate(PyThreadState *tstate, PyObject *exception, const char *format, ...) { va_list vargs; va_start(vargs, format); _PyErr_FormatVFromCause(tstate, exception, format, vargs); va_end(vargs); return NULL; } PyObject * _PyErr_FormatFromCause(PyObject *exception, const char *format, ...) { PyThreadState *tstate = _PyThreadState_GET(); va_list vargs; va_start(vargs, format); _PyErr_FormatVFromCause(tstate, exception, format, vargs); va_end(vargs); return NULL; } /* Convenience functions to set a type error exception and return 0 */ int PyErr_BadArgument(void) { PyThreadState *tstate = _PyThreadState_GET(); _PyErr_SetString(tstate, PyExc_TypeError, "bad argument type for built-in operation"); return 0; } PyObject * PyErr_NoMemory(void) { PyThreadState *tstate = _PyThreadState_GET(); return _PyErr_NoMemory(tstate); } PyObject * PyErr_SetFromErrnoWithFilenameObject(PyObject *exc, PyObject *filenameObject) { return PyErr_SetFromErrnoWithFilenameObjects(exc, filenameObject, NULL); } PyObject * PyErr_SetFromErrnoWithFilenameObjects(PyObject *exc, PyObject *filenameObject, PyObject *filenameObject2) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *message; PyObject *v, *args; int i = errno; #ifdef MS_WINDOWS WCHAR *s_buf = NULL; #endif /* Unix/Windows */ #ifdef EINTR if (i == EINTR && PyErr_CheckSignals()) return NULL; #endif #ifndef MS_WINDOWS if (i != 0) { const char *s = strerror(i); message = PyUnicode_DecodeLocale(s, "surrogateescape"); } else { /* Sometimes errno didn't get set */ message = PyUnicode_FromString("Error"); } #else if (i == 0) message = PyUnicode_FromString("Error"); /* Sometimes errno didn't get set */ else { /* Note that the Win32 errors do not lineup with the errno error. So if the error is in the MSVC error table, we use it, otherwise we assume it really _is_ a Win32 error code */ if (i > 0 && i < _sys_nerr) { message = PyUnicode_FromString(_sys_errlist[i]); } else { int len = FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, /* no message source */ i, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ (LPWSTR) &s_buf, 0, /* size not used */ NULL); /* no args */ if (len==0) { /* Only ever seen this in out-of-mem situations */ s_buf = NULL; message = PyUnicode_FromFormat("Windows Error 0x%x", i); } else { /* remove trailing cr/lf and dots */ while (len > 0 && (s_buf[len-1] <= L' ' || s_buf[len-1] == L'.')) s_buf[--len] = L'\0'; message = PyUnicode_FromWideChar(s_buf, len); } } } #endif /* Unix/Windows */ if (message == NULL) { #ifdef MS_WINDOWS LocalFree(s_buf); #endif return NULL; } if (filenameObject != NULL) { if (filenameObject2 != NULL) args = Py_BuildValue("(iOOiO)", i, message, filenameObject, 0, filenameObject2); else args = Py_BuildValue("(iOO)", i, message, filenameObject); } else { assert(filenameObject2 == NULL); args = Py_BuildValue("(iO)", i, message); } Py_DECREF(message); if (args != NULL) { v = PyObject_Call(exc, args, NULL); Py_DECREF(args); if (v != NULL) { _PyErr_SetObject(tstate, (PyObject *) Py_TYPE(v), v); Py_DECREF(v); } } #ifdef MS_WINDOWS LocalFree(s_buf); #endif return NULL; } PyObject * PyErr_SetFromErrnoWithFilename(PyObject *exc, const char *filename) { PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL; PyObject *result = PyErr_SetFromErrnoWithFilenameObjects(exc, name, NULL); Py_XDECREF(name); return result; } PyObject * PyErr_SetFromErrno(PyObject *exc) { return PyErr_SetFromErrnoWithFilenameObjects(exc, NULL, NULL); } #ifdef MS_WINDOWS /* Windows specific error code handling */ PyObject *PyErr_SetExcFromWindowsErrWithFilenameObject( PyObject *exc, int ierr, PyObject *filenameObject) { return PyErr_SetExcFromWindowsErrWithFilenameObjects(exc, ierr, filenameObject, NULL); } PyObject *PyErr_SetExcFromWindowsErrWithFilenameObjects( PyObject *exc, int ierr, PyObject *filenameObject, PyObject *filenameObject2) { PyThreadState *tstate = _PyThreadState_GET(); int len; WCHAR *s_buf = NULL; /* Free via LocalFree */ PyObject *message; PyObject *args, *v; DWORD err = (DWORD)ierr; if (err==0) { err = GetLastError(); } len = FormatMessageW( /* Error API error */ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, /* no message source */ err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ (LPWSTR) &s_buf, 0, /* size not used */ NULL); /* no args */ if (len==0) { /* Only seen this in out of mem situations */ message = PyUnicode_FromFormat("Windows Error 0x%x", err); s_buf = NULL; } else { /* remove trailing cr/lf and dots */ while (len > 0 && (s_buf[len-1] <= L' ' || s_buf[len-1] == L'.')) s_buf[--len] = L'\0'; message = PyUnicode_FromWideChar(s_buf, len); } if (message == NULL) { LocalFree(s_buf); return NULL; } if (filenameObject == NULL) { assert(filenameObject2 == NULL); filenameObject = filenameObject2 = Py_None; } else if (filenameObject2 == NULL) filenameObject2 = Py_None; /* This is the constructor signature for OSError. The POSIX translation will be figured out by the constructor. */ args = Py_BuildValue("(iOOiO)", 0, message, filenameObject, err, filenameObject2); Py_DECREF(message); if (args != NULL) { v = PyObject_Call(exc, args, NULL); Py_DECREF(args); if (v != NULL) { _PyErr_SetObject(tstate, (PyObject *) Py_TYPE(v), v); Py_DECREF(v); } } LocalFree(s_buf); return NULL; } PyObject *PyErr_SetExcFromWindowsErrWithFilename( PyObject *exc, int ierr, const char *filename) { PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL; PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObjects(exc, ierr, name, NULL); Py_XDECREF(name); return ret; } PyObject *PyErr_SetExcFromWindowsErr(PyObject *exc, int ierr) { return PyErr_SetExcFromWindowsErrWithFilename(exc, ierr, NULL); } PyObject *PyErr_SetFromWindowsErr(int ierr) { return PyErr_SetExcFromWindowsErrWithFilename(PyExc_OSError, ierr, NULL); } PyObject *PyErr_SetFromWindowsErrWithFilename( int ierr, const char *filename) { PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL; PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObjects( PyExc_OSError, ierr, name, NULL); Py_XDECREF(name); return result; } #endif /* MS_WINDOWS */ static PyObject * _PyErr_SetImportErrorSubclassWithNameFrom( PyObject *exception, PyObject *msg, PyObject *name, PyObject *path, PyObject* from_name) { PyThreadState *tstate = _PyThreadState_GET(); int issubclass; PyObject *kwargs, *error; issubclass = PyObject_IsSubclass(exception, PyExc_ImportError); if (issubclass < 0) { return NULL; } else if (!issubclass) { _PyErr_SetString(tstate, PyExc_TypeError, "expected a subclass of ImportError"); return NULL; } if (msg == NULL) { _PyErr_SetString(tstate, PyExc_TypeError, "expected a message argument"); return NULL; } if (name == NULL) { name = Py_None; } if (path == NULL) { path = Py_None; } if (from_name == NULL) { from_name = Py_None; } kwargs = PyDict_New(); if (kwargs == NULL) { return NULL; } if (PyDict_SetItemString(kwargs, "name", name) < 0) { goto done; } if (PyDict_SetItemString(kwargs, "path", path) < 0) { goto done; } if (PyDict_SetItemString(kwargs, "name_from", from_name) < 0) { goto done; } error = PyObject_VectorcallDict(exception, &msg, 1, kwargs); if (error != NULL) { _PyErr_SetObject(tstate, (PyObject *)Py_TYPE(error), error); Py_DECREF(error); } done: Py_DECREF(kwargs); return NULL; } PyObject * PyErr_SetImportErrorSubclass(PyObject *exception, PyObject *msg, PyObject *name, PyObject *path) { return _PyErr_SetImportErrorSubclassWithNameFrom(exception, msg, name, path, NULL); } PyObject * _PyErr_SetImportErrorWithNameFrom(PyObject *msg, PyObject *name, PyObject *path, PyObject* from_name) { return _PyErr_SetImportErrorSubclassWithNameFrom(PyExc_ImportError, msg, name, path, from_name); } PyObject * PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path) { return PyErr_SetImportErrorSubclass(PyExc_ImportError, msg, name, path); } void _PyErr_BadInternalCall(const char *filename, int lineno) { PyThreadState *tstate = _PyThreadState_GET(); _PyErr_Format(tstate, PyExc_SystemError, "%s:%d: bad argument to internal function", filename, lineno); } /* Remove the preprocessor macro for PyErr_BadInternalCall() so that we can export the entry point for existing object code: */ #undef PyErr_BadInternalCall void PyErr_BadInternalCall(void) { assert(0 && "bad argument to internal function"); PyThreadState *tstate = _PyThreadState_GET(); _PyErr_SetString(tstate, PyExc_SystemError, "bad argument to internal function"); } #define PyErr_BadInternalCall() _PyErr_BadInternalCall(__FILE__, __LINE__) static PyObject * _PyErr_FormatV(PyThreadState *tstate, PyObject *exception, const char *format, va_list vargs) { PyObject* string; /* Issue #23571: PyUnicode_FromFormatV() must not be called with an exception set, it calls arbitrary Python code like PyObject_Repr() */ _PyErr_Clear(tstate); string = PyUnicode_FromFormatV(format, vargs); _PyErr_SetObject(tstate, exception, string); Py_XDECREF(string); return NULL; } PyObject * PyErr_FormatV(PyObject *exception, const char *format, va_list vargs) { PyThreadState *tstate = _PyThreadState_GET(); return _PyErr_FormatV(tstate, exception, format, vargs); } PyObject * _PyErr_Format(PyThreadState *tstate, PyObject *exception, const char *format, ...) { va_list vargs; va_start(vargs, format); _PyErr_FormatV(tstate, exception, format, vargs); va_end(vargs); return NULL; } PyObject * PyErr_Format(PyObject *exception, const char *format, ...) { PyThreadState *tstate = _PyThreadState_GET(); va_list vargs; va_start(vargs, format); _PyErr_FormatV(tstate, exception, format, vargs); va_end(vargs); return NULL; } /* Adds a note to the current exception (if any) */ void _PyErr_FormatNote(const char *format, ...) { PyObject *exc = PyErr_GetRaisedException(); if (exc == NULL) { return; } va_list vargs; va_start(vargs, format); PyObject *note = PyUnicode_FromFormatV(format, vargs); va_end(vargs); if (note == NULL) { goto error; } int res = _PyException_AddNote(exc, note); Py_DECREF(note); if (res < 0) { goto error; } PyErr_SetRaisedException(exc); return; error: _PyErr_ChainExceptions1(exc); } PyObject * PyErr_NewException(const char *name, PyObject *base, PyObject *dict) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *modulename = NULL; PyObject *mydict = NULL; PyObject *bases = NULL; PyObject *result = NULL; const char *dot = strrchr(name, '.'); if (dot == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, "PyErr_NewException: name must be module.class"); return NULL; } if (base == NULL) { base = PyExc_Exception; } if (dict == NULL) { dict = mydict = PyDict_New(); if (dict == NULL) goto failure; } int r = PyDict_Contains(dict, &_Py_ID(__module__)); if (r < 0) { goto failure; } if (r == 0) { modulename = PyUnicode_FromStringAndSize(name, (Py_ssize_t)(dot-name)); if (modulename == NULL) goto failure; if (PyDict_SetItem(dict, &_Py_ID(__module__), modulename) != 0) goto failure; } if (PyTuple_Check(base)) { bases = Py_NewRef(base); } else { bases = PyTuple_Pack(1, base); if (bases == NULL) goto failure; } /* Create a real class. */ result = PyObject_CallFunction((PyObject *)&PyType_Type, "sOO", dot+1, bases, dict); failure: Py_XDECREF(bases); Py_XDECREF(mydict); Py_XDECREF(modulename); return result; } /* Create an exception with docstring */ PyObject * PyErr_NewExceptionWithDoc(const char *name, const char *doc, PyObject *base, PyObject *dict) { int result; PyObject *ret = NULL; PyObject *mydict = NULL; /* points to the dict only if we create it */ PyObject *docobj; if (dict == NULL) { dict = mydict = PyDict_New(); if (dict == NULL) { return NULL; } } if (doc != NULL) { docobj = PyUnicode_FromString(doc); if (docobj == NULL) goto failure; result = PyDict_SetItemString(dict, "__doc__", docobj); Py_DECREF(docobj); if (result < 0) goto failure; } ret = PyErr_NewException(name, base, dict); failure: Py_XDECREF(mydict); return ret; } PyDoc_STRVAR(UnraisableHookArgs__doc__, "UnraisableHookArgs\n\ \n\ Type used to pass arguments to sys.unraisablehook."); static PyTypeObject UnraisableHookArgsType; static PyStructSequence_Field UnraisableHookArgs_fields[] = { {"exc_type", "Exception type"}, {"exc_value", "Exception value"}, {"exc_traceback", "Exception traceback"}, {"err_msg", "Error message"}, {"object", "Object causing the exception"}, {0} }; static PyStructSequence_Desc UnraisableHookArgs_desc = { .name = "UnraisableHookArgs", .doc = UnraisableHookArgs__doc__, .fields = UnraisableHookArgs_fields, .n_in_sequence = 5 }; PyStatus _PyErr_InitTypes(PyInterpreterState *interp) { if (_PyStructSequence_InitBuiltin(interp, &UnraisableHookArgsType, &UnraisableHookArgs_desc) < 0) { return _PyStatus_ERR("failed to initialize UnraisableHookArgs type"); } return _PyStatus_OK(); } void _PyErr_FiniTypes(PyInterpreterState *interp) { _PyStructSequence_FiniBuiltin(interp, &UnraisableHookArgsType); } static PyObject * make_unraisable_hook_args(PyThreadState *tstate, PyObject *exc_type, PyObject *exc_value, PyObject *exc_tb, PyObject *err_msg, PyObject *obj) { PyObject *args = PyStructSequence_New(&UnraisableHookArgsType); if (args == NULL) { return NULL; } Py_ssize_t pos = 0; #define ADD_ITEM(exc_type) \ do { \ if (exc_type == NULL) { \ exc_type = Py_None; \ } \ PyStructSequence_SET_ITEM(args, pos++, Py_NewRef(exc_type)); \ } while (0) ADD_ITEM(exc_type); ADD_ITEM(exc_value); ADD_ITEM(exc_tb); ADD_ITEM(err_msg); ADD_ITEM(obj); #undef ADD_ITEM if (_PyErr_Occurred(tstate)) { Py_DECREF(args); return NULL; } return args; } /* Default implementation of sys.unraisablehook. It can be called to log the exception of a custom sys.unraisablehook. Do nothing if sys.stderr attribute doesn't exist or is set to None. */ static int write_unraisable_exc_file(PyThreadState *tstate, PyObject *exc_type, PyObject *exc_value, PyObject *exc_tb, PyObject *err_msg, PyObject *obj, PyObject *file) { if (obj != NULL && obj != Py_None) { if (err_msg != NULL && err_msg != Py_None) { if (PyFile_WriteObject(err_msg, file, Py_PRINT_RAW) < 0) { return -1; } if (PyFile_WriteString(": ", file) < 0) { return -1; } } else { if (PyFile_WriteString("Exception ignored in: ", file) < 0) { return -1; } } if (PyFile_WriteObject(obj, file, 0) < 0) { _PyErr_Clear(tstate); if (PyFile_WriteString("", file) < 0) { return -1; } } if (PyFile_WriteString("\n", file) < 0) { return -1; } } else if (err_msg != NULL && err_msg != Py_None) { if (PyFile_WriteObject(err_msg, file, Py_PRINT_RAW) < 0) { return -1; } if (PyFile_WriteString(":\n", file) < 0) { return -1; } } if (exc_tb != NULL && exc_tb != Py_None) { if (PyTraceBack_Print(exc_tb, file) < 0) { /* continue even if writing the traceback failed */ _PyErr_Clear(tstate); } } if (exc_type == NULL || exc_type == Py_None) { return -1; } assert(PyExceptionClass_Check(exc_type)); PyObject *modulename = PyObject_GetAttr(exc_type, &_Py_ID(__module__)); if (modulename == NULL || !PyUnicode_Check(modulename)) { Py_XDECREF(modulename); _PyErr_Clear(tstate); if (PyFile_WriteString("", file) < 0) { return -1; } } else { if (!_PyUnicode_Equal(modulename, &_Py_ID(builtins)) && !_PyUnicode_Equal(modulename, &_Py_ID(__main__))) { if (PyFile_WriteObject(modulename, file, Py_PRINT_RAW) < 0) { Py_DECREF(modulename); return -1; } Py_DECREF(modulename); if (PyFile_WriteString(".", file) < 0) { return -1; } } else { Py_DECREF(modulename); } } PyObject *qualname = PyType_GetQualName((PyTypeObject *)exc_type); if (qualname == NULL || !PyUnicode_Check(qualname)) { Py_XDECREF(qualname); _PyErr_Clear(tstate); if (PyFile_WriteString("", file) < 0) { return -1; } } else { if (PyFile_WriteObject(qualname, file, Py_PRINT_RAW) < 0) { Py_DECREF(qualname); return -1; } Py_DECREF(qualname); } if (exc_value && exc_value != Py_None) { if (PyFile_WriteString(": ", file) < 0) { return -1; } if (PyFile_WriteObject(exc_value, file, Py_PRINT_RAW) < 0) { _PyErr_Clear(tstate); if (PyFile_WriteString("", file) < 0) { return -1; } } } if (PyFile_WriteString("\n", file) < 0) { return -1; } /* Explicitly call file.flush() */ PyObject *res = _PyObject_CallMethodNoArgs(file, &_Py_ID(flush)); if (!res) { return -1; } Py_DECREF(res); return 0; } static int write_unraisable_exc(PyThreadState *tstate, PyObject *exc_type, PyObject *exc_value, PyObject *exc_tb, PyObject *err_msg, PyObject *obj) { PyObject *file = _PySys_GetAttr(tstate, &_Py_ID(stderr)); if (file == NULL || file == Py_None) { return 0; } /* Hold a strong reference to ensure that sys.stderr doesn't go away while we use it */ Py_INCREF(file); int res = write_unraisable_exc_file(tstate, exc_type, exc_value, exc_tb, err_msg, obj, file); Py_DECREF(file); return res; } PyObject* _PyErr_WriteUnraisableDefaultHook(PyObject *args) { PyThreadState *tstate = _PyThreadState_GET(); if (!Py_IS_TYPE(args, &UnraisableHookArgsType)) { _PyErr_SetString(tstate, PyExc_TypeError, "sys.unraisablehook argument type " "must be UnraisableHookArgs"); return NULL; } /* Borrowed references */ PyObject *exc_type = PyStructSequence_GET_ITEM(args, 0); PyObject *exc_value = PyStructSequence_GET_ITEM(args, 1); PyObject *exc_tb = PyStructSequence_GET_ITEM(args, 2); PyObject *err_msg = PyStructSequence_GET_ITEM(args, 3); PyObject *obj = PyStructSequence_GET_ITEM(args, 4); if (write_unraisable_exc(tstate, exc_type, exc_value, exc_tb, err_msg, obj) < 0) { return NULL; } Py_RETURN_NONE; } /* Call sys.unraisablehook(). This function can be used when an exception has occurred but there is no way for Python to handle it. For example, when a destructor raises an exception or during garbage collection (gc.collect()). If err_msg_str is non-NULL, the error message is formatted as: "Exception ignored %s" % err_msg_str. Otherwise, use "Exception ignored in" error message. An exception must be set when calling this function. */ void _PyErr_WriteUnraisableMsg(const char *err_msg_str, PyObject *obj) { PyThreadState *tstate = _PyThreadState_GET(); _Py_EnsureTstateNotNULL(tstate); PyObject *err_msg = NULL; PyObject *exc_type, *exc_value, *exc_tb; _PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb); assert(exc_type != NULL); if (exc_type == NULL) { /* sys.unraisablehook requires that at least exc_type is set */ goto default_hook; } if (exc_tb == NULL) { PyFrameObject *frame = PyThreadState_GetFrame(tstate); if (frame != NULL) { exc_tb = _PyTraceBack_FromFrame(NULL, frame); if (exc_tb == NULL) { _PyErr_Clear(tstate); } Py_DECREF(frame); } } _PyErr_NormalizeException(tstate, &exc_type, &exc_value, &exc_tb); if (exc_tb != NULL && exc_tb != Py_None && PyTraceBack_Check(exc_tb)) { if (PyException_SetTraceback(exc_value, exc_tb) < 0) { _PyErr_Clear(tstate); } } if (err_msg_str != NULL) { err_msg = PyUnicode_FromFormat("Exception ignored %s", err_msg_str); if (err_msg == NULL) { PyErr_Clear(); } } PyObject *hook_args = make_unraisable_hook_args( tstate, exc_type, exc_value, exc_tb, err_msg, obj); if (hook_args == NULL) { err_msg_str = ("Exception ignored on building " "sys.unraisablehook arguments"); goto error; } PyObject *hook = _PySys_GetAttr(tstate, &_Py_ID(unraisablehook)); if (hook == NULL) { Py_DECREF(hook_args); goto default_hook; } if (_PySys_Audit(tstate, "sys.unraisablehook", "OO", hook, hook_args) < 0) { Py_DECREF(hook_args); err_msg_str = "Exception ignored in audit hook"; obj = NULL; goto error; } if (hook == Py_None) { Py_DECREF(hook_args); goto default_hook; } PyObject *res = PyObject_CallOneArg(hook, hook_args); Py_DECREF(hook_args); if (res != NULL) { Py_DECREF(res); goto done; } /* sys.unraisablehook failed: log its error using default hook */ obj = hook; err_msg_str = NULL; error: /* err_msg_str and obj have been updated and we have a new exception */ Py_XSETREF(err_msg, PyUnicode_FromString(err_msg_str ? err_msg_str : "Exception ignored in sys.unraisablehook")); Py_XDECREF(exc_type); Py_XDECREF(exc_value); Py_XDECREF(exc_tb); _PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb); default_hook: /* Call the default unraisable hook (ignore failure) */ (void)write_unraisable_exc(tstate, exc_type, exc_value, exc_tb, err_msg, obj); done: Py_XDECREF(exc_type); Py_XDECREF(exc_value); Py_XDECREF(exc_tb); Py_XDECREF(err_msg); _PyErr_Clear(tstate); /* Just in case */ } void PyErr_WriteUnraisable(PyObject *obj) { _PyErr_WriteUnraisableMsg(NULL, obj); } void PyErr_SyntaxLocation(const char *filename, int lineno) { PyErr_SyntaxLocationEx(filename, lineno, -1); } /* Set file and line information for the current exception. If the exception is not a SyntaxError, also sets additional attributes to make printing of exceptions believe it is a syntax error. */ static void PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, int end_lineno, int end_col_offset) { PyThreadState *tstate = _PyThreadState_GET(); /* add attributes for the line number and filename for the error */ PyObject *exc = _PyErr_GetRaisedException(tstate); /* XXX check that it is, indeed, a syntax error. It might not * be, though. */ PyObject *tmp = PyLong_FromLong(lineno); if (tmp == NULL) { _PyErr_Clear(tstate); } else { if (PyObject_SetAttr(exc, &_Py_ID(lineno), tmp)) { _PyErr_Clear(tstate); } Py_DECREF(tmp); } tmp = NULL; if (col_offset >= 0) { tmp = PyLong_FromLong(col_offset); if (tmp == NULL) { _PyErr_Clear(tstate); } } if (PyObject_SetAttr(exc, &_Py_ID(offset), tmp ? tmp : Py_None)) { _PyErr_Clear(tstate); } Py_XDECREF(tmp); tmp = NULL; if (end_lineno >= 0) { tmp = PyLong_FromLong(end_lineno); if (tmp == NULL) { _PyErr_Clear(tstate); } } if (PyObject_SetAttr(exc, &_Py_ID(end_lineno), tmp ? tmp : Py_None)) { _PyErr_Clear(tstate); } Py_XDECREF(tmp); tmp = NULL; if (end_col_offset >= 0) { tmp = PyLong_FromLong(end_col_offset); if (tmp == NULL) { _PyErr_Clear(tstate); } } if (PyObject_SetAttr(exc, &_Py_ID(end_offset), tmp ? tmp : Py_None)) { _PyErr_Clear(tstate); } Py_XDECREF(tmp); tmp = NULL; if (filename != NULL) { if (PyObject_SetAttr(exc, &_Py_ID(filename), filename)) { _PyErr_Clear(tstate); } tmp = PyErr_ProgramTextObject(filename, lineno); if (tmp) { if (PyObject_SetAttr(exc, &_Py_ID(text), tmp)) { _PyErr_Clear(tstate); } Py_DECREF(tmp); } else { _PyErr_Clear(tstate); } } if ((PyObject *)Py_TYPE(exc) != PyExc_SyntaxError) { if (_PyObject_LookupAttr(exc, &_Py_ID(msg), &tmp) < 0) { _PyErr_Clear(tstate); } else if (tmp) { Py_DECREF(tmp); } else { tmp = PyObject_Str(exc); if (tmp) { if (PyObject_SetAttr(exc, &_Py_ID(msg), tmp)) { _PyErr_Clear(tstate); } Py_DECREF(tmp); } else { _PyErr_Clear(tstate); } } if (_PyObject_LookupAttr(exc, &_Py_ID(print_file_and_line), &tmp) < 0) { _PyErr_Clear(tstate); } else if (tmp) { Py_DECREF(tmp); } else { if (PyObject_SetAttr(exc, &_Py_ID(print_file_and_line), Py_None)) { _PyErr_Clear(tstate); } } } _PyErr_SetRaisedException(tstate, exc); } void PyErr_SyntaxLocationObject(PyObject *filename, int lineno, int col_offset) { PyErr_SyntaxLocationObjectEx(filename, lineno, col_offset, lineno, -1); } void PyErr_RangedSyntaxLocationObject(PyObject *filename, int lineno, int col_offset, int end_lineno, int end_col_offset) { PyErr_SyntaxLocationObjectEx(filename, lineno, col_offset, end_lineno, end_col_offset); } void PyErr_SyntaxLocationEx(const char *filename, int lineno, int col_offset) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *fileobj; if (filename != NULL) { fileobj = PyUnicode_DecodeFSDefault(filename); if (fileobj == NULL) { _PyErr_Clear(tstate); } } else { fileobj = NULL; } PyErr_SyntaxLocationObject(fileobj, lineno, col_offset); Py_XDECREF(fileobj); } /* Attempt to load the line of text that the exception refers to. If it fails, it will return NULL but will not set an exception. XXX The functionality of this function is quite similar to the functionality in tb_displayline() in traceback.c. */ static PyObject * err_programtext(PyThreadState *tstate, FILE *fp, int lineno, const char* encoding) { int i; char linebuf[1000]; if (fp == NULL) { return NULL; } for (i = 0; i < lineno; i++) { char *pLastChar = &linebuf[sizeof(linebuf) - 2]; do { *pLastChar = '\0'; if (Py_UniversalNewlineFgets(linebuf, sizeof linebuf, fp, NULL) == NULL) { goto after_loop; } /* fgets read *something*; if it didn't get as far as pLastChar, it must have found a newline or hit the end of the file; if pLastChar is \n, it obviously found a newline; else we haven't yet seen a newline, so must continue */ } while (*pLastChar != '\0' && *pLastChar != '\n'); } after_loop: fclose(fp); if (i == lineno) { PyObject *res; if (encoding != NULL) { res = PyUnicode_Decode(linebuf, strlen(linebuf), encoding, "replace"); } else { res = PyUnicode_FromString(linebuf); } if (res == NULL) _PyErr_Clear(tstate); return res; } return NULL; } PyObject * PyErr_ProgramText(const char *filename, int lineno) { if (filename == NULL) { return NULL; } PyObject *filename_obj = PyUnicode_DecodeFSDefault(filename); if (filename_obj == NULL) { PyErr_Clear(); return NULL; } PyObject *res = PyErr_ProgramTextObject(filename_obj, lineno); Py_DECREF(filename_obj); return res; } PyObject * _PyErr_ProgramDecodedTextObject(PyObject *filename, int lineno, const char* encoding) { if (filename == NULL || lineno <= 0) { return NULL; } PyThreadState *tstate = _PyThreadState_GET(); FILE *fp = _Py_fopen_obj(filename, "r" PY_STDIOTEXTMODE); if (fp == NULL) { _PyErr_Clear(tstate); return NULL; } return err_programtext(tstate, fp, lineno, encoding); } PyObject * PyErr_ProgramTextObject(PyObject *filename, int lineno) { return _PyErr_ProgramDecodedTextObject(filename, lineno, NULL); } #ifdef __cplusplus } #endif ================================================ FILE: Fileutils.c ================================================ #include "Python.h" #include "pycore_fileutils.h" // fileutils definitions #include "pycore_runtime.h" // _PyRuntime #include "osdefs.h" // SEP #include #include // mbstowcs() #ifdef MS_WINDOWS # include # include # include // FILE_DEVICE_* constants # include "pycore_fileutils_windows.h" // FILE_STAT_BASIC_INFORMATION # if defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP) # define PATHCCH_ALLOW_LONG_PATHS 0x01 # else # include // PathCchCombineEx # endif extern int winerror_to_errno(int); #endif #ifdef HAVE_LANGINFO_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION #include #endif #ifdef HAVE_FCNTL_H #include #endif /* HAVE_FCNTL_H */ #ifdef O_CLOEXEC /* Does open() support the O_CLOEXEC flag? Possible values: -1: unknown 0: open() ignores O_CLOEXEC flag, ex: Linux kernel older than 2.6.23 1: open() supports O_CLOEXEC flag, close-on-exec is set The flag is used by _Py_open(), _Py_open_noraise(), io.FileIO and os.open(). */ int _Py_open_cloexec_works = -1; #endif // The value must be the same in unicodeobject.c. #define MAX_UNICODE 0x10ffff // mbstowcs() and mbrtowc() errors static const size_t DECODE_ERROR = ((size_t)-1); static const size_t INCOMPLETE_CHARACTER = (size_t)-2; static int get_surrogateescape(_Py_error_handler errors, int *surrogateescape) { switch (errors) { case _Py_ERROR_STRICT: *surrogateescape = 0; return 0; case _Py_ERROR_SURROGATEESCAPE: *surrogateescape = 1; return 0; default: return -1; } } PyObject * _Py_device_encoding(int fd) { int valid; Py_BEGIN_ALLOW_THREADS _Py_BEGIN_SUPPRESS_IPH valid = isatty(fd); _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS if (!valid) Py_RETURN_NONE; #ifdef MS_WINDOWS #ifdef HAVE_WINDOWS_CONSOLE_IO UINT cp; if (fd == 0) cp = GetConsoleCP(); else if (fd == 1 || fd == 2) cp = GetConsoleOutputCP(); else cp = 0; /* GetConsoleCP() and GetConsoleOutputCP() return 0 if the application has no console */ if (cp == 0) { Py_RETURN_NONE; } return PyUnicode_FromFormat("cp%u", (unsigned int)cp); #else Py_RETURN_NONE; #endif /* HAVE_WINDOWS_CONSOLE_IO */ #else if (_PyRuntime.preconfig.utf8_mode) { _Py_DECLARE_STR(utf_8, "utf-8"); return Py_NewRef(&_Py_STR(utf_8)); } return _Py_GetLocaleEncodingObject(); #endif } static int is_valid_wide_char(wchar_t ch) { #ifdef HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION /* Oracle Solaris doesn't use Unicode code points as wchar_t encoding for non-Unicode locales, which makes values higher than MAX_UNICODE possibly valid. */ return 1; #endif if (Py_UNICODE_IS_SURROGATE(ch)) { // Reject lone surrogate characters return 0; } if (ch > MAX_UNICODE) { // bpo-35883: Reject characters outside [U+0000; U+10ffff] range. // The glibc mbstowcs() UTF-8 decoder does not respect the RFC 3629, // it creates characters outside the [U+0000; U+10ffff] range: // https://sourceware.org/bugzilla/show_bug.cgi?id=2373 return 0; } return 1; } static size_t _Py_mbstowcs(wchar_t *dest, const char *src, size_t n) { size_t count = mbstowcs(dest, src, n); if (dest != NULL && count != DECODE_ERROR) { for (size_t i=0; i < count; i++) { wchar_t ch = dest[i]; if (!is_valid_wide_char(ch)) { return DECODE_ERROR; } } } return count; } #ifdef HAVE_MBRTOWC static size_t _Py_mbrtowc(wchar_t *pwc, const char *str, size_t len, mbstate_t *pmbs) { assert(pwc != NULL); size_t count = mbrtowc(pwc, str, len, pmbs); if (count != 0 && count != DECODE_ERROR && count != INCOMPLETE_CHARACTER) { if (!is_valid_wide_char(*pwc)) { return DECODE_ERROR; } } return count; } #endif #if !defined(_Py_FORCE_UTF8_FS_ENCODING) && !defined(MS_WINDOWS) #define USE_FORCE_ASCII extern int _Py_normalize_encoding(const char *, char *, size_t); /* Workaround FreeBSD and OpenIndiana locale encoding issue with the C locale and POSIX locale. nl_langinfo(CODESET) announces an alias of the ASCII encoding, whereas mbstowcs() and wcstombs() functions use the ISO-8859-1 encoding. The problem is that os.fsencode() and os.fsdecode() use locale.getpreferredencoding() codec. For example, if command line arguments are decoded by mbstowcs() and encoded back by os.fsencode(), we get a UnicodeEncodeError instead of retrieving the original byte string. The workaround is enabled if setlocale(LC_CTYPE, NULL) returns "C", nl_langinfo(CODESET) announces "ascii" (or an alias to ASCII), and at least one byte in range 0x80-0xff can be decoded from the locale encoding. The workaround is also enabled on error, for example if getting the locale failed. On HP-UX with the C locale or the POSIX locale, nl_langinfo(CODESET) announces "roman8" but mbstowcs() uses Latin1 in practice. Force also the ASCII encoding in this case. Values of force_ascii: 1: the workaround is used: Py_EncodeLocale() uses encode_ascii_surrogateescape() and Py_DecodeLocale() uses decode_ascii() 0: the workaround is not used: Py_EncodeLocale() uses wcstombs() and Py_DecodeLocale() uses mbstowcs() -1: unknown, need to call check_force_ascii() to get the value */ #define force_ascii (_PyRuntime.fileutils.force_ascii) static int check_force_ascii(void) { char *loc = setlocale(LC_CTYPE, NULL); if (loc == NULL) { goto error; } if (strcmp(loc, "C") != 0 && strcmp(loc, "POSIX") != 0) { /* the LC_CTYPE locale is different than C and POSIX */ return 0; } #if defined(HAVE_LANGINFO_H) && defined(CODESET) const char *codeset = nl_langinfo(CODESET); if (!codeset || codeset[0] == '\0') { /* CODESET is not set or empty */ goto error; } char encoding[20]; /* longest name: "iso_646.irv_1991\0" */ if (!_Py_normalize_encoding(codeset, encoding, sizeof(encoding))) { goto error; } #ifdef __hpux if (strcmp(encoding, "roman8") == 0) { unsigned char ch; wchar_t wch; size_t res; ch = (unsigned char)0xA7; res = _Py_mbstowcs(&wch, (char*)&ch, 1); if (res != DECODE_ERROR && wch == L'\xA7') { /* On HP-UX with C locale or the POSIX locale, nl_langinfo(CODESET) announces "roman8", whereas mbstowcs() uses Latin1 encoding in practice. Force ASCII in this case. Roman8 decodes 0xA7 to U+00CF. Latin1 decodes 0xA7 to U+00A7. */ return 1; } } #else const char* ascii_aliases[] = { "ascii", /* Aliases from Lib/encodings/aliases.py */ "646", "ansi_x3.4_1968", "ansi_x3.4_1986", "ansi_x3_4_1968", "cp367", "csascii", "ibm367", "iso646_us", "iso_646.irv_1991", "iso_ir_6", "us", "us_ascii", NULL }; int is_ascii = 0; for (const char **alias=ascii_aliases; *alias != NULL; alias++) { if (strcmp(encoding, *alias) == 0) { is_ascii = 1; break; } } if (!is_ascii) { /* nl_langinfo(CODESET) is not "ascii" or an alias of ASCII */ return 0; } for (unsigned int i=0x80; i<=0xff; i++) { char ch[1]; wchar_t wch[1]; size_t res; unsigned uch = (unsigned char)i; ch[0] = (char)uch; res = _Py_mbstowcs(wch, ch, 1); if (res != DECODE_ERROR) { /* decoding a non-ASCII character from the locale encoding succeed: the locale encoding is not ASCII, force ASCII */ return 1; } } /* None of the bytes in the range 0x80-0xff can be decoded from the locale encoding: the locale encoding is really ASCII */ #endif /* !defined(__hpux) */ return 0; #else /* nl_langinfo(CODESET) is not available: always force ASCII */ return 1; #endif /* defined(HAVE_LANGINFO_H) && defined(CODESET) */ error: /* if an error occurred, force the ASCII encoding */ return 1; } int _Py_GetForceASCII(void) { if (force_ascii == -1) { force_ascii = check_force_ascii(); } return force_ascii; } void _Py_ResetForceASCII(void) { force_ascii = -1; } static int encode_ascii(const wchar_t *text, char **str, size_t *error_pos, const char **reason, int raw_malloc, _Py_error_handler errors) { char *result = NULL, *out; size_t len, i; wchar_t ch; int surrogateescape; if (get_surrogateescape(errors, &surrogateescape) < 0) { return -3; } len = wcslen(text); /* +1 for NULL byte */ if (raw_malloc) { result = PyMem_RawMalloc(len + 1); } else { result = PyMem_Malloc(len + 1); } if (result == NULL) { return -1; } out = result; for (i=0; i PY_SSIZE_T_MAX / sizeof(wchar_t)) { return -1; } res = PyMem_RawMalloc(argsize * sizeof(wchar_t)); if (!res) { return -1; } out = res; for (in = (unsigned char*)arg; *in; in++) { unsigned char ch = *in; if (ch < 128) { *out++ = ch; } else { if (!surrogateescape) { PyMem_RawFree(res); if (wlen) { *wlen = in - (unsigned char*)arg; } if (reason) { *reason = "decoding error"; } return -2; } *out++ = 0xdc00 + ch; } } *out = 0; if (wlen != NULL) { *wlen = out - res; } *wstr = res; return 0; } #endif /* !HAVE_MBRTOWC */ static int decode_current_locale(const char* arg, wchar_t **wstr, size_t *wlen, const char **reason, _Py_error_handler errors) { wchar_t *res; size_t argsize; size_t count; #ifdef HAVE_MBRTOWC unsigned char *in; wchar_t *out; mbstate_t mbs; #endif int surrogateescape; if (get_surrogateescape(errors, &surrogateescape) < 0) { return -3; } #ifdef HAVE_BROKEN_MBSTOWCS /* Some platforms have a broken implementation of * mbstowcs which does not count the characters that * would result from conversion. Use an upper bound. */ argsize = strlen(arg); #else argsize = _Py_mbstowcs(NULL, arg, 0); #endif if (argsize != DECODE_ERROR) { if (argsize > PY_SSIZE_T_MAX / sizeof(wchar_t) - 1) { return -1; } res = (wchar_t *)PyMem_RawMalloc((argsize + 1) * sizeof(wchar_t)); if (!res) { return -1; } count = _Py_mbstowcs(res, arg, argsize + 1); if (count != DECODE_ERROR) { *wstr = res; if (wlen != NULL) { *wlen = count; } return 0; } PyMem_RawFree(res); } /* Conversion failed. Fall back to escaping with surrogateescape. */ #ifdef HAVE_MBRTOWC /* Try conversion with mbrtwoc (C99), and escape non-decodable bytes. */ /* Overallocate; as multi-byte characters are in the argument, the actual output could use less memory. */ argsize = strlen(arg) + 1; if (argsize > PY_SSIZE_T_MAX / sizeof(wchar_t)) { return -1; } res = (wchar_t*)PyMem_RawMalloc(argsize * sizeof(wchar_t)); if (!res) { return -1; } in = (unsigned char*)arg; out = res; memset(&mbs, 0, sizeof mbs); while (argsize) { size_t converted = _Py_mbrtowc(out, (char*)in, argsize, &mbs); if (converted == 0) { /* Reached end of string; null char stored. */ break; } if (converted == INCOMPLETE_CHARACTER) { /* Incomplete character. This should never happen, since we provide everything that we have - unless there is a bug in the C library, or I misunderstood how mbrtowc works. */ goto decode_error; } if (converted == DECODE_ERROR) { if (!surrogateescape) { goto decode_error; } /* Decoding error. Escape as UTF-8b, and start over in the initial shift state. */ *out++ = 0xdc00 + *in++; argsize--; memset(&mbs, 0, sizeof mbs); continue; } // _Py_mbrtowc() reject lone surrogate characters assert(!Py_UNICODE_IS_SURROGATE(*out)); /* successfully converted some bytes */ in += converted; argsize -= converted; out++; } if (wlen != NULL) { *wlen = out - res; } *wstr = res; return 0; decode_error: PyMem_RawFree(res); if (wlen) { *wlen = in - (unsigned char*)arg; } if (reason) { *reason = "decoding error"; } return -2; #else /* HAVE_MBRTOWC */ /* Cannot use C locale for escaping; manually escape as if charset is ASCII (i.e. escape all bytes > 128. This will still roundtrip correctly in the locale's charset, which must be an ASCII superset. */ return decode_ascii(arg, wstr, wlen, reason, errors); #endif /* HAVE_MBRTOWC */ } /* Decode a byte string from the locale encoding. Use the strict error handler if 'surrogateescape' is zero. Use the surrogateescape error handler if 'surrogateescape' is non-zero: undecodable bytes are decoded as characters in range U+DC80..U+DCFF. If a byte sequence can be decoded as a surrogate character, escape the bytes using the surrogateescape error handler instead of decoding them. On success, return 0 and write the newly allocated wide character string into *wstr (use PyMem_RawFree() to free the memory). If wlen is not NULL, write the number of wide characters excluding the null character into *wlen. On memory allocation failure, return -1. On decoding error, return -2. If wlen is not NULL, write the start of invalid byte sequence in the input string into *wlen. If reason is not NULL, write the decoding error message into *reason. Return -3 if the error handler 'errors' is not supported. Use the Py_EncodeLocaleEx() function to encode the character string back to a byte string. */ int _Py_DecodeLocaleEx(const char* arg, wchar_t **wstr, size_t *wlen, const char **reason, int current_locale, _Py_error_handler errors) { if (current_locale) { #ifdef _Py_FORCE_UTF8_LOCALE return _Py_DecodeUTF8Ex(arg, strlen(arg), wstr, wlen, reason, errors); #else return decode_current_locale(arg, wstr, wlen, reason, errors); #endif } #ifdef _Py_FORCE_UTF8_FS_ENCODING return _Py_DecodeUTF8Ex(arg, strlen(arg), wstr, wlen, reason, errors); #else int use_utf8 = (_PyRuntime.preconfig.utf8_mode >= 1); #ifdef MS_WINDOWS use_utf8 |= (_PyRuntime.preconfig.legacy_windows_fs_encoding == 0); #endif if (use_utf8) { return _Py_DecodeUTF8Ex(arg, strlen(arg), wstr, wlen, reason, errors); } #ifdef USE_FORCE_ASCII if (force_ascii == -1) { force_ascii = check_force_ascii(); } if (force_ascii) { /* force ASCII encoding to workaround mbstowcs() issue */ return decode_ascii(arg, wstr, wlen, reason, errors); } #endif return decode_current_locale(arg, wstr, wlen, reason, errors); #endif /* !_Py_FORCE_UTF8_FS_ENCODING */ } /* Decode a byte string from the locale encoding with the surrogateescape error handler: undecodable bytes are decoded as characters in range U+DC80..U+DCFF. If a byte sequence can be decoded as a surrogate character, escape the bytes using the surrogateescape error handler instead of decoding them. Return a pointer to a newly allocated wide character string, use PyMem_RawFree() to free the memory. If size is not NULL, write the number of wide characters excluding the null character into *size Return NULL on decoding error or memory allocation error. If *size* is not NULL, *size is set to (size_t)-1 on memory error or set to (size_t)-2 on decoding error. Decoding errors should never happen, unless there is a bug in the C library. Use the Py_EncodeLocale() function to encode the character string back to a byte string. */ wchar_t* Py_DecodeLocale(const char* arg, size_t *wlen) { wchar_t *wstr; int res = _Py_DecodeLocaleEx(arg, &wstr, wlen, NULL, 0, _Py_ERROR_SURROGATEESCAPE); if (res != 0) { assert(res != -3); if (wlen != NULL) { *wlen = (size_t)res; } return NULL; } return wstr; } static int encode_current_locale(const wchar_t *text, char **str, size_t *error_pos, const char **reason, int raw_malloc, _Py_error_handler errors) { const size_t len = wcslen(text); char *result = NULL, *bytes = NULL; size_t i, size, converted; wchar_t c, buf[2]; int surrogateescape; if (get_surrogateescape(errors, &surrogateescape) < 0) { return -3; } /* The function works in two steps: 1. compute the length of the output buffer in bytes (size) 2. outputs the bytes */ size = 0; buf[1] = 0; while (1) { for (i=0; i < len; i++) { c = text[i]; if (c >= 0xdc80 && c <= 0xdcff) { if (!surrogateescape) { goto encode_error; } /* UTF-8b surrogate */ if (bytes != NULL) { *bytes++ = c - 0xdc00; size--; } else { size++; } continue; } else { buf[0] = c; if (bytes != NULL) { converted = wcstombs(bytes, buf, size); } else { converted = wcstombs(NULL, buf, 0); } if (converted == DECODE_ERROR) { goto encode_error; } if (bytes != NULL) { bytes += converted; size -= converted; } else { size += converted; } } } if (result != NULL) { *bytes = '\0'; break; } size += 1; /* nul byte at the end */ if (raw_malloc) { result = PyMem_RawMalloc(size); } else { result = PyMem_Malloc(size); } if (result == NULL) { return -1; } bytes = result; } *str = result; return 0; encode_error: if (raw_malloc) { PyMem_RawFree(result); } else { PyMem_Free(result); } if (error_pos != NULL) { *error_pos = i; } if (reason) { *reason = "encoding error"; } return -2; } /* Encode a string to the locale encoding. Parameters: * raw_malloc: if non-zero, allocate memory using PyMem_RawMalloc() instead of PyMem_Malloc(). * current_locale: if non-zero, use the current LC_CTYPE, otherwise use Python filesystem encoding. * errors: error handler like "strict" or "surrogateescape". Return value: 0: success, *str is set to a newly allocated decoded string. -1: memory allocation failure -2: encoding error, set *error_pos and *reason (if set). -3: the error handler 'errors' is not supported. */ static int encode_locale_ex(const wchar_t *text, char **str, size_t *error_pos, const char **reason, int raw_malloc, int current_locale, _Py_error_handler errors) { if (current_locale) { #ifdef _Py_FORCE_UTF8_LOCALE return _Py_EncodeUTF8Ex(text, str, error_pos, reason, raw_malloc, errors); #else return encode_current_locale(text, str, error_pos, reason, raw_malloc, errors); #endif } #ifdef _Py_FORCE_UTF8_FS_ENCODING return _Py_EncodeUTF8Ex(text, str, error_pos, reason, raw_malloc, errors); #else int use_utf8 = (_PyRuntime.preconfig.utf8_mode >= 1); #ifdef MS_WINDOWS use_utf8 |= (_PyRuntime.preconfig.legacy_windows_fs_encoding == 0); #endif if (use_utf8) { return _Py_EncodeUTF8Ex(text, str, error_pos, reason, raw_malloc, errors); } #ifdef USE_FORCE_ASCII if (force_ascii == -1) { force_ascii = check_force_ascii(); } if (force_ascii) { return encode_ascii(text, str, error_pos, reason, raw_malloc, errors); } #endif return encode_current_locale(text, str, error_pos, reason, raw_malloc, errors); #endif /* _Py_FORCE_UTF8_FS_ENCODING */ } static char* encode_locale(const wchar_t *text, size_t *error_pos, int raw_malloc, int current_locale) { char *str; int res = encode_locale_ex(text, &str, error_pos, NULL, raw_malloc, current_locale, _Py_ERROR_SURROGATEESCAPE); if (res != -2 && error_pos) { *error_pos = (size_t)-1; } if (res != 0) { return NULL; } return str; } /* Encode a wide character string to the locale encoding with the surrogateescape error handler: surrogate characters in the range U+DC80..U+DCFF are converted to bytes 0x80..0xFF. Return a pointer to a newly allocated byte string, use PyMem_Free() to free the memory. Return NULL on encoding or memory allocation error. If error_pos is not NULL, *error_pos is set to (size_t)-1 on success, or set to the index of the invalid character on encoding error. Use the Py_DecodeLocale() function to decode the bytes string back to a wide character string. */ char* Py_EncodeLocale(const wchar_t *text, size_t *error_pos) { return encode_locale(text, error_pos, 0, 0); } /* Similar to Py_EncodeLocale(), but result must be freed by PyMem_RawFree() instead of PyMem_Free(). */ char* _Py_EncodeLocaleRaw(const wchar_t *text, size_t *error_pos) { return encode_locale(text, error_pos, 1, 0); } int _Py_EncodeLocaleEx(const wchar_t *text, char **str, size_t *error_pos, const char **reason, int current_locale, _Py_error_handler errors) { return encode_locale_ex(text, str, error_pos, reason, 1, current_locale, errors); } // Get the current locale encoding name: // // - Return "utf-8" if _Py_FORCE_UTF8_LOCALE macro is defined (ex: on Android) // - Return "utf-8" if the UTF-8 Mode is enabled // - On Windows, return the ANSI code page (ex: "cp1250") // - Return "utf-8" if nl_langinfo(CODESET) returns an empty string. // - Otherwise, return nl_langinfo(CODESET). // // Return NULL on memory allocation failure. // // See also config_get_locale_encoding() wchar_t* _Py_GetLocaleEncoding(void) { #ifdef _Py_FORCE_UTF8_LOCALE // On Android langinfo.h and CODESET are missing, // and UTF-8 is always used in mbstowcs() and wcstombs(). return _PyMem_RawWcsdup(L"utf-8"); #else #ifdef MS_WINDOWS wchar_t encoding[23]; unsigned int ansi_codepage = GetACP(); swprintf(encoding, Py_ARRAY_LENGTH(encoding), L"cp%u", ansi_codepage); encoding[Py_ARRAY_LENGTH(encoding) - 1] = 0; return _PyMem_RawWcsdup(encoding); #else const char *encoding = nl_langinfo(CODESET); if (!encoding || encoding[0] == '\0') { // Use UTF-8 if nl_langinfo() returns an empty string. It can happen on // macOS if the LC_CTYPE locale is not supported. return _PyMem_RawWcsdup(L"utf-8"); } wchar_t *wstr; int res = decode_current_locale(encoding, &wstr, NULL, NULL, _Py_ERROR_SURROGATEESCAPE); if (res < 0) { return NULL; } return wstr; #endif // !MS_WINDOWS #endif // !_Py_FORCE_UTF8_LOCALE } PyObject * _Py_GetLocaleEncodingObject(void) { wchar_t *encoding = _Py_GetLocaleEncoding(); if (encoding == NULL) { PyErr_NoMemory(); return NULL; } PyObject *str = PyUnicode_FromWideChar(encoding, -1); PyMem_RawFree(encoding); return str; } #ifdef HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION /* Check whether current locale uses Unicode as internal wchar_t form. */ int _Py_LocaleUsesNonUnicodeWchar(void) { /* Oracle Solaris uses non-Unicode internal wchar_t form for non-Unicode locales and hence needs conversion to UTF first. */ char* codeset = nl_langinfo(CODESET); if (!codeset) { return 0; } /* 646 refers to ISO/IEC 646 standard that corresponds to ASCII encoding */ return (strcmp(codeset, "UTF-8") != 0 && strcmp(codeset, "646") != 0); } static wchar_t * _Py_ConvertWCharForm(const wchar_t *source, Py_ssize_t size, const char *tocode, const char *fromcode) { static_assert(sizeof(wchar_t) == 4, "wchar_t must be 32-bit"); /* Ensure we won't overflow the size. */ if (size > (PY_SSIZE_T_MAX / (Py_ssize_t)sizeof(wchar_t))) { PyErr_NoMemory(); return NULL; } /* the string doesn't have to be NULL terminated */ wchar_t* target = PyMem_Malloc(size * sizeof(wchar_t)); if (target == NULL) { PyErr_NoMemory(); return NULL; } iconv_t cd = iconv_open(tocode, fromcode); if (cd == (iconv_t)-1) { PyErr_Format(PyExc_ValueError, "iconv_open() failed"); PyMem_Free(target); return NULL; } char *inbuf = (char *) source; char *outbuf = (char *) target; size_t inbytesleft = sizeof(wchar_t) * size; size_t outbytesleft = inbytesleft; size_t ret = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); if (ret == DECODE_ERROR) { PyErr_Format(PyExc_ValueError, "iconv() failed"); PyMem_Free(target); iconv_close(cd); return NULL; } iconv_close(cd); return target; } /* Convert a wide character string to the UCS-4 encoded string. This is necessary on systems where internal form of wchar_t are not Unicode code points (e.g. Oracle Solaris). Return a pointer to a newly allocated string, use PyMem_Free() to free the memory. Return NULL and raise exception on conversion or memory allocation error. */ wchar_t * _Py_DecodeNonUnicodeWchar(const wchar_t *native, Py_ssize_t size) { return _Py_ConvertWCharForm(native, size, "UCS-4-INTERNAL", "wchar_t"); } /* Convert a UCS-4 encoded string to native wide character string. This is necessary on systems where internal form of wchar_t are not Unicode code points (e.g. Oracle Solaris). The conversion is done in place. This can be done because both wchar_t and UCS-4 use 4-byte encoding, and one wchar_t symbol always correspond to a single UCS-4 symbol and vice versa. (This is true for Oracle Solaris, which is currently the only system using these functions; it doesn't have to be for other systems). Return 0 on success. Return -1 and raise exception on conversion or memory allocation error. */ int _Py_EncodeNonUnicodeWchar_InPlace(wchar_t *unicode, Py_ssize_t size) { wchar_t* result = _Py_ConvertWCharForm(unicode, size, "wchar_t", "UCS-4-INTERNAL"); if (!result) { return -1; } memcpy(unicode, result, size * sizeof(wchar_t)); PyMem_Free(result); return 0; } #endif /* HAVE_NON_UNICODE_WCHAR_T_REPRESENTATION */ #ifdef MS_WINDOWS static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 and 1.1.1970 */ static void FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out) { /* XXX endianness. Shouldn't matter, as all Windows implementations are little-endian */ /* Cannot simply cast and dereference in_ptr, since it might not be aligned properly */ __int64 in; memcpy(&in, in_ptr, sizeof(in)); *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100 nsec. */ *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t); } static void LARGE_INTEGER_to_time_t_nsec(LARGE_INTEGER *in_ptr, time_t *time_out, int* nsec_out) { *nsec_out = (int)(in_ptr->QuadPart % 10000000) * 100; /* FILETIME is in units of 100 nsec. */ *time_out = Py_SAFE_DOWNCAST((in_ptr->QuadPart / 10000000) - secs_between_epochs, __int64, time_t); } void _Py_time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr) { /* XXX endianness */ __int64 out; out = time_in + secs_between_epochs; out = out * 10000000 + nsec_in / 100; memcpy(out_ptr, &out, sizeof(out)); } /* Below, we *know* that ugo+r is 0444 */ #if _S_IREAD != 0400 #error Unsupported C library #endif static int attributes_to_mode(DWORD attr) { int m = 0; if (attr & FILE_ATTRIBUTE_DIRECTORY) m |= _S_IFDIR | 0111; /* IFEXEC for user,group,other */ else m |= _S_IFREG; if (attr & FILE_ATTRIBUTE_READONLY) m |= 0444; else m |= 0666; return m; } typedef union { FILE_ID_128 id; struct { uint64_t st_ino; uint64_t st_ino_high; }; } id_128_to_ino; void _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, FILE_BASIC_INFO *basic_info, FILE_ID_INFO *id_info, struct _Py_stat_struct *result) { memset(result, 0, sizeof(*result)); result->st_mode = attributes_to_mode(info->dwFileAttributes); result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow; result->st_dev = id_info ? id_info->VolumeSerialNumber : info->dwVolumeSerialNumber; result->st_rdev = 0; /* st_ctime is deprecated, but we preserve the legacy value in our caller, not here */ if (basic_info) { LARGE_INTEGER_to_time_t_nsec(&basic_info->CreationTime, &result->st_birthtime, &result->st_birthtime_nsec); LARGE_INTEGER_to_time_t_nsec(&basic_info->ChangeTime, &result->st_ctime, &result->st_ctime_nsec); LARGE_INTEGER_to_time_t_nsec(&basic_info->LastWriteTime, &result->st_mtime, &result->st_mtime_nsec); LARGE_INTEGER_to_time_t_nsec(&basic_info->LastAccessTime, &result->st_atime, &result->st_atime_nsec); } else { FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_birthtime, &result->st_birthtime_nsec); FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); } result->st_nlink = info->nNumberOfLinks; if (id_info) { id_128_to_ino file_id; file_id.id = id_info->FileId; result->st_ino = file_id.st_ino; result->st_ino_high = file_id.st_ino_high; } if (!result->st_ino && !result->st_ino_high) { /* should only occur for DirEntry_from_find_data, in which case the index is likely to be zero anyway. */ result->st_ino = (((uint64_t)info->nFileIndexHigh) << 32) + info->nFileIndexLow; } /* bpo-37834: Only actual symlinks set the S_IFLNK flag. But lstat() will open other name surrogate reparse points without traversing them. To detect/handle these, check st_file_attributes and st_reparse_tag. */ result->st_reparse_tag = reparse_tag; if (info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && reparse_tag == IO_REPARSE_TAG_SYMLINK) { /* set the bits that make this a symlink */ result->st_mode = (result->st_mode & ~S_IFMT) | S_IFLNK; } result->st_file_attributes = info->dwFileAttributes; } void _Py_stat_basic_info_to_stat(FILE_STAT_BASIC_INFORMATION *info, struct _Py_stat_struct *result) { memset(result, 0, sizeof(*result)); result->st_mode = attributes_to_mode(info->FileAttributes); result->st_size = info->EndOfFile.QuadPart; LARGE_INTEGER_to_time_t_nsec(&info->CreationTime, &result->st_birthtime, &result->st_birthtime_nsec); LARGE_INTEGER_to_time_t_nsec(&info->ChangeTime, &result->st_ctime, &result->st_ctime_nsec); LARGE_INTEGER_to_time_t_nsec(&info->LastWriteTime, &result->st_mtime, &result->st_mtime_nsec); LARGE_INTEGER_to_time_t_nsec(&info->LastAccessTime, &result->st_atime, &result->st_atime_nsec); result->st_nlink = info->NumberOfLinks; result->st_dev = info->VolumeSerialNumber.QuadPart; /* File systems with less than 128-bits zero pad into this field */ id_128_to_ino file_id; file_id.id = info->FileId128; result->st_ino = file_id.st_ino; result->st_ino_high = file_id.st_ino_high; /* bpo-37834: Only actual symlinks set the S_IFLNK flag. But lstat() will open other name surrogate reparse points without traversing them. To detect/handle these, check st_file_attributes and st_reparse_tag. */ result->st_reparse_tag = info->ReparseTag; if (info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && info->ReparseTag == IO_REPARSE_TAG_SYMLINK) { /* set the bits that make this a symlink */ result->st_mode = (result->st_mode & ~S_IFMT) | S_IFLNK; } result->st_file_attributes = info->FileAttributes; switch (info->DeviceType) { case FILE_DEVICE_DISK: case FILE_DEVICE_VIRTUAL_DISK: case FILE_DEVICE_DFS: case FILE_DEVICE_CD_ROM: case FILE_DEVICE_CONTROLLER: case FILE_DEVICE_DATALINK: break; case FILE_DEVICE_DISK_FILE_SYSTEM: case FILE_DEVICE_CD_ROM_FILE_SYSTEM: case FILE_DEVICE_NETWORK_FILE_SYSTEM: result->st_mode = (result->st_mode & ~S_IFMT) | 0x6000; /* _S_IFBLK */ break; case FILE_DEVICE_CONSOLE: case FILE_DEVICE_NULL: case FILE_DEVICE_KEYBOARD: case FILE_DEVICE_MODEM: case FILE_DEVICE_MOUSE: case FILE_DEVICE_PARALLEL_PORT: case FILE_DEVICE_PRINTER: case FILE_DEVICE_SCREEN: case FILE_DEVICE_SERIAL_PORT: case FILE_DEVICE_SOUND: result->st_mode = (result->st_mode & ~S_IFMT) | _S_IFCHR; break; case FILE_DEVICE_NAMED_PIPE: result->st_mode = (result->st_mode & ~S_IFMT) | _S_IFIFO; break; default: if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { result->st_mode = (result->st_mode & ~S_IFMT) | _S_IFDIR; } break; } } #endif /* Return information about a file. On POSIX, use fstat(). On Windows, use GetFileType() and GetFileInformationByHandle() which support files larger than 2 GiB. fstat() may fail with EOVERFLOW on files larger than 2 GiB because the file size type is a signed 32-bit integer: see issue #23152. On Windows, set the last Windows error and return nonzero on error. On POSIX, set errno and return nonzero on error. Fill status and return 0 on success. */ int _Py_fstat_noraise(int fd, struct _Py_stat_struct *status) { #ifdef MS_WINDOWS BY_HANDLE_FILE_INFORMATION info; FILE_BASIC_INFO basicInfo; FILE_ID_INFO idInfo; HANDLE h; int type; h = _Py_get_osfhandle_noraise(fd); if (h == INVALID_HANDLE_VALUE) { /* errno is already set by _get_osfhandle, but we also set the Win32 error for callers who expect that */ SetLastError(ERROR_INVALID_HANDLE); return -1; } memset(status, 0, sizeof(*status)); type = GetFileType(h); if (type == FILE_TYPE_UNKNOWN) { DWORD error = GetLastError(); if (error != 0) { errno = winerror_to_errno(error); return -1; } /* else: valid but unknown file */ } if (type != FILE_TYPE_DISK) { if (type == FILE_TYPE_CHAR) status->st_mode = _S_IFCHR; else if (type == FILE_TYPE_PIPE) status->st_mode = _S_IFIFO; return 0; } if (!GetFileInformationByHandle(h, &info) || !GetFileInformationByHandleEx(h, FileBasicInfo, &basicInfo, sizeof(basicInfo)) || !GetFileInformationByHandleEx(h, FileIdInfo, &idInfo, sizeof(idInfo))) { /* The Win32 error is already set, but we also set errno for callers who expect it */ errno = winerror_to_errno(GetLastError()); return -1; } _Py_attribute_data_to_stat(&info, 0, &basicInfo, &idInfo, status); return 0; #else return fstat(fd, status); #endif } /* Return information about a file. On POSIX, use fstat(). On Windows, use GetFileType() and GetFileInformationByHandle() which support files larger than 2 GiB. fstat() may fail with EOVERFLOW on files larger than 2 GiB because the file size type is a signed 32-bit integer: see issue #23152. Raise an exception and return -1 on error. On Windows, set the last Windows error on error. On POSIX, set errno on error. Fill status and return 0 on success. Release the GIL to call GetFileType() and GetFileInformationByHandle(), or to call fstat(). The caller must hold the GIL. */ int _Py_fstat(int fd, struct _Py_stat_struct *status) { int res; assert(PyGILState_Check()); Py_BEGIN_ALLOW_THREADS res = _Py_fstat_noraise(fd, status); Py_END_ALLOW_THREADS if (res != 0) { #ifdef MS_WINDOWS PyErr_SetFromWindowsErr(0); #else PyErr_SetFromErrno(PyExc_OSError); #endif return -1; } return 0; } /* Like _Py_stat() but with a raw filename. */ int _Py_wstat(const wchar_t* path, struct stat *buf) { int err; #ifdef MS_WINDOWS struct _stat wstatbuf; err = _wstat(path, &wstatbuf); if (!err) { buf->st_mode = wstatbuf.st_mode; } #else char *fname; fname = _Py_EncodeLocaleRaw(path, NULL); if (fname == NULL) { errno = EINVAL; return -1; } err = stat(fname, buf); PyMem_RawFree(fname); #endif return err; } /* Call _wstat() on Windows, or encode the path to the filesystem encoding and call stat() otherwise. Only fill st_mode attribute on Windows. Return 0 on success, -1 on _wstat() / stat() error, -2 if an exception was raised. */ int _Py_stat(PyObject *path, struct stat *statbuf) { #ifdef MS_WINDOWS int err; wchar_t *wpath = PyUnicode_AsWideCharString(path, NULL); if (wpath == NULL) return -2; err = _Py_wstat(wpath, statbuf); PyMem_Free(wpath); return err; #else int ret; PyObject *bytes; char *cpath; bytes = PyUnicode_EncodeFSDefault(path); if (bytes == NULL) return -2; /* check for embedded null bytes */ if (PyBytes_AsStringAndSize(bytes, &cpath, NULL) == -1) { Py_DECREF(bytes); return -2; } ret = stat(cpath, statbuf); Py_DECREF(bytes); return ret; #endif } #ifdef MS_WINDOWS // For some Windows API partitions, SetHandleInformation() is declared // but none of the handle flags are defined. #ifndef HANDLE_FLAG_INHERIT #define HANDLE_FLAG_INHERIT 0x00000001 #endif #endif /* This function MUST be kept async-signal-safe on POSIX when raise=0. */ static int get_inheritable(int fd, int raise) { #ifdef MS_WINDOWS HANDLE handle; DWORD flags; handle = _Py_get_osfhandle_noraise(fd); if (handle == INVALID_HANDLE_VALUE) { if (raise) PyErr_SetFromErrno(PyExc_OSError); return -1; } if (!GetHandleInformation(handle, &flags)) { if (raise) PyErr_SetFromWindowsErr(0); return -1; } return (flags & HANDLE_FLAG_INHERIT); #else int flags; flags = fcntl(fd, F_GETFD, 0); if (flags == -1) { if (raise) PyErr_SetFromErrno(PyExc_OSError); return -1; } return !(flags & FD_CLOEXEC); #endif } /* Get the inheritable flag of the specified file descriptor. Return 1 if the file descriptor can be inherited, 0 if it cannot, raise an exception and return -1 on error. */ int _Py_get_inheritable(int fd) { return get_inheritable(fd, 1); } /* This function MUST be kept async-signal-safe on POSIX when raise=0. */ static int set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works) { #ifdef MS_WINDOWS HANDLE handle; DWORD flags; #else #if defined(HAVE_SYS_IOCTL_H) && defined(FIOCLEX) && defined(FIONCLEX) static int ioctl_works = -1; int request; int err; #endif int flags, new_flags; int res; #endif /* atomic_flag_works can only be used to make the file descriptor non-inheritable */ assert(!(atomic_flag_works != NULL && inheritable)); if (atomic_flag_works != NULL && !inheritable) { if (*atomic_flag_works == -1) { int isInheritable = get_inheritable(fd, raise); if (isInheritable == -1) return -1; *atomic_flag_works = !isInheritable; } if (*atomic_flag_works) return 0; } #ifdef MS_WINDOWS handle = _Py_get_osfhandle_noraise(fd); if (handle == INVALID_HANDLE_VALUE) { if (raise) PyErr_SetFromErrno(PyExc_OSError); return -1; } if (inheritable) flags = HANDLE_FLAG_INHERIT; else flags = 0; if (!SetHandleInformation(handle, HANDLE_FLAG_INHERIT, flags)) { if (raise) PyErr_SetFromWindowsErr(0); return -1; } return 0; #else #if defined(HAVE_SYS_IOCTL_H) && defined(FIOCLEX) && defined(FIONCLEX) if (ioctl_works != 0 && raise != 0) { /* fast-path: ioctl() only requires one syscall */ /* caveat: raise=0 is an indicator that we must be async-signal-safe * thus avoid using ioctl() so we skip the fast-path. */ if (inheritable) request = FIONCLEX; else request = FIOCLEX; err = ioctl(fd, request, NULL); if (!err) { ioctl_works = 1; return 0; } #ifdef O_PATH if (errno == EBADF) { // bpo-44849: On Linux and FreeBSD, ioctl(FIOCLEX) fails with EBADF // on O_PATH file descriptors. Fall through to the fcntl() // implementation. } else #endif if (errno != ENOTTY && errno != EACCES) { if (raise) PyErr_SetFromErrno(PyExc_OSError); return -1; } else { /* Issue #22258: Here, ENOTTY means "Inappropriate ioctl for device". The ioctl is declared but not supported by the kernel. Remember that ioctl() doesn't work. It is the case on Illumos-based OS for example. Issue #27057: When SELinux policy disallows ioctl it will fail with EACCES. While FIOCLEX is safe operation it may be unavailable because ioctl was denied altogether. This can be the case on Android. */ ioctl_works = 0; } /* fallback to fcntl() if ioctl() does not work */ } #endif /* slow-path: fcntl() requires two syscalls */ flags = fcntl(fd, F_GETFD); if (flags < 0) { if (raise) PyErr_SetFromErrno(PyExc_OSError); return -1; } if (inheritable) { new_flags = flags & ~FD_CLOEXEC; } else { new_flags = flags | FD_CLOEXEC; } if (new_flags == flags) { /* FD_CLOEXEC flag already set/cleared: nothing to do */ return 0; } res = fcntl(fd, F_SETFD, new_flags); if (res < 0) { if (raise) PyErr_SetFromErrno(PyExc_OSError); return -1; } return 0; #endif } /* Make the file descriptor non-inheritable. Return 0 on success, set errno and return -1 on error. */ static int make_non_inheritable(int fd) { return set_inheritable(fd, 0, 0, NULL); } /* Set the inheritable flag of the specified file descriptor. On success: return 0, on error: raise an exception and return -1. If atomic_flag_works is not NULL: * if *atomic_flag_works==-1, check if the inheritable is set on the file descriptor: if yes, set *atomic_flag_works to 1, otherwise set to 0 and set the inheritable flag * if *atomic_flag_works==1: do nothing * if *atomic_flag_works==0: set inheritable flag to False Set atomic_flag_works to NULL if no atomic flag was used to create the file descriptor. atomic_flag_works can only be used to make a file descriptor non-inheritable: atomic_flag_works must be NULL if inheritable=1. */ int _Py_set_inheritable(int fd, int inheritable, int *atomic_flag_works) { return set_inheritable(fd, inheritable, 1, atomic_flag_works); } /* Same as _Py_set_inheritable() but on error, set errno and don't raise an exception. This function is async-signal-safe. */ int _Py_set_inheritable_async_safe(int fd, int inheritable, int *atomic_flag_works) { return set_inheritable(fd, inheritable, 0, atomic_flag_works); } static int _Py_open_impl(const char *pathname, int flags, int gil_held) { int fd; int async_err = 0; #ifndef MS_WINDOWS int *atomic_flag_works; #endif #ifdef MS_WINDOWS flags |= O_NOINHERIT; #elif defined(O_CLOEXEC) atomic_flag_works = &_Py_open_cloexec_works; flags |= O_CLOEXEC; #else atomic_flag_works = NULL; #endif if (gil_held) { PyObject *pathname_obj = PyUnicode_DecodeFSDefault(pathname); if (pathname_obj == NULL) { return -1; } if (PySys_Audit("open", "OOi", pathname_obj, Py_None, flags) < 0) { Py_DECREF(pathname_obj); return -1; } do { Py_BEGIN_ALLOW_THREADS fd = open(pathname, flags); Py_END_ALLOW_THREADS } while (fd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (async_err) { Py_DECREF(pathname_obj); return -1; } if (fd < 0) { PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError, pathname_obj, NULL); Py_DECREF(pathname_obj); return -1; } Py_DECREF(pathname_obj); } else { fd = open(pathname, flags); if (fd < 0) return -1; } #ifndef MS_WINDOWS if (set_inheritable(fd, 0, gil_held, atomic_flag_works) < 0) { close(fd); return -1; } #endif return fd; } /* Open a file with the specified flags (wrapper to open() function). Return a file descriptor on success. Raise an exception and return -1 on error. The file descriptor is created non-inheritable. When interrupted by a signal (open() fails with EINTR), retry the syscall, except if the Python signal handler raises an exception. Release the GIL to call open(). The caller must hold the GIL. */ int _Py_open(const char *pathname, int flags) { /* _Py_open() must be called with the GIL held. */ assert(PyGILState_Check()); return _Py_open_impl(pathname, flags, 1); } /* Open a file with the specified flags (wrapper to open() function). Return a file descriptor on success. Set errno and return -1 on error. The file descriptor is created non-inheritable. If interrupted by a signal, fail with EINTR. */ int _Py_open_noraise(const char *pathname, int flags) { return _Py_open_impl(pathname, flags, 0); } /* Open a file. Use _wfopen() on Windows, encode the path to the locale encoding and use fopen() otherwise. The file descriptor is created non-inheritable. If interrupted by a signal, fail with EINTR. */ FILE * _Py_wfopen(const wchar_t *path, const wchar_t *mode) { FILE *f; if (PySys_Audit("open", "uui", path, mode, 0) < 0) { return NULL; } #ifndef MS_WINDOWS char *cpath; char cmode[10]; size_t r; r = wcstombs(cmode, mode, 10); if (r == DECODE_ERROR || r >= 10) { errno = EINVAL; return NULL; } cpath = _Py_EncodeLocaleRaw(path, NULL); if (cpath == NULL) { return NULL; } f = fopen(cpath, cmode); PyMem_RawFree(cpath); #else f = _wfopen(path, mode); #endif if (f == NULL) return NULL; if (make_non_inheritable(fileno(f)) < 0) { fclose(f); return NULL; } return f; } /* Open a file. Call _wfopen() on Windows, or encode the path to the filesystem encoding and call fopen() otherwise. Return the new file object on success. Raise an exception and return NULL on error. The file descriptor is created non-inheritable. When interrupted by a signal (open() fails with EINTR), retry the syscall, except if the Python signal handler raises an exception. Release the GIL to call _wfopen() or fopen(). The caller must hold the GIL. */ FILE* _Py_fopen_obj(PyObject *path, const char *mode) { FILE *f; int async_err = 0; #ifdef MS_WINDOWS wchar_t wmode[10]; int usize; assert(PyGILState_Check()); if (PySys_Audit("open", "Osi", path, mode, 0) < 0) { return NULL; } if (!PyUnicode_Check(path)) { PyErr_Format(PyExc_TypeError, "str file path expected under Windows, got %R", Py_TYPE(path)); return NULL; } wchar_t *wpath = PyUnicode_AsWideCharString(path, NULL); if (wpath == NULL) return NULL; usize = MultiByteToWideChar(CP_ACP, 0, mode, -1, wmode, Py_ARRAY_LENGTH(wmode)); if (usize == 0) { PyErr_SetFromWindowsErr(0); PyMem_Free(wpath); return NULL; } do { Py_BEGIN_ALLOW_THREADS f = _wfopen(wpath, wmode); Py_END_ALLOW_THREADS } while (f == NULL && errno == EINTR && !(async_err = PyErr_CheckSignals())); PyMem_Free(wpath); #else PyObject *bytes; const char *path_bytes; assert(PyGILState_Check()); if (!PyUnicode_FSConverter(path, &bytes)) return NULL; path_bytes = PyBytes_AS_STRING(bytes); if (PySys_Audit("open", "Osi", path, mode, 0) < 0) { Py_DECREF(bytes); return NULL; } do { Py_BEGIN_ALLOW_THREADS f = fopen(path_bytes, mode); Py_END_ALLOW_THREADS } while (f == NULL && errno == EINTR && !(async_err = PyErr_CheckSignals())); Py_DECREF(bytes); #endif if (async_err) return NULL; if (f == NULL) { PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path); return NULL; } if (set_inheritable(fileno(f), 0, 1, NULL) < 0) { fclose(f); return NULL; } return f; } /* Read count bytes from fd into buf. On success, return the number of read bytes, it can be lower than count. If the current file offset is at or past the end of file, no bytes are read, and read() returns zero. On error, raise an exception, set errno and return -1. When interrupted by a signal (read() fails with EINTR), retry the syscall. If the Python signal handler raises an exception, the function returns -1 (the syscall is not retried). Release the GIL to call read(). The caller must hold the GIL. */ Py_ssize_t _Py_read(int fd, void *buf, size_t count) { Py_ssize_t n; int err; int async_err = 0; assert(PyGILState_Check()); /* _Py_read() must not be called with an exception set, otherwise the * caller may think that read() was interrupted by a signal and the signal * handler raised an exception. */ assert(!PyErr_Occurred()); if (count > _PY_READ_MAX) { count = _PY_READ_MAX; } _Py_BEGIN_SUPPRESS_IPH do { Py_BEGIN_ALLOW_THREADS errno = 0; #ifdef MS_WINDOWS _doserrno = 0; n = read(fd, buf, (int)count); // read() on a non-blocking empty pipe fails with EINVAL, which is // mapped from the Windows error code ERROR_NO_DATA. if (n < 0 && errno == EINVAL) { if (_doserrno == ERROR_NO_DATA) { errno = EAGAIN; } } #else n = read(fd, buf, count); #endif /* save/restore errno because PyErr_CheckSignals() * and PyErr_SetFromErrno() can modify it */ err = errno; Py_END_ALLOW_THREADS } while (n < 0 && err == EINTR && !(async_err = PyErr_CheckSignals())); _Py_END_SUPPRESS_IPH if (async_err) { /* read() was interrupted by a signal (failed with EINTR) * and the Python signal handler raised an exception */ errno = err; assert(errno == EINTR && PyErr_Occurred()); return -1; } if (n < 0) { PyErr_SetFromErrno(PyExc_OSError); errno = err; return -1; } return n; } static Py_ssize_t _Py_write_impl(int fd, const void *buf, size_t count, int gil_held) { Py_ssize_t n; int err; int async_err = 0; _Py_BEGIN_SUPPRESS_IPH #ifdef MS_WINDOWS if (count > 32767) { /* Issue #11395: the Windows console returns an error (12: not enough space error) on writing into stdout if stdout mode is binary and the length is greater than 66,000 bytes (or less, depending on heap usage). */ if (gil_held) { Py_BEGIN_ALLOW_THREADS if (isatty(fd)) { count = 32767; } Py_END_ALLOW_THREADS } else { if (isatty(fd)) { count = 32767; } } } #endif if (count > _PY_WRITE_MAX) { count = _PY_WRITE_MAX; } if (gil_held) { do { Py_BEGIN_ALLOW_THREADS errno = 0; #ifdef MS_WINDOWS // write() on a non-blocking pipe fails with ENOSPC on Windows if // the pipe lacks available space for the entire buffer. int c = (int)count; do { _doserrno = 0; n = write(fd, buf, c); if (n >= 0 || errno != ENOSPC || _doserrno != 0) { break; } errno = EAGAIN; c /= 2; } while (c > 0); #else n = write(fd, buf, count); #endif /* save/restore errno because PyErr_CheckSignals() * and PyErr_SetFromErrno() can modify it */ err = errno; Py_END_ALLOW_THREADS } while (n < 0 && err == EINTR && !(async_err = PyErr_CheckSignals())); } else { do { errno = 0; #ifdef MS_WINDOWS // write() on a non-blocking pipe fails with ENOSPC on Windows if // the pipe lacks available space for the entire buffer. int c = (int)count; do { _doserrno = 0; n = write(fd, buf, c); if (n >= 0 || errno != ENOSPC || _doserrno != 0) { break; } errno = EAGAIN; c /= 2; } while (c > 0); #else n = write(fd, buf, count); #endif err = errno; } while (n < 0 && err == EINTR); } _Py_END_SUPPRESS_IPH if (async_err) { /* write() was interrupted by a signal (failed with EINTR) and the Python signal handler raised an exception (if gil_held is nonzero). */ errno = err; assert(errno == EINTR && (!gil_held || PyErr_Occurred())); return -1; } if (n < 0) { if (gil_held) PyErr_SetFromErrno(PyExc_OSError); errno = err; return -1; } return n; } /* Write count bytes of buf into fd. On success, return the number of written bytes, it can be lower than count including 0. On error, raise an exception, set errno and return -1. When interrupted by a signal (write() fails with EINTR), retry the syscall. If the Python signal handler raises an exception, the function returns -1 (the syscall is not retried). Release the GIL to call write(). The caller must hold the GIL. */ Py_ssize_t _Py_write(int fd, const void *buf, size_t count) { assert(PyGILState_Check()); /* _Py_write() must not be called with an exception set, otherwise the * caller may think that write() was interrupted by a signal and the signal * handler raised an exception. */ assert(!PyErr_Occurred()); return _Py_write_impl(fd, buf, count, 1); } /* Write count bytes of buf into fd. * * On success, return the number of written bytes, it can be lower than count * including 0. On error, set errno and return -1. * * When interrupted by a signal (write() fails with EINTR), retry the syscall * without calling the Python signal handler. */ Py_ssize_t _Py_write_noraise(int fd, const void *buf, size_t count) { return _Py_write_impl(fd, buf, count, 0); } #ifdef HAVE_READLINK /* Read value of symbolic link. Encode the path to the locale encoding, decode the result from the locale encoding. Return -1 on encoding error, on readlink() error, if the internal buffer is too short, on decoding error, or if 'buf' is too short. */ int _Py_wreadlink(const wchar_t *path, wchar_t *buf, size_t buflen) { char *cpath; char cbuf[MAXPATHLEN]; size_t cbuf_len = Py_ARRAY_LENGTH(cbuf); wchar_t *wbuf; Py_ssize_t res; size_t r1; cpath = _Py_EncodeLocaleRaw(path, NULL); if (cpath == NULL) { errno = EINVAL; return -1; } res = readlink(cpath, cbuf, cbuf_len); PyMem_RawFree(cpath); if (res == -1) { return -1; } if ((size_t)res == cbuf_len) { errno = EINVAL; return -1; } cbuf[res] = '\0'; /* buf will be null terminated */ wbuf = Py_DecodeLocale(cbuf, &r1); if (wbuf == NULL) { errno = EINVAL; return -1; } /* wbuf must have space to store the trailing NUL character */ if (buflen <= r1) { PyMem_RawFree(wbuf); errno = EINVAL; return -1; } wcsncpy(buf, wbuf, buflen); PyMem_RawFree(wbuf); return (int)r1; } #endif #ifdef HAVE_REALPATH /* Return the canonicalized absolute pathname. Encode path to the locale encoding, decode the result from the locale encoding. Return NULL on encoding error, realpath() error, decoding error or if 'resolved_path' is too short. */ wchar_t* _Py_wrealpath(const wchar_t *path, wchar_t *resolved_path, size_t resolved_path_len) { char *cpath; char cresolved_path[MAXPATHLEN]; wchar_t *wresolved_path; char *res; size_t r; cpath = _Py_EncodeLocaleRaw(path, NULL); if (cpath == NULL) { errno = EINVAL; return NULL; } res = realpath(cpath, cresolved_path); PyMem_RawFree(cpath); if (res == NULL) return NULL; wresolved_path = Py_DecodeLocale(cresolved_path, &r); if (wresolved_path == NULL) { errno = EINVAL; return NULL; } /* wresolved_path must have space to store the trailing NUL character */ if (resolved_path_len <= r) { PyMem_RawFree(wresolved_path); errno = EINVAL; return NULL; } wcsncpy(resolved_path, wresolved_path, resolved_path_len); PyMem_RawFree(wresolved_path); return resolved_path; } #endif int _Py_isabs(const wchar_t *path) { #ifdef MS_WINDOWS const wchar_t *tail; HRESULT hr = PathCchSkipRoot(path, &tail); if (FAILED(hr) || path == tail) { return 0; } if (tail == &path[1] && (path[0] == SEP || path[0] == ALTSEP)) { // Exclude paths with leading SEP return 0; } if (tail == &path[2] && path[1] == L':') { // Exclude drive-relative paths (e.g. C:filename.ext) return 0; } return 1; #else return (path[0] == SEP); #endif } /* Get an absolute path. On error (ex: fail to get the current directory), return -1. On memory allocation failure, set *abspath_p to NULL and return 0. On success, return a newly allocated to *abspath_p to and return 0. The string must be freed by PyMem_RawFree(). */ int _Py_abspath(const wchar_t *path, wchar_t **abspath_p) { if (path[0] == '\0' || !wcscmp(path, L".")) { wchar_t cwd[MAXPATHLEN + 1]; cwd[Py_ARRAY_LENGTH(cwd) - 1] = 0; if (!_Py_wgetcwd(cwd, Py_ARRAY_LENGTH(cwd) - 1)) { /* unable to get the current directory */ return -1; } *abspath_p = _PyMem_RawWcsdup(cwd); return 0; } if (_Py_isabs(path)) { *abspath_p = _PyMem_RawWcsdup(path); return 0; } #ifdef MS_WINDOWS return _PyOS_getfullpathname(path, abspath_p); #else wchar_t cwd[MAXPATHLEN + 1]; cwd[Py_ARRAY_LENGTH(cwd) - 1] = 0; if (!_Py_wgetcwd(cwd, Py_ARRAY_LENGTH(cwd) - 1)) { /* unable to get the current directory */ return -1; } size_t cwd_len = wcslen(cwd); size_t path_len = wcslen(path); size_t len = cwd_len + 1 + path_len + 1; if (len <= (size_t)PY_SSIZE_T_MAX / sizeof(wchar_t)) { *abspath_p = PyMem_RawMalloc(len * sizeof(wchar_t)); } else { *abspath_p = NULL; } if (*abspath_p == NULL) { return 0; } wchar_t *abspath = *abspath_p; memcpy(abspath, cwd, cwd_len * sizeof(wchar_t)); abspath += cwd_len; *abspath = (wchar_t)SEP; abspath++; memcpy(abspath, path, path_len * sizeof(wchar_t)); abspath += path_len; *abspath = 0; return 0; #endif } // The Windows Games API family implements the PathCch* APIs in the Xbox OS, // but does not expose them yet. Load them dynamically until // 1) they are officially exposed // 2) we stop supporting older versions of the GDK which do not expose them #if defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP) HRESULT PathCchSkipRoot(const wchar_t *path, const wchar_t **rootEnd) { static int initialized = 0; typedef HRESULT(__stdcall *PPathCchSkipRoot) (PCWSTR pszPath, PCWSTR *ppszRootEnd); static PPathCchSkipRoot _PathCchSkipRoot; if (initialized == 0) { HMODULE pathapi = LoadLibraryExW(L"api-ms-win-core-path-l1-1-0.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); if (pathapi) { _PathCchSkipRoot = (PPathCchSkipRoot)GetProcAddress( pathapi, "PathCchSkipRoot"); } else { _PathCchSkipRoot = NULL; } initialized = 1; } if (!_PathCchSkipRoot) { return E_NOINTERFACE; } return _PathCchSkipRoot(path, rootEnd); } static HRESULT PathCchCombineEx(wchar_t *buffer, size_t bufsize, const wchar_t *dirname, const wchar_t *relfile, unsigned long flags) { static int initialized = 0; typedef HRESULT(__stdcall *PPathCchCombineEx) (PWSTR pszPathOut, size_t cchPathOut, PCWSTR pszPathIn, PCWSTR pszMore, unsigned long dwFlags); static PPathCchCombineEx _PathCchCombineEx; if (initialized == 0) { HMODULE pathapi = LoadLibraryExW(L"api-ms-win-core-path-l1-1-0.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); if (pathapi) { _PathCchCombineEx = (PPathCchCombineEx)GetProcAddress( pathapi, "PathCchCombineEx"); } else { _PathCchCombineEx = NULL; } initialized = 1; } if (!_PathCchCombineEx) { return E_NOINTERFACE; } return _PathCchCombineEx(buffer, bufsize, dirname, relfile, flags); } #endif /* defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP) */ // The caller must ensure "buffer" is big enough. static int join_relfile(wchar_t *buffer, size_t bufsize, const wchar_t *dirname, const wchar_t *relfile) { #ifdef MS_WINDOWS if (FAILED(PathCchCombineEx(buffer, bufsize, dirname, relfile, PATHCCH_ALLOW_LONG_PATHS))) { return -1; } #else assert(!_Py_isabs(relfile)); size_t dirlen = wcslen(dirname); size_t rellen = wcslen(relfile); size_t maxlen = bufsize - 1; if (maxlen > MAXPATHLEN || dirlen >= maxlen || rellen >= maxlen - dirlen) { return -1; } if (dirlen == 0) { // We do not add a leading separator. wcscpy(buffer, relfile); } else { if (dirname != buffer) { wcscpy(buffer, dirname); } size_t relstart = dirlen; if (dirlen > 1 && dirname[dirlen - 1] != SEP) { buffer[dirlen] = SEP; relstart += 1; } wcscpy(&buffer[relstart], relfile); } #endif return 0; } /* Join the two paths together, like os.path.join(). Return NULL if memory could not be allocated. The caller is responsible for calling PyMem_RawFree() on the result. */ wchar_t * _Py_join_relfile(const wchar_t *dirname, const wchar_t *relfile) { assert(dirname != NULL && relfile != NULL); #ifndef MS_WINDOWS assert(!_Py_isabs(relfile)); #endif size_t maxlen = wcslen(dirname) + 1 + wcslen(relfile); size_t bufsize = maxlen + 1; wchar_t *filename = PyMem_RawMalloc(bufsize * sizeof(wchar_t)); if (filename == NULL) { return NULL; } assert(wcslen(dirname) < MAXPATHLEN); assert(wcslen(relfile) < MAXPATHLEN - wcslen(dirname)); if (join_relfile(filename, bufsize, dirname, relfile) < 0) { PyMem_RawFree(filename); return NULL; } return filename; } /* Join the two paths together, like os.path.join(). dirname: the target buffer with the dirname already in place, including trailing NUL relfile: this must be a relative path bufsize: total allocated size of the buffer Return -1 if anything is wrong with the path lengths. */ int _Py_add_relfile(wchar_t *dirname, const wchar_t *relfile, size_t bufsize) { assert(dirname != NULL && relfile != NULL); assert(bufsize > 0); return join_relfile(dirname, bufsize, dirname, relfile); } size_t _Py_find_basename(const wchar_t *filename) { for (size_t i = wcslen(filename); i > 0; --i) { if (filename[i] == SEP) { return i + 1; } } return 0; } /* In-place path normalisation. Returns the start of the normalized path, which will be within the original buffer. Guaranteed to not make the path longer, and will not fail. 'size' is the length of the path, if known. If -1, the first null character will be assumed to be the end of the path. */ wchar_t * _Py_normpath(wchar_t *path, Py_ssize_t size) { assert(path != NULL); if (!path[0] || size == 0) { return path; } wchar_t *pEnd = size >= 0 ? &path[size] : NULL; wchar_t *p1 = path; // sequentially scanned address in the path wchar_t *p2 = path; // destination of a scanned character to be ljusted wchar_t *minP2 = path; // the beginning of the destination range wchar_t lastC = L'\0'; // the last ljusted character, p2[-1] in most cases #define IS_END(x) (pEnd ? (x) == pEnd : !*(x)) #ifdef ALTSEP #define IS_SEP(x) (*(x) == SEP || *(x) == ALTSEP) #else #define IS_SEP(x) (*(x) == SEP) #endif #define SEP_OR_END(x) (IS_SEP(x) || IS_END(x)) // Skip leading '.\' if (p1[0] == L'.' && IS_SEP(&p1[1])) { path = &path[2]; while (IS_SEP(path) && !IS_END(path)) { path++; } p1 = p2 = minP2 = path; lastC = SEP; } #ifdef MS_WINDOWS // Skip past drive segment and update minP2 else if (p1[0] && p1[1] == L':') { *p2++ = *p1++; *p2++ = *p1++; minP2 = p2; lastC = L':'; } // Skip past all \\-prefixed paths, including \\?\, \\.\, // and network paths, including the first segment. else if (IS_SEP(&p1[0]) && IS_SEP(&p1[1])) { int sepCount = 2; *p2++ = SEP; *p2++ = SEP; p1 += 2; for (; !IS_END(p1) && sepCount; ++p1) { if (IS_SEP(p1)) { --sepCount; *p2++ = lastC = SEP; } else { *p2++ = lastC = *p1; } } if (sepCount) { minP2 = p2; // Invalid path } else { minP2 = p2 - 1; // Absolute path has SEP at minP2 } } #else // Skip past two leading SEPs else if (IS_SEP(&p1[0]) && IS_SEP(&p1[1]) && !IS_SEP(&p1[2])) { *p2++ = *p1++; *p2++ = *p1++; minP2 = p2 - 1; // Absolute path has SEP at minP2 lastC = SEP; } #endif /* MS_WINDOWS */ /* if pEnd is specified, check that. Else, check for null terminator */ for (; !IS_END(p1); ++p1) { wchar_t c = *p1; #ifdef ALTSEP if (c == ALTSEP) { c = SEP; } #endif if (lastC == SEP) { if (c == L'.') { int sep_at_1 = SEP_OR_END(&p1[1]); int sep_at_2 = !sep_at_1 && SEP_OR_END(&p1[2]); if (sep_at_2 && p1[1] == L'.') { wchar_t *p3 = p2; while (p3 != minP2 && *--p3 == SEP) { } while (p3 != minP2 && *(p3 - 1) != SEP) { --p3; } if (p2 == minP2 || (p3[0] == L'.' && p3[1] == L'.' && IS_SEP(&p3[2]))) { // Previous segment is also ../, so append instead. // Relative path does not absorb ../ at minP2 as well. *p2++ = L'.'; *p2++ = L'.'; lastC = L'.'; } else if (p3[0] == SEP) { // Absolute path, so absorb segment p2 = p3 + 1; } else { p2 = p3; } p1 += 1; } else if (sep_at_1) { } else { *p2++ = lastC = c; } } else if (c == SEP) { } else { *p2++ = lastC = c; } } else { *p2++ = lastC = c; } } *p2 = L'\0'; if (p2 != minP2) { while (--p2 != minP2 && *p2 == SEP) { *p2 = L'\0'; } } #undef SEP_OR_END #undef IS_SEP #undef IS_END return path; } /* Get the current directory. buflen is the buffer size in wide characters including the null character. Decode the path from the locale encoding. Return NULL on getcwd() error, on decoding error, or if 'buf' is too short. */ wchar_t* _Py_wgetcwd(wchar_t *buf, size_t buflen) { #ifdef MS_WINDOWS int ibuflen = (int)Py_MIN(buflen, INT_MAX); return _wgetcwd(buf, ibuflen); #else char fname[MAXPATHLEN]; wchar_t *wname; size_t len; if (getcwd(fname, Py_ARRAY_LENGTH(fname)) == NULL) return NULL; wname = Py_DecodeLocale(fname, &len); if (wname == NULL) return NULL; /* wname must have space to store the trailing NUL character */ if (buflen <= len) { PyMem_RawFree(wname); return NULL; } wcsncpy(buf, wname, buflen); PyMem_RawFree(wname); return buf; #endif } /* Duplicate a file descriptor. The new file descriptor is created as non-inheritable. Return a new file descriptor on success, raise an OSError exception and return -1 on error. The GIL is released to call dup(). The caller must hold the GIL. */ int _Py_dup(int fd) { #ifdef MS_WINDOWS HANDLE handle; #endif assert(PyGILState_Check()); #ifdef MS_WINDOWS handle = _Py_get_osfhandle(fd); if (handle == INVALID_HANDLE_VALUE) return -1; Py_BEGIN_ALLOW_THREADS _Py_BEGIN_SUPPRESS_IPH fd = dup(fd); _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS if (fd < 0) { PyErr_SetFromErrno(PyExc_OSError); return -1; } if (_Py_set_inheritable(fd, 0, NULL) < 0) { _Py_BEGIN_SUPPRESS_IPH close(fd); _Py_END_SUPPRESS_IPH return -1; } #elif defined(HAVE_FCNTL_H) && defined(F_DUPFD_CLOEXEC) Py_BEGIN_ALLOW_THREADS _Py_BEGIN_SUPPRESS_IPH fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS if (fd < 0) { PyErr_SetFromErrno(PyExc_OSError); return -1; } #elif HAVE_DUP Py_BEGIN_ALLOW_THREADS _Py_BEGIN_SUPPRESS_IPH fd = dup(fd); _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS if (fd < 0) { PyErr_SetFromErrno(PyExc_OSError); return -1; } if (_Py_set_inheritable(fd, 0, NULL) < 0) { _Py_BEGIN_SUPPRESS_IPH close(fd); _Py_END_SUPPRESS_IPH return -1; } #else errno = ENOTSUP; PyErr_SetFromErrno(PyExc_OSError); return -1; #endif return fd; } #ifndef MS_WINDOWS /* Get the blocking mode of the file descriptor. Return 0 if the O_NONBLOCK flag is set, 1 if the flag is cleared, raise an exception and return -1 on error. */ int _Py_get_blocking(int fd) { int flags; _Py_BEGIN_SUPPRESS_IPH flags = fcntl(fd, F_GETFL, 0); _Py_END_SUPPRESS_IPH if (flags < 0) { PyErr_SetFromErrno(PyExc_OSError); return -1; } return !(flags & O_NONBLOCK); } /* Set the blocking mode of the specified file descriptor. Set the O_NONBLOCK flag if blocking is False, clear the O_NONBLOCK flag otherwise. Return 0 on success, raise an exception and return -1 on error. */ int _Py_set_blocking(int fd, int blocking) { /* bpo-41462: On VxWorks, ioctl(FIONBIO) only works on sockets. Use fcntl() instead. */ #if defined(HAVE_SYS_IOCTL_H) && defined(FIONBIO) && !defined(__VXWORKS__) int arg = !blocking; if (ioctl(fd, FIONBIO, &arg) < 0) goto error; #else int flags, res; _Py_BEGIN_SUPPRESS_IPH flags = fcntl(fd, F_GETFL, 0); if (flags >= 0) { if (blocking) flags = flags & (~O_NONBLOCK); else flags = flags | O_NONBLOCK; res = fcntl(fd, F_SETFL, flags); } else { res = -1; } _Py_END_SUPPRESS_IPH if (res < 0) goto error; #endif return 0; error: PyErr_SetFromErrno(PyExc_OSError); return -1; } #else /* MS_WINDOWS */ int _Py_get_blocking(int fd) { HANDLE handle; DWORD mode; BOOL success; handle = _Py_get_osfhandle(fd); if (handle == INVALID_HANDLE_VALUE) { return -1; } Py_BEGIN_ALLOW_THREADS success = GetNamedPipeHandleStateW(handle, &mode, NULL, NULL, NULL, NULL, 0); Py_END_ALLOW_THREADS if (!success) { PyErr_SetFromWindowsErr(0); return -1; } return !(mode & PIPE_NOWAIT); } int _Py_set_blocking(int fd, int blocking) { HANDLE handle; DWORD mode; BOOL success; handle = _Py_get_osfhandle(fd); if (handle == INVALID_HANDLE_VALUE) { return -1; } Py_BEGIN_ALLOW_THREADS success = GetNamedPipeHandleStateW(handle, &mode, NULL, NULL, NULL, NULL, 0); if (success) { if (blocking) { mode &= ~PIPE_NOWAIT; } else { mode |= PIPE_NOWAIT; } success = SetNamedPipeHandleState(handle, &mode, NULL, NULL); } Py_END_ALLOW_THREADS if (!success) { PyErr_SetFromWindowsErr(0); return -1; } return 0; } void* _Py_get_osfhandle_noraise(int fd) { void *handle; _Py_BEGIN_SUPPRESS_IPH handle = (void*)_get_osfhandle(fd); _Py_END_SUPPRESS_IPH return handle; } void* _Py_get_osfhandle(int fd) { void *handle = _Py_get_osfhandle_noraise(fd); if (handle == INVALID_HANDLE_VALUE) PyErr_SetFromErrno(PyExc_OSError); return handle; } int _Py_open_osfhandle_noraise(void *handle, int flags) { int fd; _Py_BEGIN_SUPPRESS_IPH fd = _open_osfhandle((intptr_t)handle, flags); _Py_END_SUPPRESS_IPH return fd; } int _Py_open_osfhandle(void *handle, int flags) { int fd = _Py_open_osfhandle_noraise(handle, flags); if (fd == -1) PyErr_SetFromErrno(PyExc_OSError); return fd; } #endif /* MS_WINDOWS */ int _Py_GetLocaleconvNumeric(struct lconv *lc, PyObject **decimal_point, PyObject **thousands_sep) { assert(decimal_point != NULL); assert(thousands_sep != NULL); #ifndef MS_WINDOWS int change_locale = 0; if ((strlen(lc->decimal_point) > 1 || ((unsigned char)lc->decimal_point[0]) > 127)) { change_locale = 1; } if ((strlen(lc->thousands_sep) > 1 || ((unsigned char)lc->thousands_sep[0]) > 127)) { change_locale = 1; } /* Keep a copy of the LC_CTYPE locale */ char *oldloc = NULL, *loc = NULL; if (change_locale) { oldloc = setlocale(LC_CTYPE, NULL); if (!oldloc) { PyErr_SetString(PyExc_RuntimeWarning, "failed to get LC_CTYPE locale"); return -1; } oldloc = _PyMem_Strdup(oldloc); if (!oldloc) { PyErr_NoMemory(); return -1; } loc = setlocale(LC_NUMERIC, NULL); if (loc != NULL && strcmp(loc, oldloc) == 0) { loc = NULL; } if (loc != NULL) { /* Only set the locale temporarily the LC_CTYPE locale if LC_NUMERIC locale is different than LC_CTYPE locale and decimal_point and/or thousands_sep are non-ASCII or longer than 1 byte */ setlocale(LC_CTYPE, loc); } } #define GET_LOCALE_STRING(ATTR) PyUnicode_DecodeLocale(lc->ATTR, NULL) #else /* MS_WINDOWS */ /* Use _W_* fields of Windows strcut lconv */ #define GET_LOCALE_STRING(ATTR) PyUnicode_FromWideChar(lc->_W_ ## ATTR, -1) #endif /* MS_WINDOWS */ int res = -1; *decimal_point = GET_LOCALE_STRING(decimal_point); if (*decimal_point == NULL) { goto done; } *thousands_sep = GET_LOCALE_STRING(thousands_sep); if (*thousands_sep == NULL) { goto done; } res = 0; done: #ifndef MS_WINDOWS if (loc != NULL) { setlocale(LC_CTYPE, oldloc); } PyMem_Free(oldloc); #endif return res; #undef GET_LOCALE_STRING } /* Our selection logic for which function to use is as follows: * 1. If close_range(2) is available, always prefer that; it's better for * contiguous ranges like this than fdwalk(3) which entails iterating over * the entire fd space and simply doing nothing for those outside the range. * 2. If closefrom(2) is available, we'll attempt to use that next if we're * closing up to sysconf(_SC_OPEN_MAX). * 2a. Fallback to fdwalk(3) if we're not closing up to sysconf(_SC_OPEN_MAX), * as that will be more performant if the range happens to have any chunk of * non-opened fd in the middle. * 2b. If fdwalk(3) isn't available, just do a plain close(2) loop. */ #ifdef __FreeBSD__ # define USE_CLOSEFROM #endif /* __FreeBSD__ */ #ifdef HAVE_FDWALK # define USE_FDWALK #endif /* HAVE_FDWALK */ #ifdef USE_FDWALK static int _fdwalk_close_func(void *lohi, int fd) { int lo = ((int *)lohi)[0]; int hi = ((int *)lohi)[1]; if (fd >= hi) { return 1; } else if (fd >= lo) { /* Ignore errors */ (void)close(fd); } return 0; } #endif /* USE_FDWALK */ /* Closes all file descriptors in [first, last], ignoring errors. */ void _Py_closerange(int first, int last) { first = Py_MAX(first, 0); _Py_BEGIN_SUPPRESS_IPH #ifdef HAVE_CLOSE_RANGE if (close_range(first, last, 0) == 0) { /* close_range() ignores errors when it closes file descriptors. * Possible reasons of an error return are lack of kernel support * or denial of the underlying syscall by a seccomp sandbox on Linux. * Fallback to other methods in case of any error. */ } else #endif /* HAVE_CLOSE_RANGE */ #ifdef USE_CLOSEFROM if (last >= sysconf(_SC_OPEN_MAX)) { /* Any errors encountered while closing file descriptors are ignored */ closefrom(first); } else #endif /* USE_CLOSEFROM */ #ifdef USE_FDWALK { int lohi[2]; lohi[0] = first; lohi[1] = last + 1; fdwalk(_fdwalk_close_func, lohi); } #else { for (int i = first; i <= last; i++) { /* Ignore errors */ (void)close(i); } } #endif /* USE_FDWALK */ _Py_END_SUPPRESS_IPH } ================================================ FILE: Flowgraph.c ================================================ #include #include "Python.h" #include "pycore_flowgraph.h" #include "pycore_compile.h" #include "pycore_pymem.h" // _PyMem_IsPtrFreed() #include "pycore_opcode_utils.h" #define NEED_OPCODE_METADATA #include "opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed #undef NEED_OPCODE_METADATA #undef SUCCESS #undef ERROR #define SUCCESS 0 #define ERROR -1 #define RETURN_IF_ERROR(X) \ if ((X) == -1) { \ return ERROR; \ } #define DEFAULT_BLOCK_SIZE 16 typedef _PyCompilerSrcLocation location; typedef _PyCfgJumpTargetLabel jump_target_label; typedef _PyCfgBasicblock basicblock; typedef _PyCfgBuilder cfg_builder; typedef _PyCfgInstruction cfg_instr; static const jump_target_label NO_LABEL = {-1}; #define SAME_LABEL(L1, L2) ((L1).id == (L2).id) #define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL))) static inline int is_block_push(cfg_instr *i) { return IS_BLOCK_PUSH_OPCODE(i->i_opcode); } static inline int is_jump(cfg_instr *i) { return IS_JUMP_OPCODE(i->i_opcode); } /* One arg*/ #define INSTR_SET_OP1(I, OP, ARG) \ do { \ assert(HAS_ARG(OP)); \ _PyCfgInstruction *_instr__ptr_ = (I); \ _instr__ptr_->i_opcode = (OP); \ _instr__ptr_->i_oparg = (ARG); \ } while (0); /* No args*/ #define INSTR_SET_OP0(I, OP) \ do { \ assert(!HAS_ARG(OP)); \ _PyCfgInstruction *_instr__ptr_ = (I); \ _instr__ptr_->i_opcode = (OP); \ _instr__ptr_->i_oparg = 0; \ } while (0); /***** Blocks *****/ /* Returns the offset of the next instruction in the current block's b_instr array. Resizes the b_instr as necessary. Returns -1 on failure. */ static int basicblock_next_instr(basicblock *b) { assert(b != NULL); RETURN_IF_ERROR( _PyCompile_EnsureArrayLargeEnough( b->b_iused + 1, (void**)&b->b_instr, &b->b_ialloc, DEFAULT_BLOCK_SIZE, sizeof(cfg_instr))); return b->b_iused++; } /* Allocate a new block and return a pointer to it. Returns NULL on error. */ static basicblock * cfg_builder_new_block(cfg_builder *g) { basicblock *b = (basicblock *)PyObject_Calloc(1, sizeof(basicblock)); if (b == NULL) { PyErr_NoMemory(); return NULL; } /* Extend the singly linked list of blocks with new block. */ b->b_list = g->g_block_list; g->g_block_list = b; b->b_label = NO_LABEL; return b; } static int basicblock_addop(basicblock *b, int opcode, int oparg, location loc) { assert(IS_WITHIN_OPCODE_RANGE(opcode)); assert(!IS_ASSEMBLER_OPCODE(opcode)); assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0); assert(0 <= oparg && oparg < (1 << 30)); int off = basicblock_next_instr(b); if (off < 0) { return ERROR; } cfg_instr *i = &b->b_instr[off]; i->i_opcode = opcode; i->i_oparg = oparg; i->i_target = NULL; i->i_loc = loc; return SUCCESS; } static inline int basicblock_append_instructions(basicblock *target, basicblock *source) { for (int i = 0; i < source->b_iused; i++) { int n = basicblock_next_instr(target); if (n < 0) { return ERROR; } target->b_instr[n] = source->b_instr[i]; } return SUCCESS; } static basicblock * copy_basicblock(cfg_builder *g, basicblock *block) { /* Cannot copy a block if it has a fallthrough, since * a block can only have one fallthrough predecessor. */ assert(BB_NO_FALLTHROUGH(block)); basicblock *result = cfg_builder_new_block(g); if (result == NULL) { return NULL; } if (basicblock_append_instructions(result, block) < 0) { return NULL; } return result; } int _PyBasicblock_InsertInstruction(basicblock *block, int pos, cfg_instr *instr) { RETURN_IF_ERROR(basicblock_next_instr(block)); for (int i = block->b_iused - 1; i > pos; i--) { block->b_instr[i] = block->b_instr[i-1]; } block->b_instr[pos] = *instr; return SUCCESS; } static int instr_size(cfg_instr *instruction) { return _PyCompile_InstrSize(instruction->i_opcode, instruction->i_oparg); } static int blocksize(basicblock *b) { int size = 0; for (int i = 0; i < b->b_iused; i++) { size += instr_size(&b->b_instr[i]); } return size; } /* For debugging purposes only */ #if 0 static void dump_instr(cfg_instr *i) { const char *jump = is_jump(i) ? "jump " : ""; char arg[128]; *arg = '\0'; if (HAS_ARG(i->i_opcode)) { sprintf(arg, "arg: %d ", i->i_oparg); } if (HAS_TARGET(i->i_opcode)) { sprintf(arg, "target: %p [%d] ", i->i_target, i->i_oparg); } fprintf(stderr, "line: %d, opcode: %d %s%s\n", i->i_loc.lineno, i->i_opcode, arg, jump); } static inline int basicblock_returns(const basicblock *b) { cfg_instr *last = _PyCfg_BasicblockLastInstr(b); return last && (last->i_opcode == RETURN_VALUE || last->i_opcode == RETURN_CONST); } static void dump_basicblock(const basicblock *b) { const char *b_return = basicblock_returns(b) ? "return " : ""; fprintf(stderr, "%d: [EH=%d CLD=%d WRM=%d NO_FT=%d %p] used: %d, depth: %d, offset: %d %s\n", b->b_label.id, b->b_except_handler, b->b_cold, b->b_warm, BB_NO_FALLTHROUGH(b), b, b->b_iused, b->b_startdepth, b->b_offset, b_return); if (b->b_instr) { int i; for (i = 0; i < b->b_iused; i++) { fprintf(stderr, " [%02d] ", i); dump_instr(b->b_instr + i); } } } void _PyCfgBuilder_DumpGraph(const basicblock *entryblock) { for (const basicblock *b = entryblock; b != NULL; b = b->b_next) { dump_basicblock(b); } } #endif /***** CFG construction and modification *****/ static basicblock * cfg_builder_use_next_block(cfg_builder *g, basicblock *block) { assert(block != NULL); g->g_curblock->b_next = block; g->g_curblock = block; return block; } cfg_instr * _PyCfg_BasicblockLastInstr(const basicblock *b) { assert(b->b_iused >= 0); if (b->b_iused > 0) { assert(b->b_instr != NULL); return &b->b_instr[b->b_iused - 1]; } return NULL; } static inline int basicblock_exits_scope(const basicblock *b) { cfg_instr *last = _PyCfg_BasicblockLastInstr(b); return last && IS_SCOPE_EXIT_OPCODE(last->i_opcode); } static bool cfg_builder_current_block_is_terminated(cfg_builder *g) { cfg_instr *last = _PyCfg_BasicblockLastInstr(g->g_curblock); if (last && IS_TERMINATOR_OPCODE(last->i_opcode)) { return true; } if (IS_LABEL(g->g_current_label)) { if (last || IS_LABEL(g->g_curblock->b_label)) { return true; } else { /* current block is empty, label it */ g->g_curblock->b_label = g->g_current_label; g->g_current_label = NO_LABEL; } } return false; } static int cfg_builder_maybe_start_new_block(cfg_builder *g) { if (cfg_builder_current_block_is_terminated(g)) { basicblock *b = cfg_builder_new_block(g); if (b == NULL) { return ERROR; } b->b_label = g->g_current_label; g->g_current_label = NO_LABEL; cfg_builder_use_next_block(g, b); } return SUCCESS; } #ifndef NDEBUG static bool cfg_builder_check(cfg_builder *g) { assert(g->g_entryblock->b_iused > 0); for (basicblock *block = g->g_block_list; block != NULL; block = block->b_list) { assert(!_PyMem_IsPtrFreed(block)); if (block->b_instr != NULL) { assert(block->b_ialloc > 0); assert(block->b_iused >= 0); assert(block->b_ialloc >= block->b_iused); } else { assert (block->b_iused == 0); assert (block->b_ialloc == 0); } } return true; } #endif int _PyCfgBuilder_Init(cfg_builder *g) { g->g_block_list = NULL; basicblock *block = cfg_builder_new_block(g); if (block == NULL) { return ERROR; } g->g_curblock = g->g_entryblock = block; g->g_current_label = NO_LABEL; return SUCCESS; } void _PyCfgBuilder_Fini(cfg_builder* g) { assert(cfg_builder_check(g)); basicblock *b = g->g_block_list; while (b != NULL) { if (b->b_instr) { PyObject_Free((void *)b->b_instr); } basicblock *next = b->b_list; PyObject_Free((void *)b); b = next; } } int _PyCfgBuilder_UseLabel(cfg_builder *g, jump_target_label lbl) { g->g_current_label = lbl; return cfg_builder_maybe_start_new_block(g); } int _PyCfgBuilder_Addop(cfg_builder *g, int opcode, int oparg, location loc) { RETURN_IF_ERROR(cfg_builder_maybe_start_new_block(g)); return basicblock_addop(g->g_curblock, opcode, oparg, loc); } /***** debugging helpers *****/ #ifndef NDEBUG static int remove_redundant_nops(basicblock *bb); static bool no_redundant_nops(cfg_builder *g) { for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { if (remove_redundant_nops(b) != 0) { return false; } } return true; } static bool no_empty_basic_blocks(cfg_builder *g) { for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { if (b->b_iused == 0) { return false; } } return true; } static bool no_redundant_jumps(cfg_builder *g) { for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { cfg_instr *last = _PyCfg_BasicblockLastInstr(b); if (last != NULL) { if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { assert(last->i_target != b->b_next); if (last->i_target == b->b_next) { return false; } } } } return true; } #endif /***** CFG preprocessing (jump targets and exceptions) *****/ static int normalize_jumps_in_block(cfg_builder *g, basicblock *b) { cfg_instr *last = _PyCfg_BasicblockLastInstr(b); if (last == NULL || !is_jump(last)) { return SUCCESS; } assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); bool is_forward = last->i_target->b_visited == 0; switch(last->i_opcode) { case JUMP: assert(SAME_OPCODE_METADATA(JUMP, JUMP_FORWARD)); assert(SAME_OPCODE_METADATA(JUMP, JUMP_BACKWARD)); last->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD; return SUCCESS; case JUMP_NO_INTERRUPT: assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_FORWARD)); assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_BACKWARD_NO_INTERRUPT)); last->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT; return SUCCESS; } int reversed_opcode = 0; switch(last->i_opcode) { case POP_JUMP_IF_NOT_NONE: reversed_opcode = POP_JUMP_IF_NONE; break; case POP_JUMP_IF_NONE: reversed_opcode = POP_JUMP_IF_NOT_NONE; break; case POP_JUMP_IF_FALSE: reversed_opcode = POP_JUMP_IF_TRUE; break; case POP_JUMP_IF_TRUE: reversed_opcode = POP_JUMP_IF_FALSE; break; } if (is_forward) { return SUCCESS; } /* transform 'conditional jump T' to * 'reversed_jump b_next' followed by 'jump_backwards T' */ basicblock *target = last->i_target; basicblock *backwards_jump = cfg_builder_new_block(g); if (backwards_jump == NULL) { return ERROR; } basicblock_addop(backwards_jump, JUMP, target->b_label.id, NO_LOCATION); backwards_jump->b_instr[0].i_target = target; last->i_opcode = reversed_opcode; last->i_target = b->b_next; backwards_jump->b_cold = b->b_cold; backwards_jump->b_next = b->b_next; b->b_next = backwards_jump; return SUCCESS; } static int normalize_jumps(_PyCfgBuilder *g) { basicblock *entryblock = g->g_entryblock; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { b->b_visited = 0; } for (basicblock *b = entryblock; b != NULL; b = b->b_next) { b->b_visited = 1; RETURN_IF_ERROR(normalize_jumps_in_block(g, b)); } return SUCCESS; } static void resolve_jump_offsets(basicblock *entryblock) { int bsize, totsize, extended_arg_recompile; /* Compute the size of each block and fixup jump args. Replace block pointer with position in bytecode. */ do { totsize = 0; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { bsize = blocksize(b); b->b_offset = totsize; totsize += bsize; } extended_arg_recompile = 0; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { bsize = b->b_offset; for (int i = 0; i < b->b_iused; i++) { cfg_instr *instr = &b->b_instr[i]; int isize = instr_size(instr); /* jump offsets are computed relative to * the instruction pointer after fetching * the jump instruction. */ bsize += isize; if (is_jump(instr)) { instr->i_oparg = instr->i_target->b_offset; if (instr->i_oparg < bsize) { assert(IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); instr->i_oparg = bsize - instr->i_oparg; } else { assert(!IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); instr->i_oparg -= bsize; } if (instr_size(instr) != isize) { extended_arg_recompile = 1; } } } } /* XXX: This is an awful hack that could hurt performance, but on the bright side it should work until we come up with a better solution. The issue is that in the first loop blocksize() is called which calls instr_size() which requires i_oparg be set appropriately. There is a bootstrap problem because i_oparg is calculated in the second loop above. So we loop until we stop seeing new EXTENDED_ARGs. The only EXTENDED_ARGs that could be popping up are ones in jump instructions. So this should converge fairly quickly. */ } while (extended_arg_recompile); } int _PyCfg_ResolveJumps(_PyCfgBuilder *g) { RETURN_IF_ERROR(normalize_jumps(g)); assert(no_redundant_jumps(g)); resolve_jump_offsets(g->g_entryblock); return SUCCESS; } static int check_cfg(cfg_builder *g) { for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { /* Raise SystemError if jump or exit is not last instruction in the block. */ for (int i = 0; i < b->b_iused; i++) { int opcode = b->b_instr[i].i_opcode; assert(!IS_ASSEMBLER_OPCODE(opcode)); if (IS_TERMINATOR_OPCODE(opcode)) { if (i != b->b_iused - 1) { PyErr_SetString(PyExc_SystemError, "malformed control flow graph."); return ERROR; } } } } return SUCCESS; } /* Calculate the actual jump target from the target_label */ static int translate_jump_labels_to_targets(basicblock *entryblock) { int max_label = -1; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { if (b->b_label.id > max_label) { max_label = b->b_label.id; } } size_t mapsize = sizeof(basicblock *) * (max_label + 1); basicblock **label2block = (basicblock **)PyMem_Malloc(mapsize); if (!label2block) { PyErr_NoMemory(); return ERROR; } memset(label2block, 0, mapsize); for (basicblock *b = entryblock; b != NULL; b = b->b_next) { if (b->b_label.id >= 0) { label2block[b->b_label.id] = b; } } for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { cfg_instr *instr = &b->b_instr[i]; assert(instr->i_target == NULL); if (HAS_TARGET(instr->i_opcode)) { int lbl = instr->i_oparg; assert(lbl >= 0 && lbl <= max_label); instr->i_target = label2block[lbl]; assert(instr->i_target != NULL); assert(instr->i_target->b_label.id == lbl); } } } PyMem_Free(label2block); return SUCCESS; } int _PyCfg_JumpLabelsToTargets(basicblock *entryblock) { return translate_jump_labels_to_targets(entryblock); } static int mark_except_handlers(basicblock *entryblock) { #ifndef NDEBUG for (basicblock *b = entryblock; b != NULL; b = b->b_next) { assert(!b->b_except_handler); } #endif for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i=0; i < b->b_iused; i++) { cfg_instr *instr = &b->b_instr[i]; if (is_block_push(instr)) { instr->i_target->b_except_handler = 1; } } } return SUCCESS; } typedef _PyCfgExceptStack ExceptStack; static basicblock * push_except_block(ExceptStack *stack, cfg_instr *setup) { assert(is_block_push(setup)); int opcode = setup->i_opcode; basicblock * target = setup->i_target; if (opcode == SETUP_WITH || opcode == SETUP_CLEANUP) { target->b_preserve_lasti = 1; } stack->handlers[++stack->depth] = target; return target; } static basicblock * pop_except_block(ExceptStack *stack) { assert(stack->depth > 0); return stack->handlers[--stack->depth]; } static basicblock * except_stack_top(ExceptStack *stack) { return stack->handlers[stack->depth]; } static ExceptStack * make_except_stack(void) { ExceptStack *new = PyMem_Malloc(sizeof(ExceptStack)); if (new == NULL) { PyErr_NoMemory(); return NULL; } new->depth = 0; new->handlers[0] = NULL; return new; } static ExceptStack * copy_except_stack(ExceptStack *stack) { ExceptStack *copy = PyMem_Malloc(sizeof(ExceptStack)); if (copy == NULL) { PyErr_NoMemory(); return NULL; } memcpy(copy, stack, sizeof(ExceptStack)); return copy; } static basicblock** make_cfg_traversal_stack(basicblock *entryblock) { int nblocks = 0; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { b->b_visited = 0; nblocks++; } basicblock **stack = (basicblock **)PyMem_Malloc(sizeof(basicblock *) * nblocks); if (!stack) { PyErr_NoMemory(); } return stack; } Py_LOCAL_INLINE(void) stackdepth_push(basicblock ***sp, basicblock *b, int depth) { assert(b->b_startdepth < 0 || b->b_startdepth == depth); if (b->b_startdepth < depth && b->b_startdepth < 100) { assert(b->b_startdepth < 0); b->b_startdepth = depth; *(*sp)++ = b; } } /* Find the flow path that needs the largest stack. We assume that * cycles in the flow graph have no net effect on the stack depth. */ int _PyCfg_Stackdepth(basicblock *entryblock, int code_flags) { for (basicblock *b = entryblock; b != NULL; b = b->b_next) { b->b_startdepth = INT_MIN; } basicblock **stack = make_cfg_traversal_stack(entryblock); if (!stack) { return ERROR; } int maxdepth = 0; basicblock **sp = stack; if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { stackdepth_push(&sp, entryblock, 1); } else { stackdepth_push(&sp, entryblock, 0); } while (sp != stack) { basicblock *b = *--sp; int depth = b->b_startdepth; assert(depth >= 0); basicblock *next = b->b_next; for (int i = 0; i < b->b_iused; i++) { cfg_instr *instr = &b->b_instr[i]; int effect = PyCompile_OpcodeStackEffectWithJump(instr->i_opcode, instr->i_oparg, 0); if (effect == PY_INVALID_STACK_EFFECT) { PyErr_Format(PyExc_SystemError, "compiler PyCompile_OpcodeStackEffectWithJump(opcode=%d, arg=%i) failed", instr->i_opcode, instr->i_oparg); return ERROR; } int new_depth = depth + effect; assert(new_depth >= 0); /* invalid code or bug in stackdepth() */ if (new_depth > maxdepth) { maxdepth = new_depth; } if (HAS_TARGET(instr->i_opcode)) { effect = PyCompile_OpcodeStackEffectWithJump(instr->i_opcode, instr->i_oparg, 1); assert(effect != PY_INVALID_STACK_EFFECT); int target_depth = depth + effect; assert(target_depth >= 0); /* invalid code or bug in stackdepth() */ if (target_depth > maxdepth) { maxdepth = target_depth; } stackdepth_push(&sp, instr->i_target, target_depth); } depth = new_depth; assert(!IS_ASSEMBLER_OPCODE(instr->i_opcode)); if (IS_UNCONDITIONAL_JUMP_OPCODE(instr->i_opcode) || IS_SCOPE_EXIT_OPCODE(instr->i_opcode)) { /* remaining code is dead */ next = NULL; break; } } if (next != NULL) { assert(BB_HAS_FALLTHROUGH(b)); stackdepth_push(&sp, next, depth); } } PyMem_Free(stack); return maxdepth; } static int label_exception_targets(basicblock *entryblock) { basicblock **todo_stack = make_cfg_traversal_stack(entryblock); if (todo_stack == NULL) { return ERROR; } ExceptStack *except_stack = make_except_stack(); if (except_stack == NULL) { PyMem_Free(todo_stack); PyErr_NoMemory(); return ERROR; } except_stack->depth = 0; todo_stack[0] = entryblock; entryblock->b_visited = 1; entryblock->b_exceptstack = except_stack; basicblock **todo = &todo_stack[1]; basicblock *handler = NULL; while (todo > todo_stack) { todo--; basicblock *b = todo[0]; assert(b->b_visited == 1); except_stack = b->b_exceptstack; assert(except_stack != NULL); b->b_exceptstack = NULL; handler = except_stack_top(except_stack); for (int i = 0; i < b->b_iused; i++) { cfg_instr *instr = &b->b_instr[i]; if (is_block_push(instr)) { if (!instr->i_target->b_visited) { ExceptStack *copy = copy_except_stack(except_stack); if (copy == NULL) { goto error; } instr->i_target->b_exceptstack = copy; todo[0] = instr->i_target; instr->i_target->b_visited = 1; todo++; } handler = push_except_block(except_stack, instr); } else if (instr->i_opcode == POP_BLOCK) { handler = pop_except_block(except_stack); } else if (is_jump(instr)) { instr->i_except = handler; assert(i == b->b_iused -1); if (!instr->i_target->b_visited) { if (BB_HAS_FALLTHROUGH(b)) { ExceptStack *copy = copy_except_stack(except_stack); if (copy == NULL) { goto error; } instr->i_target->b_exceptstack = copy; } else { instr->i_target->b_exceptstack = except_stack; except_stack = NULL; } todo[0] = instr->i_target; instr->i_target->b_visited = 1; todo++; } } else { if (instr->i_opcode == YIELD_VALUE) { instr->i_oparg = except_stack->depth; } instr->i_except = handler; } } if (BB_HAS_FALLTHROUGH(b) && !b->b_next->b_visited) { assert(except_stack != NULL); b->b_next->b_exceptstack = except_stack; todo[0] = b->b_next; b->b_next->b_visited = 1; todo++; } else if (except_stack != NULL) { PyMem_Free(except_stack); } } #ifdef Py_DEBUG for (basicblock *b = entryblock; b != NULL; b = b->b_next) { assert(b->b_exceptstack == NULL); } #endif PyMem_Free(todo_stack); return SUCCESS; error: PyMem_Free(todo_stack); PyMem_Free(except_stack); return ERROR; } /***** CFG optimizations *****/ static int mark_reachable(basicblock *entryblock) { basicblock **stack = make_cfg_traversal_stack(entryblock); if (stack == NULL) { return ERROR; } basicblock **sp = stack; entryblock->b_predecessors = 1; *sp++ = entryblock; while (sp > stack) { basicblock *b = *(--sp); b->b_visited = 1; if (b->b_next && BB_HAS_FALLTHROUGH(b)) { if (!b->b_next->b_visited) { assert(b->b_next->b_predecessors == 0); *sp++ = b->b_next; } b->b_next->b_predecessors++; } for (int i = 0; i < b->b_iused; i++) { basicblock *target; cfg_instr *instr = &b->b_instr[i]; if (is_jump(instr) || is_block_push(instr)) { target = instr->i_target; if (!target->b_visited) { assert(target->b_predecessors == 0 || target == b->b_next); *sp++ = target; } target->b_predecessors++; } } } PyMem_Free(stack); return SUCCESS; } static void eliminate_empty_basic_blocks(cfg_builder *g) { /* Eliminate empty blocks */ for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { basicblock *next = b->b_next; while (next && next->b_iused == 0) { next = next->b_next; } b->b_next = next; } while(g->g_entryblock && g->g_entryblock->b_iused == 0) { g->g_entryblock = g->g_entryblock->b_next; } for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { assert(b->b_iused > 0); for (int i = 0; i < b->b_iused; i++) { cfg_instr *instr = &b->b_instr[i]; if (HAS_TARGET(instr->i_opcode)) { basicblock *target = instr->i_target; while (target->b_iused == 0) { target = target->b_next; } instr->i_target = target; assert(instr->i_target && instr->i_target->b_iused > 0); } } } } static int remove_redundant_nops(basicblock *bb) { /* Remove NOPs when legal to do so. */ int dest = 0; int prev_lineno = -1; for (int src = 0; src < bb->b_iused; src++) { int lineno = bb->b_instr[src].i_loc.lineno; if (bb->b_instr[src].i_opcode == NOP) { /* Eliminate no-op if it doesn't have a line number */ if (lineno < 0) { continue; } /* or, if the previous instruction had the same line number. */ if (prev_lineno == lineno) { continue; } /* or, if the next instruction has same line number or no line number */ if (src < bb->b_iused - 1) { int next_lineno = bb->b_instr[src+1].i_loc.lineno; if (next_lineno == lineno) { continue; } if (next_lineno < 0) { bb->b_instr[src+1].i_loc = bb->b_instr[src].i_loc; continue; } } else { basicblock* next = bb->b_next; while (next && next->b_iused == 0) { next = next->b_next; } /* or if last instruction in BB and next BB has same line number */ if (next) { if (lineno == next->b_instr[0].i_loc.lineno) { continue; } } } } if (dest != src) { bb->b_instr[dest] = bb->b_instr[src]; } dest++; prev_lineno = lineno; } assert(dest <= bb->b_iused); int num_removed = bb->b_iused - dest; bb->b_iused = dest; return num_removed; } static int remove_redundant_nops_and_pairs(basicblock *entryblock) { bool done = false; while (! done) { done = true; cfg_instr *prev_instr = NULL; cfg_instr *instr = NULL; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { remove_redundant_nops(b); if (IS_LABEL(b->b_label)) { /* this block is a jump target, forget instr */ instr = NULL; } for (int i = 0; i < b->b_iused; i++) { prev_instr = instr; instr = &b->b_instr[i]; int prev_opcode = prev_instr ? prev_instr->i_opcode : 0; int prev_oparg = prev_instr ? prev_instr->i_oparg : 0; int opcode = instr->i_opcode; bool is_redundant_pair = false; if (opcode == POP_TOP) { if (prev_opcode == LOAD_CONST) { is_redundant_pair = true; } else if (prev_opcode == COPY && prev_oparg == 1) { is_redundant_pair = true; } } if (is_redundant_pair) { INSTR_SET_OP0(prev_instr, NOP); INSTR_SET_OP0(instr, NOP); done = false; } } if ((instr && is_jump(instr)) || !BB_HAS_FALLTHROUGH(b)) { instr = NULL; } } } return SUCCESS; } static int remove_redundant_jumps(cfg_builder *g) { /* If a non-empty block ends with a jump instruction, check if the next * non-empty block reached through normal flow control is the target * of that jump. If it is, then the jump instruction is redundant and * can be deleted. */ assert(no_empty_basic_blocks(g)); for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { cfg_instr *last = _PyCfg_BasicblockLastInstr(b); assert(last != NULL); assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { if (last->i_target == NULL) { PyErr_SetString(PyExc_SystemError, "jump with NULL target"); return ERROR; } if (last->i_target == b->b_next) { assert(b->b_next->b_iused); INSTR_SET_OP0(last, NOP); } } } return SUCCESS; } /* Maximum size of basic block that should be copied in optimizer */ #define MAX_COPY_SIZE 4 /* If this block ends with an unconditional jump to a small exit block, then * remove the jump and extend this block with the target. * Returns 1 if extended, 0 if no change, and -1 on error. */ static int inline_small_exit_blocks(basicblock *bb) { cfg_instr *last = _PyCfg_BasicblockLastInstr(bb); if (last == NULL) { return 0; } if (!IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { return 0; } basicblock *target = last->i_target; if (basicblock_exits_scope(target) && target->b_iused <= MAX_COPY_SIZE) { INSTR_SET_OP0(last, NOP); RETURN_IF_ERROR(basicblock_append_instructions(bb, target)); return 1; } return 0; } // Attempt to eliminate jumps to jumps by updating inst to jump to // target->i_target using the provided opcode. Return whether or not the // optimization was successful. static bool jump_thread(cfg_instr *inst, cfg_instr *target, int opcode) { assert(is_jump(inst)); assert(is_jump(target)); // bpo-45773: If inst->i_target == target->i_target, then nothing actually // changes (and we fall into an infinite loop): if ((inst->i_loc.lineno == target->i_loc.lineno || target->i_loc.lineno == -1) && inst->i_target != target->i_target) { inst->i_target = target->i_target; inst->i_opcode = opcode; return true; } return false; } static PyObject* get_const_value(int opcode, int oparg, PyObject *co_consts) { PyObject *constant = NULL; assert(HAS_CONST(opcode)); if (opcode == LOAD_CONST) { constant = PyList_GET_ITEM(co_consts, oparg); } if (constant == NULL) { PyErr_SetString(PyExc_SystemError, "Internal error: failed to get value of a constant"); return NULL; } return Py_NewRef(constant); } /* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n with LOAD_CONST (c1, c2, ... cn). The consts table must still be in list form so that the new constant (c1, c2, ... cn) can be appended. Called with codestr pointing to the first LOAD_CONST. */ static int fold_tuple_on_constants(PyObject *const_cache, cfg_instr *inst, int n, PyObject *consts) { /* Pre-conditions */ assert(PyDict_CheckExact(const_cache)); assert(PyList_CheckExact(consts)); assert(inst[n].i_opcode == BUILD_TUPLE); assert(inst[n].i_oparg == n); for (int i = 0; i < n; i++) { if (!HAS_CONST(inst[i].i_opcode)) { return SUCCESS; } } /* Buildup new tuple of constants */ PyObject *newconst = PyTuple_New(n); if (newconst == NULL) { return ERROR; } for (int i = 0; i < n; i++) { int op = inst[i].i_opcode; int arg = inst[i].i_oparg; PyObject *constant = get_const_value(op, arg, consts); if (constant == NULL) { return ERROR; } PyTuple_SET_ITEM(newconst, i, constant); } if (_PyCompile_ConstCacheMergeOne(const_cache, &newconst) < 0) { Py_DECREF(newconst); return ERROR; } Py_ssize_t index; for (index = 0; index < PyList_GET_SIZE(consts); index++) { if (PyList_GET_ITEM(consts, index) == newconst) { break; } } if (index == PyList_GET_SIZE(consts)) { if ((size_t)index >= (size_t)INT_MAX - 1) { Py_DECREF(newconst); PyErr_SetString(PyExc_OverflowError, "too many constants"); return ERROR; } if (PyList_Append(consts, newconst)) { Py_DECREF(newconst); return ERROR; } } Py_DECREF(newconst); for (int i = 0; i < n; i++) { INSTR_SET_OP0(&inst[i], NOP); } INSTR_SET_OP1(&inst[n], LOAD_CONST, (int)index); return SUCCESS; } #define VISITED (-1) // Replace an arbitrary run of SWAPs and NOPs with an optimal one that has the // same effect. static int swaptimize(basicblock *block, int *ix) { // NOTE: "./python -m test test_patma" serves as a good, quick stress test // for this function. Make sure to blow away cached *.pyc files first! assert(*ix < block->b_iused); cfg_instr *instructions = &block->b_instr[*ix]; // Find the length of the current sequence of SWAPs and NOPs, and record the // maximum depth of the stack manipulations: assert(instructions[0].i_opcode == SWAP); int depth = instructions[0].i_oparg; int len = 0; int more = false; int limit = block->b_iused - *ix; while (++len < limit) { int opcode = instructions[len].i_opcode; if (opcode == SWAP) { depth = Py_MAX(depth, instructions[len].i_oparg); more = true; } else if (opcode != NOP) { break; } } // It's already optimal if there's only one SWAP: if (!more) { return SUCCESS; } // Create an array with elements {0, 1, 2, ..., depth - 1}: int *stack = PyMem_Malloc(depth * sizeof(int)); if (stack == NULL) { PyErr_NoMemory(); return ERROR; } for (int i = 0; i < depth; i++) { stack[i] = i; } // Simulate the combined effect of these instructions by "running" them on // our "stack": for (int i = 0; i < len; i++) { if (instructions[i].i_opcode == SWAP) { int oparg = instructions[i].i_oparg; int top = stack[0]; // SWAPs are 1-indexed: stack[0] = stack[oparg - 1]; stack[oparg - 1] = top; } } // Now we can begin! Our approach here is based on a solution to a closely // related problem (https://cs.stackexchange.com/a/13938). It's easiest to // think of this algorithm as determining the steps needed to efficiently // "un-shuffle" our stack. By performing the moves in *reverse* order, // though, we can efficiently *shuffle* it! For this reason, we will be // replacing instructions starting from the *end* of the run. Since the // solution is optimal, we don't need to worry about running out of space: int current = len - 1; for (int i = 0; i < depth; i++) { // Skip items that have already been visited, or just happen to be in // the correct location: if (stack[i] == VISITED || stack[i] == i) { continue; } // Okay, we've found an item that hasn't been visited. It forms a cycle // with other items; traversing the cycle and swapping each item with // the next will put them all in the correct place. The weird // loop-and-a-half is necessary to insert 0 into every cycle, since we // can only swap from that position: int j = i; while (true) { // Skip the actual swap if our item is zero, since swapping the top // item with itself is pointless: if (j) { assert(0 <= current); // SWAPs are 1-indexed: instructions[current].i_opcode = SWAP; instructions[current--].i_oparg = j + 1; } if (stack[j] == VISITED) { // Completed the cycle: assert(j == i); break; } int next_j = stack[j]; stack[j] = VISITED; j = next_j; } } // NOP out any unused instructions: while (0 <= current) { INSTR_SET_OP0(&instructions[current--], NOP); } PyMem_Free(stack); *ix += len - 1; return SUCCESS; } // This list is pretty small, since it's only okay to reorder opcodes that: // - can't affect control flow (like jumping or raising exceptions) // - can't invoke arbitrary code (besides finalizers) // - only touch the TOS (and pop it when finished) #define SWAPPABLE(opcode) \ ((opcode) == STORE_FAST || \ (opcode) == STORE_FAST_MAYBE_NULL || \ (opcode) == POP_TOP) #define STORES_TO(instr) \ (((instr).i_opcode == STORE_FAST || \ (instr).i_opcode == STORE_FAST_MAYBE_NULL) \ ? (instr).i_oparg : -1) static int next_swappable_instruction(basicblock *block, int i, int lineno) { while (++i < block->b_iused) { cfg_instr *instruction = &block->b_instr[i]; if (0 <= lineno && instruction->i_loc.lineno != lineno) { // Optimizing across this instruction could cause user-visible // changes in the names bound between line tracing events! return -1; } if (instruction->i_opcode == NOP) { continue; } if (SWAPPABLE(instruction->i_opcode)) { return i; } return -1; } return -1; } // Attempt to apply SWAPs statically by swapping *instructions* rather than // stack items. For example, we can replace SWAP(2), POP_TOP, STORE_FAST(42) // with the more efficient NOP, STORE_FAST(42), POP_TOP. static void apply_static_swaps(basicblock *block, int i) { // SWAPs are to our left, and potential swaperands are to our right: for (; 0 <= i; i--) { assert(i < block->b_iused); cfg_instr *swap = &block->b_instr[i]; if (swap->i_opcode != SWAP) { if (swap->i_opcode == NOP || SWAPPABLE(swap->i_opcode)) { // Nope, but we know how to handle these. Keep looking: continue; } // We can't reason about what this instruction does. Bail: return; } int j = next_swappable_instruction(block, i, -1); if (j < 0) { return; } int k = j; int lineno = block->b_instr[j].i_loc.lineno; for (int count = swap->i_oparg - 1; 0 < count; count--) { k = next_swappable_instruction(block, k, lineno); if (k < 0) { return; } } // The reordering is not safe if the two instructions to be swapped // store to the same location, or if any intervening instruction stores // to the same location as either of them. int store_j = STORES_TO(block->b_instr[j]); int store_k = STORES_TO(block->b_instr[k]); if (store_j >= 0 || store_k >= 0) { if (store_j == store_k) { return; } for (int idx = j + 1; idx < k; idx++) { int store_idx = STORES_TO(block->b_instr[idx]); if (store_idx >= 0 && (store_idx == store_j || store_idx == store_k)) { return; } } } // Success! INSTR_SET_OP0(swap, NOP); cfg_instr temp = block->b_instr[j]; block->b_instr[j] = block->b_instr[k]; block->b_instr[k] = temp; } } static int optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) { assert(PyDict_CheckExact(const_cache)); assert(PyList_CheckExact(consts)); cfg_instr nop; INSTR_SET_OP0(&nop, NOP); cfg_instr *target = &nop; int opcode = 0; int oparg = 0; int nextop = 0; for (int i = 0; i < bb->b_iused; i++) { cfg_instr *inst = &bb->b_instr[i]; bool is_copy_of_load_const = (opcode == LOAD_CONST && inst->i_opcode == COPY && inst->i_oparg == 1); if (! is_copy_of_load_const) { opcode = inst->i_opcode; oparg = inst->i_oparg; if (HAS_TARGET(opcode)) { assert(inst->i_target->b_iused > 0); target = &inst->i_target->b_instr[0]; assert(!IS_ASSEMBLER_OPCODE(target->i_opcode)); } else { target = &nop; } } nextop = i+1 < bb->b_iused ? bb->b_instr[i+1].i_opcode : 0; assert(!IS_ASSEMBLER_OPCODE(opcode)); switch (opcode) { /* Remove LOAD_CONST const; conditional jump */ case LOAD_CONST: { PyObject* cnt; int is_true; int jump_if_true; switch(nextop) { case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: cnt = get_const_value(opcode, oparg, consts); if (cnt == NULL) { goto error; } is_true = PyObject_IsTrue(cnt); Py_DECREF(cnt); if (is_true == -1) { goto error; } INSTR_SET_OP0(inst, NOP); jump_if_true = nextop == POP_JUMP_IF_TRUE; if (is_true == jump_if_true) { bb->b_instr[i+1].i_opcode = JUMP; } else { INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); } break; case IS_OP: cnt = get_const_value(opcode, oparg, consts); if (cnt == NULL) { goto error; } int jump_op = i+2 < bb->b_iused ? bb->b_instr[i+2].i_opcode : 0; if (Py_IsNone(cnt) && (jump_op == POP_JUMP_IF_FALSE || jump_op == POP_JUMP_IF_TRUE)) { unsigned char nextarg = bb->b_instr[i+1].i_oparg; INSTR_SET_OP0(inst, NOP); INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); bb->b_instr[i+2].i_opcode = nextarg ^ (jump_op == POP_JUMP_IF_FALSE) ? POP_JUMP_IF_NOT_NONE : POP_JUMP_IF_NONE; } Py_DECREF(cnt); break; case RETURN_VALUE: INSTR_SET_OP0(inst, NOP); INSTR_SET_OP1(&bb->b_instr[++i], RETURN_CONST, oparg); break; } break; } /* Try to fold tuples of constants. Skip over BUILD_TUPLE(1) UNPACK_SEQUENCE(1). Replace BUILD_TUPLE(2) UNPACK_SEQUENCE(2) with SWAP(2). Replace BUILD_TUPLE(3) UNPACK_SEQUENCE(3) with SWAP(3). */ case BUILD_TUPLE: if (nextop == UNPACK_SEQUENCE && oparg == bb->b_instr[i+1].i_oparg) { switch(oparg) { case 1: INSTR_SET_OP0(inst, NOP); INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); continue; case 2: case 3: INSTR_SET_OP0(inst, NOP); bb->b_instr[i+1].i_opcode = SWAP; continue; } } if (i >= oparg) { if (fold_tuple_on_constants(const_cache, inst-oparg, oparg, consts)) { goto error; } } break; case POP_JUMP_IF_NOT_NONE: case POP_JUMP_IF_NONE: switch (target->i_opcode) { case JUMP: i -= jump_thread(inst, target, inst->i_opcode); } break; case POP_JUMP_IF_FALSE: switch (target->i_opcode) { case JUMP: i -= jump_thread(inst, target, POP_JUMP_IF_FALSE); } break; case POP_JUMP_IF_TRUE: switch (target->i_opcode) { case JUMP: i -= jump_thread(inst, target, POP_JUMP_IF_TRUE); } break; case JUMP: switch (target->i_opcode) { case JUMP: i -= jump_thread(inst, target, JUMP); } break; case FOR_ITER: if (target->i_opcode == JUMP) { /* This will not work now because the jump (at target) could * be forward or backward and FOR_ITER only jumps forward. We * can re-enable this if ever we implement a backward version * of FOR_ITER. */ /* i -= jump_thread(inst, target, FOR_ITER); */ } break; case STORE_FAST: if (opcode == nextop && oparg == bb->b_instr[i+1].i_oparg && bb->b_instr[i].i_loc.lineno == bb->b_instr[i+1].i_loc.lineno) { bb->b_instr[i].i_opcode = POP_TOP; bb->b_instr[i].i_oparg = 0; } break; case SWAP: if (oparg == 1) { INSTR_SET_OP0(inst, NOP); } break; case KW_NAMES: break; case PUSH_NULL: if (nextop == LOAD_GLOBAL && (inst[1].i_opcode & 1) == 0) { INSTR_SET_OP0(inst, NOP); inst[1].i_oparg |= 1; } break; default: /* All HAS_CONST opcodes should be handled with LOAD_CONST */ assert (!HAS_CONST(inst->i_opcode)); } } for (int i = 0; i < bb->b_iused; i++) { cfg_instr *inst = &bb->b_instr[i]; if (inst->i_opcode == SWAP) { if (swaptimize(bb, &i) < 0) { goto error; } apply_static_swaps(bb, i); } } return SUCCESS; error: return ERROR; } /* Perform optimizations on a control flow graph. The consts object should still be in list form to allow new constants to be appended. Code trasnformations that reduce code size initially fill the gaps with NOPs. Later those NOPs are removed. */ static int optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache) { assert(PyDict_CheckExact(const_cache)); RETURN_IF_ERROR(check_cfg(g)); eliminate_empty_basic_blocks(g); for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { RETURN_IF_ERROR(inline_small_exit_blocks(b)); } assert(no_empty_basic_blocks(g)); for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { RETURN_IF_ERROR(optimize_basic_block(const_cache, b, consts)); assert(b->b_predecessors == 0); } RETURN_IF_ERROR(remove_redundant_nops_and_pairs(g->g_entryblock)); for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { RETURN_IF_ERROR(inline_small_exit_blocks(b)); } RETURN_IF_ERROR(mark_reachable(g->g_entryblock)); /* Delete unreachable instructions */ for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { if (b->b_predecessors == 0) { b->b_iused = 0; } } for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { remove_redundant_nops(b); } eliminate_empty_basic_blocks(g); assert(no_redundant_nops(g)); RETURN_IF_ERROR(remove_redundant_jumps(g)); return SUCCESS; } static void make_super_instruction(cfg_instr *inst1, cfg_instr *inst2, int super_op) { int32_t line1 = inst1->i_loc.lineno; int32_t line2 = inst2->i_loc.lineno; /* Skip if instructions are on different lines */ if (line1 >= 0 && line2 >= 0 && line1 != line2) { return; } if (inst1->i_oparg >= 16 || inst2->i_oparg >= 16) { return; } INSTR_SET_OP1(inst1, super_op, (inst1->i_oparg << 4) | inst2->i_oparg); INSTR_SET_OP0(inst2, NOP); } static void insert_superinstructions(cfg_builder *g) { for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { cfg_instr *inst = &b->b_instr[i]; int nextop = i+1 < b->b_iused ? b->b_instr[i+1].i_opcode : 0; switch(inst->i_opcode) { case LOAD_FAST: if (nextop == LOAD_FAST) { make_super_instruction(inst, &b->b_instr[i + 1], LOAD_FAST_LOAD_FAST); } break; case STORE_FAST: switch (nextop) { case LOAD_FAST: make_super_instruction(inst, &b->b_instr[i + 1], STORE_FAST_LOAD_FAST); break; case STORE_FAST: make_super_instruction(inst, &b->b_instr[i + 1], STORE_FAST_STORE_FAST); break; } break; } } } for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { remove_redundant_nops(b); } eliminate_empty_basic_blocks(g); assert(no_redundant_nops(g)); } // helper functions for add_checks_for_loads_of_unknown_variables static inline void maybe_push(basicblock *b, uint64_t unsafe_mask, basicblock ***sp) { // Push b if the unsafe mask is giving us any new information. // To avoid overflowing the stack, only allow each block once. // Use b->b_visited=1 to mean that b is currently on the stack. uint64_t both = b->b_unsafe_locals_mask | unsafe_mask; if (b->b_unsafe_locals_mask != both) { b->b_unsafe_locals_mask = both; // More work left to do. if (!b->b_visited) { // not on the stack, so push it. *(*sp)++ = b; b->b_visited = 1; } } } static void scan_block_for_locals(basicblock *b, basicblock ***sp) { // bit i is set if local i is potentially uninitialized uint64_t unsafe_mask = b->b_unsafe_locals_mask; for (int i = 0; i < b->b_iused; i++) { cfg_instr *instr = &b->b_instr[i]; assert(instr->i_opcode != EXTENDED_ARG); if (instr->i_except != NULL) { maybe_push(instr->i_except, unsafe_mask, sp); } if (instr->i_oparg >= 64) { continue; } assert(instr->i_oparg >= 0); uint64_t bit = (uint64_t)1 << instr->i_oparg; switch (instr->i_opcode) { case DELETE_FAST: case LOAD_FAST_AND_CLEAR: case STORE_FAST_MAYBE_NULL: unsafe_mask |= bit; break; case STORE_FAST: unsafe_mask &= ~bit; break; case LOAD_FAST_CHECK: // If this doesn't raise, then the local is defined. unsafe_mask &= ~bit; break; case LOAD_FAST: if (unsafe_mask & bit) { instr->i_opcode = LOAD_FAST_CHECK; } unsafe_mask &= ~bit; break; } } if (b->b_next && BB_HAS_FALLTHROUGH(b)) { maybe_push(b->b_next, unsafe_mask, sp); } cfg_instr *last = _PyCfg_BasicblockLastInstr(b); if (last && is_jump(last)) { assert(last->i_target != NULL); maybe_push(last->i_target, unsafe_mask, sp); } } static int fast_scan_many_locals(basicblock *entryblock, int nlocals) { assert(nlocals > 64); Py_ssize_t *states = PyMem_Calloc(nlocals - 64, sizeof(Py_ssize_t)); if (states == NULL) { PyErr_NoMemory(); return ERROR; } Py_ssize_t blocknum = 0; // state[i - 64] == blocknum if local i is guaranteed to // be initialized, i.e., if it has had a previous LOAD_FAST or // STORE_FAST within that basicblock (not followed by // DELETE_FAST/LOAD_FAST_AND_CLEAR/STORE_FAST_MAYBE_NULL). for (basicblock *b = entryblock; b != NULL; b = b->b_next) { blocknum++; for (int i = 0; i < b->b_iused; i++) { cfg_instr *instr = &b->b_instr[i]; assert(instr->i_opcode != EXTENDED_ARG); int arg = instr->i_oparg; if (arg < 64) { continue; } assert(arg >= 0); switch (instr->i_opcode) { case DELETE_FAST: case LOAD_FAST_AND_CLEAR: case STORE_FAST_MAYBE_NULL: states[arg - 64] = blocknum - 1; break; case STORE_FAST: states[arg - 64] = blocknum; break; case LOAD_FAST: if (states[arg - 64] != blocknum) { instr->i_opcode = LOAD_FAST_CHECK; } states[arg - 64] = blocknum; break; Py_UNREACHABLE(); } } } PyMem_Free(states); return SUCCESS; } static int remove_unused_consts(basicblock *entryblock, PyObject *consts) { assert(PyList_CheckExact(consts)); Py_ssize_t nconsts = PyList_GET_SIZE(consts); if (nconsts == 0) { return SUCCESS; /* nothing to do */ } Py_ssize_t *index_map = NULL; Py_ssize_t *reverse_index_map = NULL; int err = ERROR; index_map = PyMem_Malloc(nconsts * sizeof(Py_ssize_t)); if (index_map == NULL) { goto end; } for (Py_ssize_t i = 1; i < nconsts; i++) { index_map[i] = -1; } // The first constant may be docstring; keep it always. index_map[0] = 0; /* mark used consts */ for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { if (HAS_CONST(b->b_instr[i].i_opcode)) { int index = b->b_instr[i].i_oparg; index_map[index] = index; } } } /* now index_map[i] == i if consts[i] is used, -1 otherwise */ /* condense consts */ Py_ssize_t n_used_consts = 0; for (int i = 0; i < nconsts; i++) { if (index_map[i] != -1) { assert(index_map[i] == i); index_map[n_used_consts++] = index_map[i]; } } if (n_used_consts == nconsts) { /* nothing to do */ err = SUCCESS; goto end; } /* move all used consts to the beginning of the consts list */ assert(n_used_consts < nconsts); for (Py_ssize_t i = 0; i < n_used_consts; i++) { Py_ssize_t old_index = index_map[i]; assert(i <= old_index && old_index < nconsts); if (i != old_index) { PyObject *value = PyList_GET_ITEM(consts, index_map[i]); assert(value != NULL); PyList_SetItem(consts, i, Py_NewRef(value)); } } /* truncate the consts list at its new size */ if (PyList_SetSlice(consts, n_used_consts, nconsts, NULL) < 0) { goto end; } /* adjust const indices in the bytecode */ reverse_index_map = PyMem_Malloc(nconsts * sizeof(Py_ssize_t)); if (reverse_index_map == NULL) { goto end; } for (Py_ssize_t i = 0; i < nconsts; i++) { reverse_index_map[i] = -1; } for (Py_ssize_t i = 0; i < n_used_consts; i++) { assert(index_map[i] != -1); assert(reverse_index_map[index_map[i]] == -1); reverse_index_map[index_map[i]] = i; } for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { if (HAS_CONST(b->b_instr[i].i_opcode)) { int index = b->b_instr[i].i_oparg; assert(reverse_index_map[index] >= 0); assert(reverse_index_map[index] < n_used_consts); b->b_instr[i].i_oparg = (int)reverse_index_map[index]; } } } err = SUCCESS; end: PyMem_Free(index_map); PyMem_Free(reverse_index_map); return err; } static int add_checks_for_loads_of_uninitialized_variables(basicblock *entryblock, int nlocals, int nparams) { if (nlocals == 0) { return SUCCESS; } if (nlocals > 64) { // To avoid O(nlocals**2) compilation, locals beyond the first // 64 are only analyzed one basicblock at a time: initialization // info is not passed between basicblocks. if (fast_scan_many_locals(entryblock, nlocals) < 0) { return ERROR; } nlocals = 64; } basicblock **stack = make_cfg_traversal_stack(entryblock); if (stack == NULL) { return ERROR; } basicblock **sp = stack; // First origin of being uninitialized: // The non-parameter locals in the entry block. uint64_t start_mask = 0; for (int i = nparams; i < nlocals; i++) { start_mask |= (uint64_t)1 << i; } maybe_push(entryblock, start_mask, &sp); // Second origin of being uninitialized: // There could be DELETE_FAST somewhere, so // be sure to scan each basicblock at least once. for (basicblock *b = entryblock; b != NULL; b = b->b_next) { scan_block_for_locals(b, &sp); } // Now propagate the uncertainty from the origins we found: Use // LOAD_FAST_CHECK for any LOAD_FAST where the local could be undefined. while (sp > stack) { basicblock *b = *--sp; // mark as no longer on stack b->b_visited = 0; scan_block_for_locals(b, &sp); } PyMem_Free(stack); return SUCCESS; } static int mark_warm(basicblock *entryblock) { basicblock **stack = make_cfg_traversal_stack(entryblock); if (stack == NULL) { return ERROR; } basicblock **sp = stack; *sp++ = entryblock; entryblock->b_visited = 1; while (sp > stack) { basicblock *b = *(--sp); assert(!b->b_except_handler); b->b_warm = 1; basicblock *next = b->b_next; if (next && BB_HAS_FALLTHROUGH(b) && !next->b_visited) { *sp++ = next; next->b_visited = 1; } for (int i=0; i < b->b_iused; i++) { cfg_instr *instr = &b->b_instr[i]; if (is_jump(instr) && !instr->i_target->b_visited) { *sp++ = instr->i_target; instr->i_target->b_visited = 1; } } } PyMem_Free(stack); return SUCCESS; } static int mark_cold(basicblock *entryblock) { for (basicblock *b = entryblock; b != NULL; b = b->b_next) { assert(!b->b_cold && !b->b_warm); } if (mark_warm(entryblock) < 0) { return ERROR; } basicblock **stack = make_cfg_traversal_stack(entryblock); if (stack == NULL) { return ERROR; } basicblock **sp = stack; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { if (b->b_except_handler) { assert(!b->b_warm); *sp++ = b; b->b_visited = 1; } } while (sp > stack) { basicblock *b = *(--sp); b->b_cold = 1; basicblock *next = b->b_next; if (next && BB_HAS_FALLTHROUGH(b)) { if (!next->b_warm && !next->b_visited) { *sp++ = next; next->b_visited = 1; } } for (int i = 0; i < b->b_iused; i++) { cfg_instr *instr = &b->b_instr[i]; if (is_jump(instr)) { assert(i == b->b_iused - 1); basicblock *target = b->b_instr[i].i_target; if (!target->b_warm && !target->b_visited) { *sp++ = target; target->b_visited = 1; } } } } PyMem_Free(stack); return SUCCESS; } static int push_cold_blocks_to_end(cfg_builder *g, int code_flags) { basicblock *entryblock = g->g_entryblock; if (entryblock->b_next == NULL) { /* single basicblock, no need to reorder */ return SUCCESS; } RETURN_IF_ERROR(mark_cold(entryblock)); /* If we have a cold block with fallthrough to a warm block, add */ /* an explicit jump instead of fallthrough */ for (basicblock *b = entryblock; b != NULL; b = b->b_next) { if (b->b_cold && BB_HAS_FALLTHROUGH(b) && b->b_next && b->b_next->b_warm) { basicblock *explicit_jump = cfg_builder_new_block(g); if (explicit_jump == NULL) { return ERROR; } basicblock_addop(explicit_jump, JUMP, b->b_next->b_label.id, NO_LOCATION); explicit_jump->b_cold = 1; explicit_jump->b_next = b->b_next; b->b_next = explicit_jump; /* set target */ cfg_instr *last = _PyCfg_BasicblockLastInstr(explicit_jump); last->i_target = explicit_jump->b_next; } } assert(!entryblock->b_cold); /* First block can't be cold */ basicblock *cold_blocks = NULL; basicblock *cold_blocks_tail = NULL; basicblock *b = entryblock; while(b->b_next) { assert(!b->b_cold); while (b->b_next && !b->b_next->b_cold) { b = b->b_next; } if (b->b_next == NULL) { /* no more cold blocks */ break; } /* b->b_next is the beginning of a cold streak */ assert(!b->b_cold && b->b_next->b_cold); basicblock *b_end = b->b_next; while (b_end->b_next && b_end->b_next->b_cold) { b_end = b_end->b_next; } /* b_end is the end of the cold streak */ assert(b_end && b_end->b_cold); assert(b_end->b_next == NULL || !b_end->b_next->b_cold); if (cold_blocks == NULL) { cold_blocks = b->b_next; } else { cold_blocks_tail->b_next = b->b_next; } cold_blocks_tail = b_end; b->b_next = b_end->b_next; b_end->b_next = NULL; } assert(b != NULL && b->b_next == NULL); b->b_next = cold_blocks; if (cold_blocks != NULL) { RETURN_IF_ERROR(remove_redundant_jumps(g)); } return SUCCESS; } void _PyCfg_ConvertPseudoOps(basicblock *entryblock) { for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { cfg_instr *instr = &b->b_instr[i]; if (is_block_push(instr) || instr->i_opcode == POP_BLOCK) { assert(SAME_OPCODE_METADATA(instr->i_opcode, NOP)); INSTR_SET_OP0(instr, NOP); } else if (instr->i_opcode == STORE_FAST_MAYBE_NULL) { assert(SAME_OPCODE_METADATA(STORE_FAST_MAYBE_NULL, STORE_FAST)); instr->i_opcode = STORE_FAST; } } } for (basicblock *b = entryblock; b != NULL; b = b->b_next) { remove_redundant_nops(b); } } static inline bool is_exit_without_lineno(basicblock *b) { if (!basicblock_exits_scope(b)) { return false; } for (int i = 0; i < b->b_iused; i++) { if (b->b_instr[i].i_loc.lineno >= 0) { return false; } } return true; } /* PEP 626 mandates that the f_lineno of a frame is correct * after a frame terminates. It would be prohibitively expensive * to continuously update the f_lineno field at runtime, * so we make sure that all exiting instruction (raises and returns) * have a valid line number, allowing us to compute f_lineno lazily. * We can do this by duplicating the exit blocks without line number * so that none have more than one predecessor. We can then safely * copy the line number from the sole predecessor block. */ static int duplicate_exits_without_lineno(cfg_builder *g) { assert(no_empty_basic_blocks(g)); /* Copy all exit blocks without line number that are targets of a jump. */ basicblock *entryblock = g->g_entryblock; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { cfg_instr *last = _PyCfg_BasicblockLastInstr(b); assert(last != NULL); if (is_jump(last)) { basicblock *target = last->i_target; if (is_exit_without_lineno(target) && target->b_predecessors > 1) { basicblock *new_target = copy_basicblock(g, target); if (new_target == NULL) { return ERROR; } new_target->b_instr[0].i_loc = last->i_loc; last->i_target = new_target; target->b_predecessors--; new_target->b_predecessors = 1; new_target->b_next = target->b_next; target->b_next = new_target; } } } /* Any remaining reachable exit blocks without line number can only be reached by * fall through, and thus can only have a single predecessor */ for (basicblock *b = entryblock; b != NULL; b = b->b_next) { if (BB_HAS_FALLTHROUGH(b) && b->b_next && b->b_iused > 0) { if (is_exit_without_lineno(b->b_next)) { cfg_instr *last = _PyCfg_BasicblockLastInstr(b); assert(last != NULL); b->b_next->b_instr[0].i_loc = last->i_loc; } } } return SUCCESS; } /* If an instruction has no line number, but it's predecessor in the BB does, * then copy the line number. If a successor block has no line number, and only * one predecessor, then inherit the line number. * This ensures that all exit blocks (with one predecessor) receive a line number. * Also reduces the size of the line number table, * but has no impact on the generated line number events. */ static void propagate_line_numbers(basicblock *entryblock) { for (basicblock *b = entryblock; b != NULL; b = b->b_next) { cfg_instr *last = _PyCfg_BasicblockLastInstr(b); if (last == NULL) { continue; } location prev_location = NO_LOCATION; for (int i = 0; i < b->b_iused; i++) { if (b->b_instr[i].i_loc.lineno < 0) { b->b_instr[i].i_loc = prev_location; } else { prev_location = b->b_instr[i].i_loc; } } if (BB_HAS_FALLTHROUGH(b) && b->b_next->b_predecessors == 1) { assert(b->b_next->b_iused); if (b->b_next->b_instr[0].i_loc.lineno < 0) { b->b_next->b_instr[0].i_loc = prev_location; } } if (is_jump(last)) { basicblock *target = last->i_target; if (target->b_predecessors == 1) { if (target->b_instr[0].i_loc.lineno < 0) { target->b_instr[0].i_loc = prev_location; } } } } } /* Make sure that all returns have a line number, even if early passes * have failed to propagate a correct line number. * The resulting line number may not be correct according to PEP 626, * but should be "good enough", and no worse than in older versions. */ static void guarantee_lineno_for_exits(basicblock *entryblock, int firstlineno) { int lineno = firstlineno; assert(lineno > 0); for (basicblock *b = entryblock; b != NULL; b = b->b_next) { cfg_instr *last = _PyCfg_BasicblockLastInstr(b); if (last == NULL) { continue; } if (last->i_loc.lineno < 0) { if (last->i_opcode == RETURN_VALUE) { for (int i = 0; i < b->b_iused; i++) { assert(b->b_instr[i].i_loc.lineno < 0); b->b_instr[i].i_loc.lineno = lineno; } } } else { lineno = last->i_loc.lineno; } } } static int resolve_line_numbers(cfg_builder *g, int firstlineno) { RETURN_IF_ERROR(duplicate_exits_without_lineno(g)); propagate_line_numbers(g->g_entryblock); guarantee_lineno_for_exits(g->g_entryblock, firstlineno); return SUCCESS; } int _PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache, int code_flags, int nlocals, int nparams, int firstlineno) { assert(cfg_builder_check(g)); /** Preprocessing **/ /* Map labels to targets and mark exception handlers */ RETURN_IF_ERROR(translate_jump_labels_to_targets(g->g_entryblock)); RETURN_IF_ERROR(mark_except_handlers(g->g_entryblock)); RETURN_IF_ERROR(label_exception_targets(g->g_entryblock)); /** Optimization **/ RETURN_IF_ERROR(optimize_cfg(g, consts, const_cache)); RETURN_IF_ERROR(remove_unused_consts(g->g_entryblock, consts)); RETURN_IF_ERROR( add_checks_for_loads_of_uninitialized_variables( g->g_entryblock, nlocals, nparams)); insert_superinstructions(g); RETURN_IF_ERROR(push_cold_blocks_to_end(g, code_flags)); RETURN_IF_ERROR(resolve_line_numbers(g, firstlineno)); return SUCCESS; } ================================================ FILE: Formatter_Unicode.c ================================================ /* implements the unicode (as opposed to string) version of the built-in formatters for string, int, float. that is, the versions of int.__float__, etc., that take and return unicode objects */ #include "Python.h" #include "pycore_fileutils.h" // _Py_GetLocaleconvNumeric() #include "pycore_long.h" // _PyLong_FormatWriter() #include /* Raises an exception about an unknown presentation type for this * type. */ static void unknown_presentation_type(Py_UCS4 presentation_type, const char* type_name) { /* %c might be out-of-range, hence the two cases. */ if (presentation_type > 32 && presentation_type < 128) PyErr_Format(PyExc_ValueError, "Unknown format code '%c' " "for object of type '%.200s'", (char)presentation_type, type_name); else PyErr_Format(PyExc_ValueError, "Unknown format code '\\x%x' " "for object of type '%.200s'", (unsigned int)presentation_type, type_name); } static void invalid_thousands_separator_type(char specifier, Py_UCS4 presentation_type) { assert(specifier == ',' || specifier == '_'); if (presentation_type > 32 && presentation_type < 128) PyErr_Format(PyExc_ValueError, "Cannot specify '%c' with '%c'.", specifier, (char)presentation_type); else PyErr_Format(PyExc_ValueError, "Cannot specify '%c' with '\\x%x'.", specifier, (unsigned int)presentation_type); } static void invalid_comma_and_underscore(void) { PyErr_Format(PyExc_ValueError, "Cannot specify both ',' and '_'."); } /* get_integer consumes 0 or more decimal digit characters from an input string, updates *result with the corresponding positive integer, and returns the number of digits consumed. returns -1 on error. */ static int get_integer(PyObject *str, Py_ssize_t *ppos, Py_ssize_t end, Py_ssize_t *result) { Py_ssize_t accumulator, digitval, pos = *ppos; int numdigits; int kind = PyUnicode_KIND(str); const void *data = PyUnicode_DATA(str); accumulator = numdigits = 0; for (; pos < end; pos++, numdigits++) { digitval = Py_UNICODE_TODECIMAL(PyUnicode_READ(kind, data, pos)); if (digitval < 0) break; /* Detect possible overflow before it happens: accumulator * 10 + digitval > PY_SSIZE_T_MAX if and only if accumulator > (PY_SSIZE_T_MAX - digitval) / 10. */ if (accumulator > (PY_SSIZE_T_MAX - digitval) / 10) { PyErr_Format(PyExc_ValueError, "Too many decimal digits in format string"); *ppos = pos; return -1; } accumulator = accumulator * 10 + digitval; } *ppos = pos; *result = accumulator; return numdigits; } /************************************************************************/ /*********** standard format specifier parsing **************************/ /************************************************************************/ /* returns true if this character is a specifier alignment token */ Py_LOCAL_INLINE(int) is_alignment_token(Py_UCS4 c) { switch (c) { case '<': case '>': case '=': case '^': return 1; default: return 0; } } /* returns true if this character is a sign element */ Py_LOCAL_INLINE(int) is_sign_element(Py_UCS4 c) { switch (c) { case ' ': case '+': case '-': return 1; default: return 0; } } /* Locale type codes. LT_NO_LOCALE must be zero. */ enum LocaleType { LT_NO_LOCALE = 0, LT_DEFAULT_LOCALE = ',', LT_UNDERSCORE_LOCALE = '_', LT_UNDER_FOUR_LOCALE, LT_CURRENT_LOCALE }; typedef struct { Py_UCS4 fill_char; Py_UCS4 align; int alternate; int no_neg_0; Py_UCS4 sign; Py_ssize_t width; enum LocaleType thousands_separators; Py_ssize_t precision; Py_UCS4 type; } InternalFormatSpec; /* ptr points to the start of the format_spec, end points just past its end. fills in format with the parsed information. returns 1 on success, 0 on failure. if failure, sets the exception */ static int parse_internal_render_format_spec(PyObject *obj, PyObject *format_spec, Py_ssize_t start, Py_ssize_t end, InternalFormatSpec *format, char default_type, char default_align) { Py_ssize_t pos = start; int kind = PyUnicode_KIND(format_spec); const void *data = PyUnicode_DATA(format_spec); /* end-pos is used throughout this code to specify the length of the input string */ #define READ_spec(index) PyUnicode_READ(kind, data, index) Py_ssize_t consumed; int align_specified = 0; int fill_char_specified = 0; format->fill_char = ' '; format->align = default_align; format->alternate = 0; format->no_neg_0 = 0; format->sign = '\0'; format->width = -1; format->thousands_separators = LT_NO_LOCALE; format->precision = -1; format->type = default_type; /* If the second char is an alignment token, then parse the fill char */ if (end-pos >= 2 && is_alignment_token(READ_spec(pos+1))) { format->align = READ_spec(pos+1); format->fill_char = READ_spec(pos); fill_char_specified = 1; align_specified = 1; pos += 2; } else if (end-pos >= 1 && is_alignment_token(READ_spec(pos))) { format->align = READ_spec(pos); align_specified = 1; ++pos; } /* Parse the various sign options */ if (end-pos >= 1 && is_sign_element(READ_spec(pos))) { format->sign = READ_spec(pos); ++pos; } /* If the next character is z, request coercion of negative 0. Applies only to floats. */ if (end-pos >= 1 && READ_spec(pos) == 'z') { format->no_neg_0 = 1; ++pos; } /* If the next character is #, we're in alternate mode. This only applies to integers. */ if (end-pos >= 1 && READ_spec(pos) == '#') { format->alternate = 1; ++pos; } /* The special case for 0-padding (backwards compat) */ if (!fill_char_specified && end-pos >= 1 && READ_spec(pos) == '0') { format->fill_char = '0'; if (!align_specified && default_align == '>') { format->align = '='; } ++pos; } consumed = get_integer(format_spec, &pos, end, &format->width); if (consumed == -1) /* Overflow error. Exception already set. */ return 0; /* If consumed is 0, we didn't consume any characters for the width. In that case, reset the width to -1, because get_integer() will have set it to zero. -1 is how we record that the width wasn't specified. */ if (consumed == 0) format->width = -1; /* Comma signifies add thousands separators */ if (end-pos && READ_spec(pos) == ',') { format->thousands_separators = LT_DEFAULT_LOCALE; ++pos; } /* Underscore signifies add thousands separators */ if (end-pos && READ_spec(pos) == '_') { if (format->thousands_separators != LT_NO_LOCALE) { invalid_comma_and_underscore(); return 0; } format->thousands_separators = LT_UNDERSCORE_LOCALE; ++pos; } if (end-pos && READ_spec(pos) == ',') { if (format->thousands_separators == LT_UNDERSCORE_LOCALE) { invalid_comma_and_underscore(); return 0; } } /* Parse field precision */ if (end-pos && READ_spec(pos) == '.') { ++pos; consumed = get_integer(format_spec, &pos, end, &format->precision); if (consumed == -1) /* Overflow error. Exception already set. */ return 0; /* Not having a precision after a dot is an error. */ if (consumed == 0) { PyErr_Format(PyExc_ValueError, "Format specifier missing precision"); return 0; } } /* Finally, parse the type field. */ if (end-pos > 1) { /* More than one char remains, so this is an invalid format specifier. */ /* Create a temporary object that contains the format spec we're operating on. It's format_spec[start:end] (in Python syntax). */ PyObject* actual_format_spec = PyUnicode_FromKindAndData(kind, (char*)data + kind*start, end-start); if (actual_format_spec != NULL) { PyErr_Format(PyExc_ValueError, "Invalid format specifier '%U' for object of type '%.200s'", actual_format_spec, Py_TYPE(obj)->tp_name); Py_DECREF(actual_format_spec); } return 0; } if (end-pos == 1) { format->type = READ_spec(pos); ++pos; } /* Do as much validating as we can, just by looking at the format specifier. Do not take into account what type of formatting we're doing (int, float, string). */ if (format->thousands_separators) { switch (format->type) { case 'd': case 'e': case 'f': case 'g': case 'E': case 'G': case '%': case 'F': case '\0': /* These are allowed. See PEP 378.*/ break; case 'b': case 'o': case 'x': case 'X': /* Underscores are allowed in bin/oct/hex. See PEP 515. */ if (format->thousands_separators == LT_UNDERSCORE_LOCALE) { /* Every four digits, not every three, in bin/oct/hex. */ format->thousands_separators = LT_UNDER_FOUR_LOCALE; break; } /* fall through */ default: invalid_thousands_separator_type(format->thousands_separators, format->type); return 0; } } assert (format->align <= 127); assert (format->sign <= 127); return 1; } /* Calculate the padding needed. */ static void calc_padding(Py_ssize_t nchars, Py_ssize_t width, Py_UCS4 align, Py_ssize_t *n_lpadding, Py_ssize_t *n_rpadding, Py_ssize_t *n_total) { if (width >= 0) { if (nchars > width) *n_total = nchars; else *n_total = width; } else { /* not specified, use all of the chars and no more */ *n_total = nchars; } /* Figure out how much leading space we need, based on the aligning */ if (align == '>') *n_lpadding = *n_total - nchars; else if (align == '^') *n_lpadding = (*n_total - nchars) / 2; else if (align == '<' || align == '=') *n_lpadding = 0; else { /* We should never have an unspecified alignment. */ Py_UNREACHABLE(); } *n_rpadding = *n_total - nchars - *n_lpadding; } /* Do the padding, and return a pointer to where the caller-supplied content goes. */ static int fill_padding(_PyUnicodeWriter *writer, Py_ssize_t nchars, Py_UCS4 fill_char, Py_ssize_t n_lpadding, Py_ssize_t n_rpadding) { Py_ssize_t pos; /* Pad on left. */ if (n_lpadding) { pos = writer->pos; _PyUnicode_FastFill(writer->buffer, pos, n_lpadding, fill_char); } /* Pad on right. */ if (n_rpadding) { pos = writer->pos + nchars + n_lpadding; _PyUnicode_FastFill(writer->buffer, pos, n_rpadding, fill_char); } /* Pointer to the user content. */ writer->pos += n_lpadding; return 0; } /************************************************************************/ /*********** common routines for numeric formatting *********************/ /************************************************************************/ /* Locale info needed for formatting integers and the part of floats before and including the decimal. Note that locales only support 8-bit chars, not unicode. */ typedef struct { PyObject *decimal_point; PyObject *thousands_sep; const char *grouping; char *grouping_buffer; } LocaleInfo; #define LocaleInfo_STATIC_INIT {0, 0, 0, 0} /* describes the layout for an integer, see the comment in calc_number_widths() for details */ typedef struct { Py_ssize_t n_lpadding; Py_ssize_t n_prefix; Py_ssize_t n_spadding; Py_ssize_t n_rpadding; char sign; Py_ssize_t n_sign; /* number of digits needed for sign (0/1) */ Py_ssize_t n_grouped_digits; /* Space taken up by the digits, including any grouping chars. */ Py_ssize_t n_decimal; /* 0 if only an integer */ Py_ssize_t n_remainder; /* Digits in decimal and/or exponent part, excluding the decimal itself, if present. */ /* These 2 are not the widths of fields, but are needed by STRINGLIB_GROUPING. */ Py_ssize_t n_digits; /* The number of digits before a decimal or exponent. */ Py_ssize_t n_min_width; /* The min_width we used when we computed the n_grouped_digits width. */ } NumberFieldWidths; /* Given a number of the form: digits[remainder] where ptr points to the start and end points to the end, find where the integer part ends. This could be a decimal, an exponent, both, or neither. If a decimal point is present, set *has_decimal and increment remainder beyond it. Results are undefined (but shouldn't crash) for improperly formatted strings. */ static void parse_number(PyObject *s, Py_ssize_t pos, Py_ssize_t end, Py_ssize_t *n_remainder, int *has_decimal) { Py_ssize_t remainder; int kind = PyUnicode_KIND(s); const void *data = PyUnicode_DATA(s); while (posn_digits = n_end - n_start - n_remainder - (has_decimal?1:0); spec->n_lpadding = 0; spec->n_prefix = n_prefix; spec->n_decimal = has_decimal ? PyUnicode_GET_LENGTH(locale->decimal_point) : 0; spec->n_remainder = n_remainder; spec->n_spadding = 0; spec->n_rpadding = 0; spec->sign = '\0'; spec->n_sign = 0; /* the output will look like: | | | | | | sign is computed from format->sign and the actual sign of the number prefix is given (it's for the '0x' prefix) digits is already known the total width is either given, or computed from the actual digits only one of lpadding, spadding, and rpadding can be non-zero, and it's calculated from the width and other fields */ /* compute the various parts we're going to write */ switch (format->sign) { case '+': /* always put a + or - */ spec->n_sign = 1; spec->sign = (sign_char == '-' ? '-' : '+'); break; case ' ': spec->n_sign = 1; spec->sign = (sign_char == '-' ? '-' : ' '); break; default: /* Not specified, or the default (-) */ if (sign_char == '-') { spec->n_sign = 1; spec->sign = '-'; } } /* The number of chars used for non-digits and non-padding. */ n_non_digit_non_padding = spec->n_sign + spec->n_prefix + spec->n_decimal + spec->n_remainder; /* min_width can go negative, that's okay. format->width == -1 means we don't care. */ if (format->fill_char == '0' && format->align == '=') spec->n_min_width = format->width - n_non_digit_non_padding; else spec->n_min_width = 0; if (spec->n_digits == 0) /* This case only occurs when using 'c' formatting, we need to special case it because the grouping code always wants to have at least one character. */ spec->n_grouped_digits = 0; else { Py_UCS4 grouping_maxchar; spec->n_grouped_digits = _PyUnicode_InsertThousandsGrouping( NULL, 0, NULL, 0, spec->n_digits, spec->n_min_width, locale->grouping, locale->thousands_sep, &grouping_maxchar); if (spec->n_grouped_digits == -1) { return -1; } *maxchar = Py_MAX(*maxchar, grouping_maxchar); } /* Given the desired width and the total of digit and non-digit space we consume, see if we need any padding. format->width can be negative (meaning no padding), but this code still works in that case. */ n_padding = format->width - (n_non_digit_non_padding + spec->n_grouped_digits); if (n_padding > 0) { /* Some padding is needed. Determine if it's left, space, or right. */ switch (format->align) { case '<': spec->n_rpadding = n_padding; break; case '^': spec->n_lpadding = n_padding / 2; spec->n_rpadding = n_padding - spec->n_lpadding; break; case '=': spec->n_spadding = n_padding; break; case '>': spec->n_lpadding = n_padding; break; default: /* Shouldn't get here */ Py_UNREACHABLE(); } } if (spec->n_lpadding || spec->n_spadding || spec->n_rpadding) *maxchar = Py_MAX(*maxchar, format->fill_char); if (spec->n_decimal) *maxchar = Py_MAX(*maxchar, PyUnicode_MAX_CHAR_VALUE(locale->decimal_point)); return spec->n_lpadding + spec->n_sign + spec->n_prefix + spec->n_spadding + spec->n_grouped_digits + spec->n_decimal + spec->n_remainder + spec->n_rpadding; } /* Fill in the digit parts of a number's string representation, as determined in calc_number_widths(). Return -1 on error, or 0 on success. */ static int fill_number(_PyUnicodeWriter *writer, const NumberFieldWidths *spec, PyObject *digits, Py_ssize_t d_start, PyObject *prefix, Py_ssize_t p_start, Py_UCS4 fill_char, LocaleInfo *locale, int toupper) { /* Used to keep track of digits, decimal, and remainder. */ Py_ssize_t d_pos = d_start; const int kind = writer->kind; const void *data = writer->data; Py_ssize_t r; if (spec->n_lpadding) { _PyUnicode_FastFill(writer->buffer, writer->pos, spec->n_lpadding, fill_char); writer->pos += spec->n_lpadding; } if (spec->n_sign == 1) { PyUnicode_WRITE(kind, data, writer->pos, spec->sign); writer->pos++; } if (spec->n_prefix) { _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos, prefix, p_start, spec->n_prefix); if (toupper) { Py_ssize_t t; for (t = 0; t < spec->n_prefix; t++) { Py_UCS4 c = PyUnicode_READ(kind, data, writer->pos + t); c = Py_TOUPPER(c); assert (c <= 127); PyUnicode_WRITE(kind, data, writer->pos + t, c); } } writer->pos += spec->n_prefix; } if (spec->n_spadding) { _PyUnicode_FastFill(writer->buffer, writer->pos, spec->n_spadding, fill_char); writer->pos += spec->n_spadding; } /* Only for type 'c' special case, it has no digits. */ if (spec->n_digits != 0) { /* Fill the digits with InsertThousandsGrouping. */ r = _PyUnicode_InsertThousandsGrouping( writer, spec->n_grouped_digits, digits, d_pos, spec->n_digits, spec->n_min_width, locale->grouping, locale->thousands_sep, NULL); if (r == -1) return -1; assert(r == spec->n_grouped_digits); d_pos += spec->n_digits; } if (toupper) { Py_ssize_t t; for (t = 0; t < spec->n_grouped_digits; t++) { Py_UCS4 c = PyUnicode_READ(kind, data, writer->pos + t); c = Py_TOUPPER(c); if (c > 127) { PyErr_SetString(PyExc_SystemError, "non-ascii grouped digit"); return -1; } PyUnicode_WRITE(kind, data, writer->pos + t, c); } } writer->pos += spec->n_grouped_digits; if (spec->n_decimal) { _PyUnicode_FastCopyCharacters( writer->buffer, writer->pos, locale->decimal_point, 0, spec->n_decimal); writer->pos += spec->n_decimal; d_pos += 1; } if (spec->n_remainder) { _PyUnicode_FastCopyCharacters( writer->buffer, writer->pos, digits, d_pos, spec->n_remainder); writer->pos += spec->n_remainder; /* d_pos += spec->n_remainder; */ } if (spec->n_rpadding) { _PyUnicode_FastFill(writer->buffer, writer->pos, spec->n_rpadding, fill_char); writer->pos += spec->n_rpadding; } return 0; } static const char no_grouping[1] = {CHAR_MAX}; /* Find the decimal point character(s?), thousands_separator(s?), and grouping description, either for the current locale if type is LT_CURRENT_LOCALE, a hard-coded locale if LT_DEFAULT_LOCALE or LT_UNDERSCORE_LOCALE/LT_UNDER_FOUR_LOCALE, or none if LT_NO_LOCALE. */ static int get_locale_info(enum LocaleType type, LocaleInfo *locale_info) { switch (type) { case LT_CURRENT_LOCALE: { struct lconv *lc = localeconv(); if (_Py_GetLocaleconvNumeric(lc, &locale_info->decimal_point, &locale_info->thousands_sep) < 0) { return -1; } /* localeconv() grouping can become a dangling pointer or point to a different string if another thread calls localeconv() during the string formatting. Copy the string to avoid this risk. */ locale_info->grouping_buffer = _PyMem_Strdup(lc->grouping); if (locale_info->grouping_buffer == NULL) { PyErr_NoMemory(); return -1; } locale_info->grouping = locale_info->grouping_buffer; break; } case LT_DEFAULT_LOCALE: case LT_UNDERSCORE_LOCALE: case LT_UNDER_FOUR_LOCALE: locale_info->decimal_point = PyUnicode_FromOrdinal('.'); locale_info->thousands_sep = PyUnicode_FromOrdinal( type == LT_DEFAULT_LOCALE ? ',' : '_'); if (!locale_info->decimal_point || !locale_info->thousands_sep) return -1; if (type != LT_UNDER_FOUR_LOCALE) locale_info->grouping = "\3"; /* Group every 3 characters. The (implicit) trailing 0 means repeat infinitely. */ else locale_info->grouping = "\4"; /* Bin/oct/hex group every four. */ break; case LT_NO_LOCALE: locale_info->decimal_point = PyUnicode_FromOrdinal('.'); locale_info->thousands_sep = PyUnicode_New(0, 0); if (!locale_info->decimal_point || !locale_info->thousands_sep) return -1; locale_info->grouping = no_grouping; break; } return 0; } static void free_locale_info(LocaleInfo *locale_info) { Py_XDECREF(locale_info->decimal_point); Py_XDECREF(locale_info->thousands_sep); PyMem_Free(locale_info->grouping_buffer); } /************************************************************************/ /*********** string formatting ******************************************/ /************************************************************************/ static int format_string_internal(PyObject *value, const InternalFormatSpec *format, _PyUnicodeWriter *writer) { Py_ssize_t lpad; Py_ssize_t rpad; Py_ssize_t total; Py_ssize_t len; int result = -1; Py_UCS4 maxchar; assert(PyUnicode_IS_READY(value)); len = PyUnicode_GET_LENGTH(value); /* sign is not allowed on strings */ if (format->sign != '\0') { if (format->sign == ' ') { PyErr_SetString(PyExc_ValueError, "Space not allowed in string format specifier"); } else { PyErr_SetString(PyExc_ValueError, "Sign not allowed in string format specifier"); } goto done; } /* negative 0 coercion is not allowed on strings */ if (format->no_neg_0) { PyErr_SetString(PyExc_ValueError, "Negative zero coercion (z) not allowed in string format " "specifier"); goto done; } /* alternate is not allowed on strings */ if (format->alternate) { PyErr_SetString(PyExc_ValueError, "Alternate form (#) not allowed in string format " "specifier"); goto done; } /* '=' alignment not allowed on strings */ if (format->align == '=') { PyErr_SetString(PyExc_ValueError, "'=' alignment not allowed " "in string format specifier"); goto done; } if ((format->width == -1 || format->width <= len) && (format->precision == -1 || format->precision >= len)) { /* Fast path */ return _PyUnicodeWriter_WriteStr(writer, value); } /* if precision is specified, output no more that format.precision characters */ if (format->precision >= 0 && len >= format->precision) { len = format->precision; } calc_padding(len, format->width, format->align, &lpad, &rpad, &total); maxchar = writer->maxchar; if (lpad != 0 || rpad != 0) maxchar = Py_MAX(maxchar, format->fill_char); if (PyUnicode_MAX_CHAR_VALUE(value) > maxchar) { Py_UCS4 valmaxchar = _PyUnicode_FindMaxChar(value, 0, len); maxchar = Py_MAX(maxchar, valmaxchar); } /* allocate the resulting string */ if (_PyUnicodeWriter_Prepare(writer, total, maxchar) == -1) goto done; /* Write into that space. First the padding. */ result = fill_padding(writer, len, format->fill_char, lpad, rpad); if (result == -1) goto done; /* Then the source string. */ if (len) { _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos, value, 0, len); } writer->pos += (len + rpad); result = 0; done: return result; } /************************************************************************/ /*********** long formatting ********************************************/ /************************************************************************/ static int format_long_internal(PyObject *value, const InternalFormatSpec *format, _PyUnicodeWriter *writer) { int result = -1; Py_UCS4 maxchar = 127; PyObject *tmp = NULL; Py_ssize_t inumeric_chars; Py_UCS4 sign_char = '\0'; Py_ssize_t n_digits; /* count of digits need from the computed string */ Py_ssize_t n_remainder = 0; /* Used only for 'c' formatting, which produces non-digits */ Py_ssize_t n_prefix = 0; /* Count of prefix chars, (e.g., '0x') */ Py_ssize_t n_total; Py_ssize_t prefix = 0; NumberFieldWidths spec; long x; /* Locale settings, either from the actual locale or from a hard-code pseudo-locale */ LocaleInfo locale = LocaleInfo_STATIC_INIT; /* no precision allowed on integers */ if (format->precision != -1) { PyErr_SetString(PyExc_ValueError, "Precision not allowed in integer format specifier"); goto done; } /* no negative zero coercion on integers */ if (format->no_neg_0) { PyErr_SetString(PyExc_ValueError, "Negative zero coercion (z) not allowed in integer" " format specifier"); goto done; } /* special case for character formatting */ if (format->type == 'c') { /* error to specify a sign */ if (format->sign != '\0') { PyErr_SetString(PyExc_ValueError, "Sign not allowed with integer" " format specifier 'c'"); goto done; } /* error to request alternate format */ if (format->alternate) { PyErr_SetString(PyExc_ValueError, "Alternate form (#) not allowed with integer" " format specifier 'c'"); goto done; } /* taken from unicodeobject.c formatchar() */ /* Integer input truncated to a character */ x = PyLong_AsLong(value); if (x == -1 && PyErr_Occurred()) goto done; if (x < 0 || x > 0x10ffff) { PyErr_SetString(PyExc_OverflowError, "%c arg not in range(0x110000)"); goto done; } tmp = PyUnicode_FromOrdinal(x); inumeric_chars = 0; n_digits = 1; maxchar = Py_MAX(maxchar, (Py_UCS4)x); /* As a sort-of hack, we tell calc_number_widths that we only have "remainder" characters. calc_number_widths thinks these are characters that don't get formatted, only copied into the output string. We do this for 'c' formatting, because the characters are likely to be non-digits. */ n_remainder = 1; } else { int base; int leading_chars_to_skip = 0; /* Number of characters added by PyNumber_ToBase that we want to skip over. */ /* Compute the base and how many characters will be added by PyNumber_ToBase */ switch (format->type) { case 'b': base = 2; leading_chars_to_skip = 2; /* 0b */ break; case 'o': base = 8; leading_chars_to_skip = 2; /* 0o */ break; case 'x': case 'X': base = 16; leading_chars_to_skip = 2; /* 0x */ break; default: /* shouldn't be needed, but stops a compiler warning */ case 'd': case 'n': base = 10; break; } if (format->sign != '+' && format->sign != ' ' && format->width == -1 && format->type != 'X' && format->type != 'n' && !format->thousands_separators && PyLong_CheckExact(value)) { /* Fast path */ return _PyLong_FormatWriter(writer, value, base, format->alternate); } /* The number of prefix chars is the same as the leading chars to skip */ if (format->alternate) n_prefix = leading_chars_to_skip; /* Do the hard part, converting to a string in a given base */ tmp = _PyLong_Format(value, base); if (tmp == NULL) goto done; inumeric_chars = 0; n_digits = PyUnicode_GET_LENGTH(tmp); prefix = inumeric_chars; /* Is a sign character present in the output? If so, remember it and skip it */ if (PyUnicode_READ_CHAR(tmp, inumeric_chars) == '-') { sign_char = '-'; ++prefix; ++leading_chars_to_skip; } /* Skip over the leading chars (0x, 0b, etc.) */ n_digits -= leading_chars_to_skip; inumeric_chars += leading_chars_to_skip; } /* Determine the grouping, separator, and decimal point, if any. */ if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE : format->thousands_separators, &locale) == -1) goto done; /* Calculate how much memory we'll need. */ n_total = calc_number_widths(&spec, n_prefix, sign_char, inumeric_chars, inumeric_chars + n_digits, n_remainder, 0, &locale, format, &maxchar); if (n_total == -1) { goto done; } /* Allocate the memory. */ if (_PyUnicodeWriter_Prepare(writer, n_total, maxchar) == -1) goto done; /* Populate the memory. */ result = fill_number(writer, &spec, tmp, inumeric_chars, tmp, prefix, format->fill_char, &locale, format->type == 'X'); done: Py_XDECREF(tmp); free_locale_info(&locale); return result; } /************************************************************************/ /*********** float formatting *******************************************/ /************************************************************************/ /* much of this is taken from unicodeobject.c */ static int format_float_internal(PyObject *value, const InternalFormatSpec *format, _PyUnicodeWriter *writer) { char *buf = NULL; /* buffer returned from PyOS_double_to_string */ Py_ssize_t n_digits; Py_ssize_t n_remainder; Py_ssize_t n_total; int has_decimal; double val; int precision, default_precision = 6; Py_UCS4 type = format->type; int add_pct = 0; Py_ssize_t index; NumberFieldWidths spec; int flags = 0; int result = -1; Py_UCS4 maxchar = 127; Py_UCS4 sign_char = '\0'; int float_type; /* Used to see if we have a nan, inf, or regular float. */ PyObject *unicode_tmp = NULL; /* Locale settings, either from the actual locale or from a hard-code pseudo-locale */ LocaleInfo locale = LocaleInfo_STATIC_INIT; if (format->precision > INT_MAX) { PyErr_SetString(PyExc_ValueError, "precision too big"); goto done; } precision = (int)format->precision; if (format->alternate) flags |= Py_DTSF_ALT; if (format->no_neg_0) flags |= Py_DTSF_NO_NEG_0; if (type == '\0') { /* Omitted type specifier. Behaves in the same way as repr(x) and str(x) if no precision is given, else like 'g', but with at least one digit after the decimal point. */ flags |= Py_DTSF_ADD_DOT_0; type = 'r'; default_precision = 0; } if (type == 'n') /* 'n' is the same as 'g', except for the locale used to format the result. We take care of that later. */ type = 'g'; val = PyFloat_AsDouble(value); if (val == -1.0 && PyErr_Occurred()) goto done; if (type == '%') { type = 'f'; val *= 100; add_pct = 1; } if (precision < 0) precision = default_precision; else if (type == 'r') type = 'g'; /* Cast "type", because if we're in unicode we need to pass an 8-bit char. This is safe, because we've restricted what "type" can be. */ buf = PyOS_double_to_string(val, (char)type, precision, flags, &float_type); if (buf == NULL) goto done; n_digits = strlen(buf); if (add_pct) { /* We know that buf has a trailing zero (since we just called strlen() on it), and we don't use that fact any more. So we can just write over the trailing zero. */ buf[n_digits] = '%'; n_digits += 1; } if (format->sign != '+' && format->sign != ' ' && format->width == -1 && format->type != 'n' && !format->thousands_separators) { /* Fast path */ result = _PyUnicodeWriter_WriteASCIIString(writer, buf, n_digits); PyMem_Free(buf); return result; } /* Since there is no unicode version of PyOS_double_to_string, just use the 8 bit version and then convert to unicode. */ unicode_tmp = _PyUnicode_FromASCII(buf, n_digits); PyMem_Free(buf); if (unicode_tmp == NULL) goto done; /* Is a sign character present in the output? If so, remember it and skip it */ index = 0; if (PyUnicode_READ_CHAR(unicode_tmp, index) == '-') { sign_char = '-'; ++index; --n_digits; } /* Determine if we have any "remainder" (after the digits, might include decimal or exponent or both (or neither)) */ parse_number(unicode_tmp, index, index + n_digits, &n_remainder, &has_decimal); /* Determine the grouping, separator, and decimal point, if any. */ if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE : format->thousands_separators, &locale) == -1) goto done; /* Calculate how much memory we'll need. */ n_total = calc_number_widths(&spec, 0, sign_char, index, index + n_digits, n_remainder, has_decimal, &locale, format, &maxchar); if (n_total == -1) { goto done; } /* Allocate the memory. */ if (_PyUnicodeWriter_Prepare(writer, n_total, maxchar) == -1) goto done; /* Populate the memory. */ result = fill_number(writer, &spec, unicode_tmp, index, NULL, 0, format->fill_char, &locale, 0); done: Py_XDECREF(unicode_tmp); free_locale_info(&locale); return result; } /************************************************************************/ /*********** complex formatting *****************************************/ /************************************************************************/ static int format_complex_internal(PyObject *value, const InternalFormatSpec *format, _PyUnicodeWriter *writer) { double re; double im; char *re_buf = NULL; /* buffer returned from PyOS_double_to_string */ char *im_buf = NULL; /* buffer returned from PyOS_double_to_string */ InternalFormatSpec tmp_format = *format; Py_ssize_t n_re_digits; Py_ssize_t n_im_digits; Py_ssize_t n_re_remainder; Py_ssize_t n_im_remainder; Py_ssize_t n_re_total; Py_ssize_t n_im_total; int re_has_decimal; int im_has_decimal; int precision, default_precision = 6; Py_UCS4 type = format->type; Py_ssize_t i_re; Py_ssize_t i_im; NumberFieldWidths re_spec; NumberFieldWidths im_spec; int flags = 0; int result = -1; Py_UCS4 maxchar = 127; int rkind; void *rdata; Py_UCS4 re_sign_char = '\0'; Py_UCS4 im_sign_char = '\0'; int re_float_type; /* Used to see if we have a nan, inf, or regular float. */ int im_float_type; int add_parens = 0; int skip_re = 0; Py_ssize_t lpad; Py_ssize_t rpad; Py_ssize_t total; PyObject *re_unicode_tmp = NULL; PyObject *im_unicode_tmp = NULL; /* Locale settings, either from the actual locale or from a hard-code pseudo-locale */ LocaleInfo locale = LocaleInfo_STATIC_INIT; if (format->precision > INT_MAX) { PyErr_SetString(PyExc_ValueError, "precision too big"); goto done; } precision = (int)format->precision; /* Zero padding is not allowed. */ if (format->fill_char == '0') { PyErr_SetString(PyExc_ValueError, "Zero padding is not allowed in complex format " "specifier"); goto done; } /* Neither is '=' alignment . */ if (format->align == '=') { PyErr_SetString(PyExc_ValueError, "'=' alignment flag is not allowed in complex format " "specifier"); goto done; } re = PyComplex_RealAsDouble(value); if (re == -1.0 && PyErr_Occurred()) goto done; im = PyComplex_ImagAsDouble(value); if (im == -1.0 && PyErr_Occurred()) goto done; if (format->alternate) flags |= Py_DTSF_ALT; if (format->no_neg_0) flags |= Py_DTSF_NO_NEG_0; if (type == '\0') { /* Omitted type specifier. Should be like str(self). */ type = 'r'; default_precision = 0; if (re == 0.0 && copysign(1.0, re) == 1.0) skip_re = 1; else add_parens = 1; } if (type == 'n') /* 'n' is the same as 'g', except for the locale used to format the result. We take care of that later. */ type = 'g'; if (precision < 0) precision = default_precision; else if (type == 'r') type = 'g'; /* Cast "type", because if we're in unicode we need to pass an 8-bit char. This is safe, because we've restricted what "type" can be. */ re_buf = PyOS_double_to_string(re, (char)type, precision, flags, &re_float_type); if (re_buf == NULL) goto done; im_buf = PyOS_double_to_string(im, (char)type, precision, flags, &im_float_type); if (im_buf == NULL) goto done; n_re_digits = strlen(re_buf); n_im_digits = strlen(im_buf); /* Since there is no unicode version of PyOS_double_to_string, just use the 8 bit version and then convert to unicode. */ re_unicode_tmp = _PyUnicode_FromASCII(re_buf, n_re_digits); if (re_unicode_tmp == NULL) goto done; i_re = 0; im_unicode_tmp = _PyUnicode_FromASCII(im_buf, n_im_digits); if (im_unicode_tmp == NULL) goto done; i_im = 0; /* Is a sign character present in the output? If so, remember it and skip it */ if (PyUnicode_READ_CHAR(re_unicode_tmp, i_re) == '-') { re_sign_char = '-'; ++i_re; --n_re_digits; } if (PyUnicode_READ_CHAR(im_unicode_tmp, i_im) == '-') { im_sign_char = '-'; ++i_im; --n_im_digits; } /* Determine if we have any "remainder" (after the digits, might include decimal or exponent or both (or neither)) */ parse_number(re_unicode_tmp, i_re, i_re + n_re_digits, &n_re_remainder, &re_has_decimal); parse_number(im_unicode_tmp, i_im, i_im + n_im_digits, &n_im_remainder, &im_has_decimal); /* Determine the grouping, separator, and decimal point, if any. */ if (get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE : format->thousands_separators, &locale) == -1) goto done; /* Turn off any padding. We'll do it later after we've composed the numbers without padding. */ tmp_format.fill_char = '\0'; tmp_format.align = '<'; tmp_format.width = -1; /* Calculate how much memory we'll need. */ n_re_total = calc_number_widths(&re_spec, 0, re_sign_char, i_re, i_re + n_re_digits, n_re_remainder, re_has_decimal, &locale, &tmp_format, &maxchar); if (n_re_total == -1) { goto done; } /* Same formatting, but always include a sign, unless the real part is * going to be omitted, in which case we use whatever sign convention was * requested by the original format. */ if (!skip_re) tmp_format.sign = '+'; n_im_total = calc_number_widths(&im_spec, 0, im_sign_char, i_im, i_im + n_im_digits, n_im_remainder, im_has_decimal, &locale, &tmp_format, &maxchar); if (n_im_total == -1) { goto done; } if (skip_re) n_re_total = 0; /* Add 1 for the 'j', and optionally 2 for parens. */ calc_padding(n_re_total + n_im_total + 1 + add_parens * 2, format->width, format->align, &lpad, &rpad, &total); if (lpad || rpad) maxchar = Py_MAX(maxchar, format->fill_char); if (_PyUnicodeWriter_Prepare(writer, total, maxchar) == -1) goto done; rkind = writer->kind; rdata = writer->data; /* Populate the memory. First, the padding. */ result = fill_padding(writer, n_re_total + n_im_total + 1 + add_parens * 2, format->fill_char, lpad, rpad); if (result == -1) goto done; if (add_parens) { PyUnicode_WRITE(rkind, rdata, writer->pos, '('); writer->pos++; } if (!skip_re) { result = fill_number(writer, &re_spec, re_unicode_tmp, i_re, NULL, 0, 0, &locale, 0); if (result == -1) goto done; } result = fill_number(writer, &im_spec, im_unicode_tmp, i_im, NULL, 0, 0, &locale, 0); if (result == -1) goto done; PyUnicode_WRITE(rkind, rdata, writer->pos, 'j'); writer->pos++; if (add_parens) { PyUnicode_WRITE(rkind, rdata, writer->pos, ')'); writer->pos++; } writer->pos += rpad; done: PyMem_Free(re_buf); PyMem_Free(im_buf); Py_XDECREF(re_unicode_tmp); Py_XDECREF(im_unicode_tmp); free_locale_info(&locale); return result; } /************************************************************************/ /*********** built in formatters ****************************************/ /************************************************************************/ static int format_obj(PyObject *obj, _PyUnicodeWriter *writer) { PyObject *str; int err; str = PyObject_Str(obj); if (str == NULL) return -1; err = _PyUnicodeWriter_WriteStr(writer, str); Py_DECREF(str); return err; } int _PyUnicode_FormatAdvancedWriter(_PyUnicodeWriter *writer, PyObject *obj, PyObject *format_spec, Py_ssize_t start, Py_ssize_t end) { InternalFormatSpec format; assert(PyUnicode_Check(obj)); /* check for the special case of zero length format spec, make it equivalent to str(obj) */ if (start == end) { if (PyUnicode_CheckExact(obj)) return _PyUnicodeWriter_WriteStr(writer, obj); else return format_obj(obj, writer); } /* parse the format_spec */ if (!parse_internal_render_format_spec(obj, format_spec, start, end, &format, 's', '<')) return -1; /* type conversion? */ switch (format.type) { case 's': /* no type conversion needed, already a string. do the formatting */ return format_string_internal(obj, &format, writer); default: /* unknown */ unknown_presentation_type(format.type, Py_TYPE(obj)->tp_name); return -1; } } int _PyLong_FormatAdvancedWriter(_PyUnicodeWriter *writer, PyObject *obj, PyObject *format_spec, Py_ssize_t start, Py_ssize_t end) { PyObject *tmp = NULL; InternalFormatSpec format; int result = -1; /* check for the special case of zero length format spec, make it equivalent to str(obj) */ if (start == end) { if (PyLong_CheckExact(obj)) return _PyLong_FormatWriter(writer, obj, 10, 0); else return format_obj(obj, writer); } /* parse the format_spec */ if (!parse_internal_render_format_spec(obj, format_spec, start, end, &format, 'd', '>')) goto done; /* type conversion? */ switch (format.type) { case 'b': case 'c': case 'd': case 'o': case 'x': case 'X': case 'n': /* no type conversion needed, already an int. do the formatting */ result = format_long_internal(obj, &format, writer); break; case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case '%': /* convert to float */ tmp = PyNumber_Float(obj); if (tmp == NULL) goto done; result = format_float_internal(tmp, &format, writer); break; default: /* unknown */ unknown_presentation_type(format.type, Py_TYPE(obj)->tp_name); goto done; } done: Py_XDECREF(tmp); return result; } int _PyFloat_FormatAdvancedWriter(_PyUnicodeWriter *writer, PyObject *obj, PyObject *format_spec, Py_ssize_t start, Py_ssize_t end) { InternalFormatSpec format; /* check for the special case of zero length format spec, make it equivalent to str(obj) */ if (start == end) return format_obj(obj, writer); /* parse the format_spec */ if (!parse_internal_render_format_spec(obj, format_spec, start, end, &format, '\0', '>')) return -1; /* type conversion? */ switch (format.type) { case '\0': /* No format code: like 'g', but with at least one decimal. */ case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case 'n': case '%': /* no conversion, already a float. do the formatting */ return format_float_internal(obj, &format, writer); default: /* unknown */ unknown_presentation_type(format.type, Py_TYPE(obj)->tp_name); return -1; } } int _PyComplex_FormatAdvancedWriter(_PyUnicodeWriter *writer, PyObject *obj, PyObject *format_spec, Py_ssize_t start, Py_ssize_t end) { InternalFormatSpec format; /* check for the special case of zero length format spec, make it equivalent to str(obj) */ if (start == end) return format_obj(obj, writer); /* parse the format_spec */ if (!parse_internal_render_format_spec(obj, format_spec, start, end, &format, '\0', '>')) return -1; /* type conversion? */ switch (format.type) { case '\0': /* No format code: like 'g', but with at least one decimal. */ case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case 'n': /* no conversion, already a complex. do the formatting */ return format_complex_internal(obj, &format, writer); default: /* unknown */ unknown_presentation_type(format.type, Py_TYPE(obj)->tp_name); return -1; } } ================================================ FILE: Frame.c ================================================ #define _PY_INTERPRETER #include "Python.h" #include "frameobject.h" #include "pycore_code.h" // stats #include "pycore_frame.h" #include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "opcode.h" int _PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg) { Py_VISIT(frame->frame_obj); Py_VISIT(frame->f_locals); Py_VISIT(frame->f_funcobj); Py_VISIT(frame->f_code); /* locals */ PyObject **locals = _PyFrame_GetLocalsArray(frame); int i = 0; /* locals and stack */ for (; i stacktop; i++) { Py_VISIT(locals[i]); } return 0; } PyFrameObject * _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame) { assert(frame->frame_obj == NULL); PyObject *exc = PyErr_GetRaisedException(); PyFrameObject *f = _PyFrame_New_NoTrack(frame->f_code); if (f == NULL) { Py_XDECREF(exc); return NULL; } PyErr_SetRaisedException(exc); if (frame->frame_obj) { // GH-97002: How did we get into this horrible situation? Most likely, // allocating f triggered a GC collection, which ran some code that // *also* created the same frame... while we were in the middle of // creating it! See test_sneaky_frame_object in test_frame.py for a // concrete example. // // Regardless, just throw f away and use that frame instead, since it's // already been exposed to user code. It's actually a bit tricky to do // this, since we aren't backed by a real _PyInterpreterFrame anymore. // Just pretend that we have an owned, cleared frame so frame_dealloc // doesn't make the situation worse: f->f_frame = (_PyInterpreterFrame *)f->_f_frame_data; f->f_frame->owner = FRAME_CLEARED; f->f_frame->frame_obj = f; Py_DECREF(f); return frame->frame_obj; } assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT); assert(frame->owner != FRAME_CLEARED); f->f_frame = frame; frame->frame_obj = f; return f; } void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest) { assert(src->stacktop >= src->f_code->co_nlocalsplus); Py_ssize_t size = ((char*)&src->localsplus[src->stacktop]) - (char *)src; memcpy(dest, src, size); // Don't leave a dangling pointer to the old frame when creating generators // and coroutines: dest->previous = NULL; } static void take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame) { assert(frame->owner != FRAME_OWNED_BY_CSTACK); assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT); assert(frame->owner != FRAME_CLEARED); Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame; Py_INCREF(frame->f_code); memcpy((_PyInterpreterFrame *)f->_f_frame_data, frame, size); frame = (_PyInterpreterFrame *)f->_f_frame_data; f->f_frame = frame; frame->owner = FRAME_OWNED_BY_FRAME_OBJECT; if (_PyFrame_IsIncomplete(frame)) { // This may be a newly-created generator or coroutine frame. Since it's // dead anyways, just pretend that the first RESUME ran: PyCodeObject *code = frame->f_code; frame->prev_instr = _PyCode_CODE(code) + code->_co_firsttraceable; } assert(!_PyFrame_IsIncomplete(frame)); assert(f->f_back == NULL); _PyInterpreterFrame *prev = _PyFrame_GetFirstComplete(frame->previous); frame->previous = NULL; if (prev) { assert(prev->owner != FRAME_OWNED_BY_CSTACK); /* Link PyFrameObjects.f_back and remove link through _PyInterpreterFrame.previous */ PyFrameObject *back = _PyFrame_GetFrameObject(prev); if (back == NULL) { /* Memory error here. */ assert(PyErr_ExceptionMatches(PyExc_MemoryError)); /* Nothing we can do about it */ PyErr_Clear(); } else { f->f_back = (PyFrameObject *)Py_NewRef(back); } } if (!_PyObject_GC_IS_TRACKED((PyObject *)f)) { _PyObject_GC_TRACK((PyObject *)f); } } void _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame) { /* It is the responsibility of the owning generator/coroutine * to have cleared the enclosing generator, if any. */ assert(frame->owner != FRAME_OWNED_BY_GENERATOR || _PyFrame_GetGenerator(frame)->gi_frame_state == FRAME_CLEARED); // GH-99729: Clearing this frame can expose the stack (via finalizers). It's // crucial that this frame has been unlinked, and is no longer visible: assert(_PyThreadState_GET()->cframe->current_frame != frame); if (frame->frame_obj) { PyFrameObject *f = frame->frame_obj; frame->frame_obj = NULL; if (Py_REFCNT(f) > 1) { take_ownership(f, frame); Py_DECREF(f); return; } Py_DECREF(f); } assert(frame->stacktop >= 0); for (int i = 0; i < frame->stacktop; i++) { Py_XDECREF(frame->localsplus[i]); } Py_XDECREF(frame->frame_obj); Py_XDECREF(frame->f_locals); Py_DECREF(frame->f_funcobj); } /* Unstable API functions */ PyObject * PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame) { PyObject *code = (PyObject *)frame->f_code; Py_INCREF(code); return code; } int PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame) { return _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); } int PyUnstable_InterpreterFrame_GetLine(_PyInterpreterFrame *frame) { int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); return PyCode_Addr2Line(frame->f_code, addr); } ================================================ FILE: Frozen.c ================================================ /* Frozen modules initializer * * Frozen modules are written to header files by Programs/_freeze_module. * These files are typically put in Python/frozen_modules/. Each holds * an array of bytes named "_Py_M__", which is used below. * * These files must be regenerated any time the corresponding .pyc * file would change (including with changes to the compiler, bytecode * format, marshal format). This can be done with "make regen-frozen". * That make target just runs Tools/build/freeze_modules.py. * * The freeze_modules.py script also determines which modules get * frozen. Update the list at the top of the script to add, remove, * or modify the target modules. Then run the script * (or run "make regen-frozen"). * * The script does the following: * * 1. run Programs/_freeze_module on the target modules * 2. update the includes and _PyImport_FrozenModules[] in this file * 3. update the FROZEN_FILES variable in Makefile.pre.in * 4. update the per-module targets in Makefile.pre.in * 5. update the lists of modules in PCbuild/_freeze_module.vcxproj and * PCbuild/_freeze_module.vcxproj.filters * * (Note that most of the data in this file is auto-generated by the script.) * * Those steps can also be done manually, though this is not recommended. * Expect such manual changes to be removed the next time * freeze_modules.py runs. * */ /* In order to test the support for frozen modules, by default we define some simple frozen modules: __hello__, __phello__ (a package), and __phello__.spam. Loading any will print some famous words... */ #include "Python.h" #include "pycore_import.h" #include /* Includes for frozen modules: */ #include "frozen_modules/importlib._bootstrap.h" #include "frozen_modules/importlib._bootstrap_external.h" #include "frozen_modules/zipimport.h" #include "frozen_modules/abc.h" #include "frozen_modules/codecs.h" #include "frozen_modules/io.h" #include "frozen_modules/_collections_abc.h" #include "frozen_modules/_sitebuiltins.h" #include "frozen_modules/genericpath.h" #include "frozen_modules/ntpath.h" #include "frozen_modules/posixpath.h" #include "frozen_modules/os.h" #include "frozen_modules/site.h" #include "frozen_modules/stat.h" #include "frozen_modules/importlib.util.h" #include "frozen_modules/importlib.machinery.h" #include "frozen_modules/runpy.h" #include "frozen_modules/__hello__.h" #include "frozen_modules/__phello__.h" #include "frozen_modules/__phello__.ham.h" #include "frozen_modules/__phello__.ham.eggs.h" #include "frozen_modules/__phello__.spam.h" #include "frozen_modules/frozen_only.h" /* End includes */ #define GET_CODE(name) _Py_get_##name##_toplevel /* Start extern declarations */ extern PyObject *_Py_get_importlib__bootstrap_toplevel(void); extern PyObject *_Py_get_importlib__bootstrap_external_toplevel(void); extern PyObject *_Py_get_zipimport_toplevel(void); extern PyObject *_Py_get_abc_toplevel(void); extern PyObject *_Py_get_codecs_toplevel(void); extern PyObject *_Py_get_io_toplevel(void); extern PyObject *_Py_get__collections_abc_toplevel(void); extern PyObject *_Py_get__sitebuiltins_toplevel(void); extern PyObject *_Py_get_genericpath_toplevel(void); extern PyObject *_Py_get_ntpath_toplevel(void); extern PyObject *_Py_get_posixpath_toplevel(void); extern PyObject *_Py_get_posixpath_toplevel(void); extern PyObject *_Py_get_os_toplevel(void); extern PyObject *_Py_get_site_toplevel(void); extern PyObject *_Py_get_stat_toplevel(void); extern PyObject *_Py_get_importlib_util_toplevel(void); extern PyObject *_Py_get_importlib_machinery_toplevel(void); extern PyObject *_Py_get_runpy_toplevel(void); extern PyObject *_Py_get___hello___toplevel(void); extern PyObject *_Py_get___hello___toplevel(void); extern PyObject *_Py_get___hello___toplevel(void); extern PyObject *_Py_get___hello___toplevel(void); extern PyObject *_Py_get___phello___toplevel(void); extern PyObject *_Py_get___phello___toplevel(void); extern PyObject *_Py_get___phello___ham_toplevel(void); extern PyObject *_Py_get___phello___ham_toplevel(void); extern PyObject *_Py_get___phello___ham_eggs_toplevel(void); extern PyObject *_Py_get___phello___spam_toplevel(void); extern PyObject *_Py_get_frozen_only_toplevel(void); /* End extern declarations */ static const struct _frozen bootstrap_modules[] = { {"_frozen_importlib", _Py_M__importlib__bootstrap, (int)sizeof(_Py_M__importlib__bootstrap), false, GET_CODE(importlib__bootstrap)}, {"_frozen_importlib_external", _Py_M__importlib__bootstrap_external, (int)sizeof(_Py_M__importlib__bootstrap_external), false, GET_CODE(importlib__bootstrap_external)}, {"zipimport", _Py_M__zipimport, (int)sizeof(_Py_M__zipimport), false, GET_CODE(zipimport)}, {0, 0, 0} /* bootstrap sentinel */ }; static const struct _frozen stdlib_modules[] = { /* stdlib - startup, without site (python -S) */ {"abc", _Py_M__abc, (int)sizeof(_Py_M__abc), false, GET_CODE(abc)}, {"codecs", _Py_M__codecs, (int)sizeof(_Py_M__codecs), false, GET_CODE(codecs)}, {"io", _Py_M__io, (int)sizeof(_Py_M__io), false, GET_CODE(io)}, /* stdlib - startup, with site */ {"_collections_abc", _Py_M___collections_abc, (int)sizeof(_Py_M___collections_abc), false, GET_CODE(_collections_abc)}, {"_sitebuiltins", _Py_M___sitebuiltins, (int)sizeof(_Py_M___sitebuiltins), false, GET_CODE(_sitebuiltins)}, {"genericpath", _Py_M__genericpath, (int)sizeof(_Py_M__genericpath), false, GET_CODE(genericpath)}, {"ntpath", _Py_M__ntpath, (int)sizeof(_Py_M__ntpath), false, GET_CODE(ntpath)}, {"posixpath", _Py_M__posixpath, (int)sizeof(_Py_M__posixpath), false, GET_CODE(posixpath)}, {"os.path", _Py_M__posixpath, (int)sizeof(_Py_M__posixpath), false, GET_CODE(posixpath)}, {"os", _Py_M__os, (int)sizeof(_Py_M__os), false, GET_CODE(os)}, {"site", _Py_M__site, (int)sizeof(_Py_M__site), false, GET_CODE(site)}, {"stat", _Py_M__stat, (int)sizeof(_Py_M__stat), false, GET_CODE(stat)}, /* runpy - run module with -m */ {"importlib.util", _Py_M__importlib_util, (int)sizeof(_Py_M__importlib_util), false, GET_CODE(importlib_util)}, {"importlib.machinery", _Py_M__importlib_machinery, (int)sizeof(_Py_M__importlib_machinery), false, GET_CODE(importlib_machinery)}, {"runpy", _Py_M__runpy, (int)sizeof(_Py_M__runpy), false, GET_CODE(runpy)}, {0, 0, 0} /* stdlib sentinel */ }; static const struct _frozen test_modules[] = { {"__hello__", _Py_M____hello__, (int)sizeof(_Py_M____hello__), false, GET_CODE(__hello__)}, {"__hello_alias__", _Py_M____hello__, (int)sizeof(_Py_M____hello__), false, GET_CODE(__hello__)}, {"__phello_alias__", _Py_M____hello__, (int)sizeof(_Py_M____hello__), true, GET_CODE(__hello__)}, {"__phello_alias__.spam", _Py_M____hello__, (int)sizeof(_Py_M____hello__), false, GET_CODE(__hello__)}, {"__phello__", _Py_M____phello__, (int)sizeof(_Py_M____phello__), true, GET_CODE(__phello__)}, {"__phello__.__init__", _Py_M____phello__, (int)sizeof(_Py_M____phello__), false, GET_CODE(__phello__)}, {"__phello__.ham", _Py_M____phello___ham, (int)sizeof(_Py_M____phello___ham), true, GET_CODE(__phello___ham)}, {"__phello__.ham.__init__", _Py_M____phello___ham, (int)sizeof(_Py_M____phello___ham), false, GET_CODE(__phello___ham)}, {"__phello__.ham.eggs", _Py_M____phello___ham_eggs, (int)sizeof(_Py_M____phello___ham_eggs), false, GET_CODE(__phello___ham_eggs)}, {"__phello__.spam", _Py_M____phello___spam, (int)sizeof(_Py_M____phello___spam), false, GET_CODE(__phello___spam)}, {"__hello_only__", _Py_M__frozen_only, (int)sizeof(_Py_M__frozen_only), false, GET_CODE(frozen_only)}, {0, 0, 0} /* test sentinel */ }; const struct _frozen *_PyImport_FrozenBootstrap = bootstrap_modules; const struct _frozen *_PyImport_FrozenStdlib = stdlib_modules; const struct _frozen *_PyImport_FrozenTest = test_modules; static const struct _module_alias aliases[] = { {"_frozen_importlib", "importlib._bootstrap"}, {"_frozen_importlib_external", "importlib._bootstrap_external"}, {"os.path", "posixpath"}, {"__hello_alias__", "__hello__"}, {"__phello_alias__", "__hello__"}, {"__phello_alias__.spam", "__hello__"}, {"__phello__.__init__", "<__phello__"}, {"__phello__.ham.__init__", "<__phello__.ham"}, {"__hello_only__", NULL}, {0, 0} /* aliases sentinel */ }; const struct _module_alias *_PyImport_FrozenAliases = aliases; /* Embedding apps may change this pointer to point to their favorite collection of frozen modules: */ const struct _frozen *PyImport_FrozenModules = NULL; ================================================ FILE: FrozenMain.c ================================================ /* Python interpreter main program for frozen scripts */ #include "Python.h" #include "pycore_runtime.h" // _PyRuntime_Initialize() #include #ifdef MS_WINDOWS extern void PyWinFreeze_ExeInit(void); extern void PyWinFreeze_ExeTerm(void); extern int PyInitFrozenExtensions(void); #endif /* Main program */ int Py_FrozenMain(int argc, char **argv) { PyStatus status = _PyRuntime_Initialize(); if (PyStatus_Exception(status)) { Py_ExitStatusException(status); } PyConfig config; PyConfig_InitPythonConfig(&config); // Suppress errors from getpath.c config.pathconfig_warnings = 0; // Don't parse command line options like -E config.parse_argv = 0; status = PyConfig_SetBytesArgv(&config, argc, argv); if (PyStatus_Exception(status)) { PyConfig_Clear(&config); Py_ExitStatusException(status); } const char *p; int inspect = 0; if ((p = Py_GETENV("PYTHONINSPECT")) && *p != '\0') { inspect = 1; } #ifdef MS_WINDOWS PyInitFrozenExtensions(); #endif /* MS_WINDOWS */ status = Py_InitializeFromConfig(&config); PyConfig_Clear(&config); if (PyStatus_Exception(status)) { Py_ExitStatusException(status); } #ifdef MS_WINDOWS PyWinFreeze_ExeInit(); #endif if (_Py_GetConfig()->verbose) { fprintf(stderr, "Python %s\n%s\n", Py_GetVersion(), Py_GetCopyright()); } int sts = 1; int n = PyImport_ImportFrozenModule("__main__"); if (n == 0) { Py_FatalError("the __main__ module is not frozen"); } if (n < 0) { PyErr_Print(); sts = 1; } else { sts = 0; } if (inspect && isatty((int)fileno(stdin))) { sts = PyRun_AnyFile(stdin, "") != 0; } #ifdef MS_WINDOWS PyWinFreeze_ExeTerm(); #endif if (Py_FinalizeEx() < 0) { sts = 120; } return sts; } ================================================ FILE: Future.c ================================================ #include "Python.h" #include "pycore_ast.h" // _PyAST_GetDocString() #define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined" static int future_check_features(PyFutureFeatures *ff, stmt_ty s, PyObject *filename) { int i; assert(s->kind == ImportFrom_kind); asdl_alias_seq *names = s->v.ImportFrom.names; for (i = 0; i < asdl_seq_LEN(names); i++) { alias_ty name = (alias_ty)asdl_seq_GET(names, i); const char *feature = PyUnicode_AsUTF8(name->name); if (!feature) return 0; if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) { continue; } else if (strcmp(feature, FUTURE_GENERATORS) == 0) { continue; } else if (strcmp(feature, FUTURE_DIVISION) == 0) { continue; } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) { continue; } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) { continue; } else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) { continue; } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) { continue; } else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) { ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL; } else if (strcmp(feature, FUTURE_GENERATOR_STOP) == 0) { continue; } else if (strcmp(feature, FUTURE_ANNOTATIONS) == 0) { ff->ff_features |= CO_FUTURE_ANNOTATIONS; } else if (strcmp(feature, "braces") == 0) { PyErr_SetString(PyExc_SyntaxError, "not a chance"); PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1); return 0; } else { PyErr_Format(PyExc_SyntaxError, UNDEFINED_FUTURE_FEATURE, feature); PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1); return 0; } } return 1; } static int future_parse(PyFutureFeatures *ff, mod_ty mod, PyObject *filename) { if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) { return 1; } Py_ssize_t n = asdl_seq_LEN(mod->v.Module.body); if (n == 0) { return 1; } Py_ssize_t i = 0; if (_PyAST_GetDocString(mod->v.Module.body) != NULL) { i++; } for (; i < n; i++) { stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i); /* The only things that can precede a future statement * are another future statement and a doc string. */ if (s->kind == ImportFrom_kind) { identifier modname = s->v.ImportFrom.module; if (modname && _PyUnicode_EqualToASCIIString(modname, "__future__")) { if (!future_check_features(ff, s, filename)) { return 0; } ff->ff_location = SRC_LOCATION_FROM_AST(s); } else { return 1; } } else { return 1; } } return 1; } int _PyFuture_FromAST(mod_ty mod, PyObject *filename, PyFutureFeatures *ff) { ff->ff_features = 0; ff->ff_location = (_PyCompilerSrcLocation){-1, -1, -1, -1}; if (!future_parse(ff, mod, filename)) { return 0; } return 1; } ================================================ FILE: Game/CMakeLists.txt ================================================ enable_language(ASM_NASM) set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64) set(CMAKE_ASM_NASM_LINK_EXECUTABLE "ld -o ") set(CMAKE_ASM_NASM_FLAGS_DEBUG "-g -Fdwarf") set(SOURCE_FILES graphics.asm linked_list.asm main.asm memory.asm utils.asm ) set_source_files_properties(${SOURCE_FILES} PROPERTIES LANGUAGE ASM_NASM) add_executable(asm_game ${SOURCE_FILES} ) target_link_libraries(asm_game X11) target_link_options(asm_game PRIVATE --dynamic-linker /lib64/ld-linux-x86-64.so.2) ================================================ FILE: Game/graphics.asm ================================================ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Distributed under the Boost Software License, Version 1.0. ;; ;; (See accompanying file LICENSE or copy at ;; ;; https://www.boost.org/LICENSE_1_0.txt) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; global create_window global try_get_event extern XBlackPixel extern XCheckWindowEvent extern XClearWindow extern XCreateGC extern XCreateSimpleWindow extern XDefaultRootWindow extern XDefaultScreen extern XFillRectangle extern XFlush extern XLookupKeysym extern XMapWindow extern XNextEvent extern XSync extern XOpenDisplay extern XSelectInput extern XSetForeground extern XWhitePixel extern assert_not_null extern assert_null extern render_begin extern draw_rectangle extern render_end extern print extern print_num ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; This file contains functions for creating a window and rendering to it. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Create and display an X Window. ; create_window: push rbp mov rbp, rsp ; X11 window setup mov rdi, 0x0 call XOpenDisplay mov [display], rax mov rdi, rax lea rsi, [x_open_display_failed] call assert_not_null call XDefaultScreen mov [screen_number], rax mov rdi, [display] mov rsi, [screen_number] call XWhitePixel mov [white_colour], rax mov rdi, [display] mov rsi, [screen_number] call XBlackPixel mov [black_colour], rax mov rdi, [display] call XDefaultRootWindow mov [default_root_window], rax mov rdi, [display] mov rsi, [default_root_window] mov rdx, 0x0 mov rcx, 0x0 mov r8, 0x320 mov r9, 0x320 mov rax, [black_colour] push rax push rax push 0x0 call XCreateSimpleWindow mov [window], rax add rsp, 0x18 mov rdi, [display] mov rsi, [window] mov rdx, 0x20003 call XSelectInput mov rdi, [display] mov rsi, [window] call XMapWindow mov rdi, [display] mov rsi, [window] mov rdx, 0x0 mov rcx, 0x0 call XCreateGC mov [gc], rax ; wait until window has appeared wait_loop_start: mov rdi, [display] lea rsi, [event] call XNextEvent mov eax, [event] cmp rax, 0x13 je wait_loop_end jmp wait_loop_start wait_loop_end: pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Try and get an event ; ; @returns ; Address of an event, or 0x0 if no event was available. ; try_get_event: push rbp mov rbp, rsp ; see if we want have events mov rdi, [display] mov rsi, [window] mov rdx, 0x03 lea rcx, [event] call XCheckWindowEvent cmp rax, 0x0 je try_get_event_end ; we got an event so return pointer to event object lea rax, [event] try_get_event_end: pop rbp ret ; Perform pre-render tasks render_begin: push rbp mov rbp, rsp ; clear window mov rdi, [display] mov rsi, [window] call XClearWindow pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Draw a rectangle. ; ; @param rdi ; X coord of rectangle ; ; @param rsi ; Y coord of rectangle ; ; @param rdx ; Width of rectangle ; ; @param rcx ; Height of rectangle ; draw_rectangle: push rbp mov rbp, rsp ; push args to stack so we can easily pop them into the correct registers push rcx push rdx push rsi push rdi ; set foreground color for drawing mov rdi, [display] mov rsi, [gc] mov rdx, [white_colour] call XSetForeground ; draw paddle mov rdi, [display] mov rsi, [window] mov rdx, [gc] pop rcx pop r8 pop r9 ; note that the last arg is now at at the top of the stack call XFillRectangle add rsp, 0x8 pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Perform post-render tasks ; render_end: push rbp mov rbp, rsp ; ensure all draw commands are flushed mov rdi, [display] call XFlush pop rbp ret section .data display: dq 0x0 screen_number: dq 0x0 black_colour: dq 0x0 white_colour: dq 0x0 default_root_window: dq 0x0 window: dq 0x0 gc: dq 0x0 event: resb 0xc0 section .rodata hello_world: db "hello world", 0xa, 0x0 goodbye: db "goodbye", 0xa, 0x0 sleep_for: db "sleep_for: ", 0x0 x_open_display_failed: db "XOpenDisplay failed", 0xa, 0x0 x_select_input_failed: db "XSelectInput failed", 0xa, 0x0 x_set_foreground_failed: db "XSetForeground failed", 0xa, 0x0 ================================================ FILE: Game/linked_list.asm ================================================ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Distributed under the Boost Software License, Version 1.0. ;; ;; (See accompanying file LICENSE or copy at ;; ;; https://www.boost.org/LICENSE_1_0.txt) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; global linked_list_init global linked_list_iterator global linked_list_iterator_advance global linked_list_iterator_remove global linked_list_iterator_value global linked_list_push_back extern memory_malloc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Simple linked list data structure. Consists of a head node then optional data nodes. ; Each node has the following layout: ; +-------+ ; | value | = 8 bytes ; +-------+ ; | ptr | = 8 bytes ; +-------+ ; ; This means that each node can store 8 bytes of data, which could be anything, even a pointer to a larger allocated ; block of data ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Create a new linked list. ; ; @returns ; A handle to the linked list which can be passed to further linked list methods. ; linked_list_init: push rbp mov rbp, rsp mov rdi, 0x0 call allocate_node ; create the head node ; we return the head node as the handle pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Insert a new value to the back of the linked list. ; ; @param rdi ; Handle to linked list to insert into. ; ; @param rsi ; Value to insert. ; ; @returns ; Address if newly created node. ; linked_list_push_back: push rbp mov rbp, rsp mov rbx, rdi ; find end of list linked_list_push_back_find_end: mov rcx, [rbx + 0x8] ; get next pointer cmp rcx, 0x0 ; if null then we are at the last node je linked_list_push_back_do_insert add rbx, 0x10 jmp linked_list_push_back_find_end linked_list_push_back_do_insert: push rbx mov rdi, rsi call allocate_node ; allocate new node pop rbx mov [rbx + 0x8], rax ; set new node as next of last node mov rax, [rbx + 0x8] ; set return value as address of new node pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Get an iterator to the start of the linked list. This is a handle that can ba passed to other iterator functions. ; ; @rdi ; Handle to list to get iterator for. ; ; @returns ; Iterator handle. ; linked_list_iterator: push rbp mov rbp, rsp call linked_list_iterator_advance ; we can cheat here by just returning the address of the first node after the head pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Remove a node from the linked list. ; ; @param rdi ; Handle to linked list to remove node from. ; ; @parma rsi ; Iterator to remove ; linked_list_iterator_remove: push rbp mov rbp, rsp linked_list_remove_find_begin: mov rax, [rdi + 8] cmp rax, 0x0 je linked_list_remove_end cmp rax, rsi je linked_list_remove_find_end mov rdi, rax jmp linked_list_remove_find_begin linked_list_remove_find_end: mov rbx, [rsi + 8] ; get next of node we are removing mov [rdi + 8], rbx ; set prev nodes next to next of removing node linked_list_remove_end: pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Advance an iterator. ; ; @param rdi ; Handle to iterator to advance. ; ; @returns ; Handle to advanced iterator. ; linked_list_iterator_advance: push rbp mov rbp, rsp mov rax, [rdi + 0x8] pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Get the value from an iterator. ; ; @param rdi ; Handle to iterator to get value for. ; ; @returns ; Value stored in node iterator is referencing. ; linked_list_iterator_value: push rbp mov rbp, rsp mov rax, [rdi] pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Allocate a new node and store a value in it. ; ; @param rdi ; Value to store in node ; ; @returns ; Address of allocated node. ; allocate_node: push rbp mov rbp, rsp push rdi mov rdi, 0x10 call memory_malloc ; allocate space for node pop rdi mov rbx, 0x0 mov [rax], rdi ; store value in node mov [rax + 0x8], rbx ; set next to be null pop rbp ret ================================================ FILE: Game/main.asm ================================================ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Distributed under the Boost Software License, Version 1.0. ;; ;; (See accompanying file LICENSE or copy at ;; ;; https://www.boost.org/LICENSE_1_0.txt) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; section .text global _start extern XBlackPixel extern XClearWindow extern XFillRectangle extern XFlush extern XLookupKeysym extern XSync extern XSetForeground extern XWhitePixel extern assert_not_null extern assert_null extern create_window extern draw_rectangle extern exit extern get_time extern linked_list_init extern linked_list_iterator extern linked_list_iterator_advance extern linked_list_iterator_remove extern linked_list_iterator_value extern linked_list_push_back extern memory_malloc extern print extern print_num extern render_begin extern render_end extern sleep_ms extern try_get_event ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Entry point to the program ; _start: lea rdi, [hello_world] call print call create_entities call create_window main_loop_start: ; get time at start of frame call get_time mov [frame_time], rax call try_get_event mov r12, rax ; no event so go to game logic cmp rax, 0x0 je game_logic ; check if its a press event mov eax, [r12] cmp rax, 0x2 je handle_key ; check if its a release event mov eax, [r12] cmp rax, 0x3 jne game_logic ; if not go to game logic handle_key: ; get the key code for the release event lea rdi, [r12] mov rsi, 0x0 call XLookupKeysym ; see if its an XK_Escape cmp rax, 0xff1b jne handle_arrow_key ; if its key press then exit the game mov eax, [r12] cmp rax, 0x2 je main_loop_end handle_arrow_key: ; if it's not an XK_Right then check if its an XK_Left cmp rax, 0xff53 jne left_check mov eax, [r12] cmp rax, 0x2 jne right_release mov rax, 0x1 mov [right_arrow_status], rax jmp game_logic right_release: mov rax, 0x0 mov [right_arrow_status], rax jmp game_logic left_check: ; if its not an XK_Left then go to game logic cmp rax, 0xff51 jne game_logic mov eax, [r12] cmp rax, 0x2 jne left_release mov rax, 0x1 mov [left_arrow_status], rax jmp game_logic left_release: mov rax, 0x0 mov [left_arrow_status], rax game_logic: mov rax, [right_arrow_status] cmp rax, 0x0 je right_arrow_update_finish mov rax, [paddle_x] add rax, 10 mov [paddle_x], rax right_arrow_update_finish: mov rax, [left_arrow_status] cmp rax, 0x0 je left_arrow_update_finish mov rax, [paddle_x] sub rax, 10 mov [paddle_x], rax left_arrow_update_finish: call ball_update call handle_collisions call render ; get end frame time call get_time ; see if we have spent less than 30ms in this frame mov rbx, [frame_time] sub rax, rbx cmp rax, 30 jg main_loop_start ; sleep for remainder of 30ms mov rbx, 30 sub rbx, rax mov rdi, rbx call sleep_ms jmp main_loop_start main_loop_end: lea rdi, [goodbye] call print mov rdi, 0x0 call exit ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Render the entity list. ; render: push rbp mov rbp, rsp call render_begin mov rdi, [entity_list] call linked_list_iterator push rax render_loop_start: mov rax, [rsp] cmp rax, 0x0 je render_loop_end mov rdi, [rsp] call linked_list_iterator_value mov rdi, [rax] mov rsi, [rax + 8] mov rdx, [rax + 16] mov rcx, [rax + 24] call draw_rectangle mov rdi, [rsp] call linked_list_iterator_advance mov [rsp], rax jmp render_loop_start call render_end render_loop_end: add rsp, 0x8 pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Perform collision detections and resolutions. ; handle_collisions: push rbp mov rbp, rsp sub rsp, 8 mov rdi, [entity_list] call linked_list_iterator mov [rsp], rax mov rdi, [rsp] call linked_list_iterator_advance ; move past first entity so we don't check ball collides with itself mov [rsp], rax ; check collision with paddle mov rdi, [rsp] call linked_list_iterator_value lea rdi, [ball_x] mov rsi, rax call check_entity_collision cmp rax, 0x0 je paddle_collision_end call handle_ball_paddle_collision paddle_collision_end: mov rdi, [rsp] call linked_list_iterator_advance ; move passed paddle, onto the bricks mov [rsp], rax brick_collision_loop_start: ; if we are at the end of the linked list then stop mov rax, [rsp] cmp rax, 0x0 je brick_collision_loop_end ; get value from the iterator (which will be the address of an entity) mov rdi, [rsp] call linked_list_iterator_value ; check if ball is colliding with block lea rdi, [ball_x] mov rsi, rax call check_entity_collision cmp rax, 0x0 jne handle_collision_found ; if no collision then move iterator to next block mov rdi, [rsp] call linked_list_iterator_advance mov [rsp], rax jmp brick_collision_loop_start handle_collision_found: ; remove block from linked list mov rdi, [entity_list] mov rsi, [rsp] call linked_list_iterator_remove ; invert ball velocity mov rax, 0xa mov [ball_velocity_y], rax brick_collision_loop_end: add rsp, 8 pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Handle ball paddle collision. This function assumes the collision has already been detected and needs resolving. ; handle_ball_paddle_collision: push rbp mov rbp, rsp ; we can simply just grab the data we need without having to go through the linked list mov rax, [ball_x] mov rbx, [paddle_x] ; check of collision happened on the left third of the paddle add rbx, 6 cmp rax, rbx jge check_middle ; if it did then set the ball moving up and left mov rax, -7 mov [ball_velocity_x], rax mov [ball_velocity_y], rax jmp handle_ball_paddle_collision_end check_middle: ; check of collision happened on the middle third of the paddle add rbx, 8 cmp rax, rbx jge check_end ; if it did then set the ball moving straight up mov rax, 0 mov [ball_velocity_x], rax mov rax, -10 mov [ball_velocity_y], rax jmp handle_ball_paddle_collision_end check_end: ; the only other choice is the paddle hit the right third, so move it up and right mov rax, 7 mov [ball_velocity_x], rax mov rax, -7 mov [ball_velocity_y], rax jmp handle_ball_paddle_collision_end handle_ball_paddle_collision_end: pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Check collisions between two entities. ; ; @param rdi ; Address of first entity. ; ; @param rsi ; Address of second entity. ; ; @returns ; 0x1 if collision was detected, otherwise 0x0. ; check_entity_collision: push rbp mov rbp, rsp ; rect1.x < rect2.x + rect2.w mov rax, [rdi] mov rbx, [rsi] mov rcx, [rsi + 16] add rbx, rcx cmp rax, rbx jge no_collision ; rect1.x + rect1.w > rect2.x mov rax, [rdi] mov rbx, [rdi + 16] add rax, rbx mov rcx, [rsi] cmp rax, rcx jle no_collision ; rect1.y < rect2.y + rect2.h mov rax, [rdi + 8] mov rbx, [rsi + 8] mov rcx, [rsi + 24] add rbx, rcx cmp rax, rbx jge no_collision ; rect1.h + rect1.y > rect1.y mov rax, [rdi + 24] mov rbx, [rdi + 8] add rax, rbx mov rcx, [rsi + 8] cmp rax, rcx jle no_collision mov rax, 0x1 jmp check_collision_end no_collision: mov rax, 0x0 check_collision_end: pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Perform ball update logic ; ball_update: push rbp mov rbp, rsp ; add y velocity to ball mov rax, [ball_y] add rax, [ball_velocity_y] mov [ball_y], rax ; add x velocity to ball mov rax, [ball_x] add rax, [ball_velocity_x] mov [ball_x], rax ; check if ball has gone off the top of the screen mov rax, [ball_y] cmp rax, 0x0 jg check_ball_right_side ; invert y velocity mov rax, 0xa mov [ball_velocity_y], rax check_ball_right_side: ; check if ball has gone of right of the screen mov rax, [ball_x] cmp rax, 800 jl check_ball_left_side ; invert x velocity mov rax, [ball_velocity_x] neg rax mov [ball_velocity_x], rax jmp ball_update_end check_ball_left_side: ; check if ball has gone of the left of the screen mov rax, [ball_x] cmp rax, 0 jg ball_update_end ; invert x velocity mov rax, [ball_velocity_x] neg rax mov [ball_velocity_x], rax ball_update_end: pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Create all the entities for the game and insert them into a linked list. ; create_entities: push rbp mov rbp, rsp call linked_list_init mov [entity_list], rax ; collision code assumes ball is first in the entity list, then the paddle then the bricks mov rdi, [entity_list] lea rsi, [ball_x] ; store address of ball in list call linked_list_push_back mov rdi, [entity_list] lea rsi, [paddle_x] ; store address of paddle data in list call linked_list_push_back mov rdi, 50 call create_brick_row mov rdi, 80 call create_brick_row mov rdi, 110 call create_brick_row mov rdi, 140 call create_brick_row mov rdi, 170 call create_brick_row mov rdi, 200 call create_brick_row pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Adds a row of 10 bricks to the entity list ; ; @param rdi ; Y coord of row. ; create_brick_row: push rbp mov rbp, rsp sub rsp, 24 mov [rsp + 16], rdi mov rax, 0 mov [rsp], rax ; store loop counter mov rax, 20 mov [rsp + 8], rax ; store initial x coord create_row_start: mov rax, [rsp] cmp rax, 10 je create_row_end ; leave loop if we have added 10 bricks mov rdi, 32 call memory_malloc ; fill out entity struct mov rbx, [rsp + 8] mov [rax], rbx mov rbx, [rsp + 16] mov [rax + 8], rbx mov rbx, 58 mov [rax + 16], rbx mov rbx, 20 mov [rax + 24], rbx mov rdi, [entity_list] mov rsi, rax call linked_list_push_back ; advance x coord for next iteration mov rax, [rsp + 8] add rax, 78 mov [rsp + 8], rax ; increment iteration count mov rax, [rsp] inc rax mov [rsp], rax jmp create_row_start create_row_end: add rsp, 24 pop rbp ret section .data entity_list: dq 0x0 paddle_x: dq 0x12c paddle_y: dq 0x30c paddle_width: dq 0xc8 paddle_height: dq 0x14 ball_x: dq 0x1a4 ball_y: dq 0x190 ball_width: dq 0xa ball_height: dq 0xa ball_velocity_y: dq 0xa ball_velocity_x: dq 0x0 left_arrow_status: dq 0x0 right_arrow_status: dq 0x0 frame_time: dq 0x0 section .rodata hello_world: db "hello world", 0xa, 0x0 goodbye: db "goodbye", 0xa, 0x0 sleep_for: db "sleep_for: ", 0x0 ================================================ FILE: Game/memory.asm ================================================ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Distributed under the Boost Software License, Version 1.0. ;; ;; (See accompanying file LICENSE or copy at ;; ;; https://www.boost.org/LICENSE_1_0.txt) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; global memory_mmap global memory_malloc extern assert_not_null ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; This file contains various utilities for dynamically allocating memory. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Map new pages into the process. ; ; @param rdi ; Number of bytes to map. ; ; @returns ; Address of allocated memory. ; memory_mmap: push rbp mov rbp, rsp push rdi mov rax, 0x9 mov rdi, 0x0 ; kernel chooses address pop rsi ; number of bytes to map mov rdx, 0x3 ; PROT_READ | PROT_WRITE mov r10, 0x22 ; MAP_PRIVATE | MAP_ANONYMOUS mov r8, 0x0 ; no backing file mov r9, 0x0 ; no offset syscall push rax mov rdi, rax sub rdi, 0xffffffffffffffff ; check MAP_FAILED was not returned lea rsi, [mmap_failed] call assert_not_null pop rax pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Simple implementation of malloc. ; ; Note that there is no equivalent of free, this just allocates memory from a large static buffer. ; ; @param rdi ; Number of bytes to allocate. ; ; @returns ; Address of allocated memory. ; memory_malloc: push rbp mov rbp, rsp push rdi ; if this is the first call then allocate a large fixed size buffer to "malloc" from mov rax, [malloc_init] cmp rax, 0x0 jne malloc_do_init_done mov rdi, 4096000 call memory_mmap mov [malloc_memory], rax mov rax, 0x1 mov [malloc_init], rax malloc_do_init_done: pop rdi mov rax, [malloc_memory] ; get address from head of buffer mov rbx, rax add rbx, rdi ; advance buffer by requested size mov [malloc_memory], rbx pop rbp ret section .data malloc_init: dq 0x0 malloc_memory: dq 0x0 section .rodata mmap_failed: db "mmap failed", 0xa, 0x0 ================================================ FILE: Game/utils.asm ================================================ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Distributed under the Boost Software License, Version 1.0. ;; ;; (See accompanying file LICENSE or copy at ;; ;; https://www.boost.org/LICENSE_1_0.txt) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; global assert_not_null global assert_null global exit global game_malloc global game_mmap global get_time global print global print_num global sleep_ms ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; This file contains various utilities. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Print a string to STDOUT. ; ; @param rdi ; Address of null terminated string to print. ; ; @returns ; Number of bytes output. ; print: push rbp mov rbp, rsp mov r10, rdi ; save off string address mov r9, rdi ; iterator register for string movzx rax, byte [r9] ; load first byte mov rcx, 0x0 ; accumulator for string length count_null_start: cmp rax, 0x0 ; are we at the null byte? je count_null_end inc rcx ; increment accumulator inc r9 ; move to next byte movzx rax, byte [r9] ; load byte jmp count_null_start count_null_end: ; syscall to write string to stdout mov rax, 0x1 mov rdi, 0x1; mov rsi, r10 mov rdx, rcx syscall pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Print an integer to STDOUT (with a new line). ; ; @param rdi ; Unsigned number to print. ; print_num: push rbp mov rbp, rsp sub rsp, 0x15 ; get stack space for two buffers, one to convert the number into a string (in reverse order)] ; and another to reverse the string into mov r9, rdi ; r9 will be the mutable copy of the input number mov rdx, rdi mov rcx, 0x0 ; accumulator for string length mov rdi, rsp ; set destination as start of first buffer write_loop_start: mov rax, r9 ; load number to be divided mov rdx, 0 ; zero out remainder mov r10, 0xa ; divisor by 10 div r10 ; rdx = remainder, rax = quotient mov r11, 0x30 add rdx, r11 ; add 0x30 to remainder to get ASCII code for number mov [rdi], dl ; write ASCII byte to buffer inc rcx ; increment how many characters have been written cmp rax, 0x0 ; check if we have reached the end je write_loop_end inc rdi mov r9, rax ; load remainder into r9 so it can be divided again jmp write_loop_start write_loop_end: mov rsi, rdi ; move destination into source so we can reverse it mov rdi, rsp add rdi, 0xa ; set destination to start of second buffer reverse_loop_start: cmp rcx, 0x0 je reverse_loop_end movzx rax, byte[rsi] mov [rdi], al ; write ascii character into second buffer dec rsi inc rdi dec rcx; ; keep track of how many characters we've reversed jmp reverse_loop_start reverse_loop_end: mov rax, 0xa mov [rdi], al ; write newline character into the end mov rdi, rsp add rdi, 0xa ; print second buffer call print leave ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Assert the input is not null. ; ; @param rdi ; Value to check is not null. ; ; @param rsi ; Pointer to error message string. ; assert_not_null: push rbp mov rbp, rsp cmp rdi, 0x0 jne assert_not_null_end mov rdi, rsi call print mov rdi, 0x1 call exit assert_not_null_end: pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Assert the input is null. ; ; @param rdi ; Value to check is null. ; ; @param rsi ; Pointer to error message string. ; assert_null: push rbp mov rbp, rsp cmp rdi, 0x0 je assert_null_end mov rdi, rsi call print mov rdi, 0x1 call exit assert_null_end: pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Exit the program. ; ; @param rdi ; Exit code. ; exit: mov rax, 0x3c syscall ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Sleep the current process for the supplied number of milliseconds. ; ; @param rdi ; Number of milliseconds to sleep for. ; sleep_ms: push rbp mov rbp, rsp imul rdi, rdi, 1000000 ; convert supplied ms to ns xor rax, rax ; recreate struct timepec on the stack push rdi ; tv_nsec push rax ; tv_sec ; nanosleep syscall mov rax, 0x23 mov rdi, rsp mov rsi, 0x0 syscall add rsp, 16 pop rbp ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Get the time since epoch in milliseconds. ; ; @returns ; Milliseconds since epoch. ; get_time: push rbp mov rbp, rsp ; create empty timeval struct on the stack push 0x0 ; tv_usec push 0x0 ; tv_sec ; gettimeofday syscall mov rax, 0x60 mov rdi, rsp mov rsi, 0x0 syscall pop rax ; seconds pop rbx ; microseconds imul rax, rax, 1000000 ; convert seconds to microseconds add rax, rbx ; add microseconds mov rdx, 0x0 mov rbx, 1000 div rbx ; convert to milliseconds pop rbp ret ================================================ FILE: Game I/CMakeLists.txt ================================================ add_executable(c_game c_list.c c_rectangle.c c_vector2.c c_window.c main.c ) target_link_directories(c_game PRIVATE ${sdl_BINARY_DIR}) target_include_directories(c_game PRIVATE ${sdl_SOURCE_DIR}/include) target_link_libraries(c_game SDL2::SDL2-static) ================================================ FILE: Game I/c_key_event.h ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #pragma once /** * Enumeration of possible key states. */ typedef enum C_KeyState { C_KEYSTATE_DOWN, C_KEYSTATE_UP } C_KeyState; /** * Enumeration of possible input keys (maybe incomplete). */ typedef enum C_Key { C_KEY_ESCAPE, C_KEY_LEFT, C_KEY_RIGHT, } C_Key; /** * Struct encapsulating the data for a key press event. */ typedef struct C_KeyEvent { C_KeyState key_state; C_Key key; } C_KeyEvent; ================================================ FILE: Game I/c_list.c ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #include "c_list.h" #include #include #include "c_result.h" /** * Internal node struct. Stores value, next node and dtor function for value. */ typedef struct Node { void *value; struct Node *next; void (*dtor)(void *); } Node; /** * Internal list struct. Stores a head sentinel node. */ typedef struct C_List { Node *head; } C_List; /** * Internal iterator struct. Stores the node it is referencing. */ typedef struct C_ListIter { Node *node; } C_ListIter; C_Result c_list_create(C_List **list) { assert(list != NULL); C_Result result = C_SUCCESS; // allocate the list C_List *new_list = (C_List *)calloc(sizeof(C_List), 1u); if (new_list == NULL) { result = C_FAILED_TO_ALLOCATE_LIST; goto fail; } // allocate the head node new_list->head = (Node *)calloc(sizeof(Node), 1u); if (new_list->head == NULL) { result = C_FAILED_TO_ALLOCATE_NODE; goto fail; } // assign the list to the user supplied pointer *list = new_list; return result; fail: // clean up and return error code c_list_destroy(new_list); return result; } void c_list_destroy(C_List *list) { if (list == NULL) { return; } Node *cursor = list->head; // walk through the linked list do { Node *next = cursor->next; // if we have a dtor the call it if (cursor->dtor != NULL) { cursor->dtor(cursor->value); } // clean up the node and advance free(cursor); cursor = next; } while (cursor != NULL); free(list); } C_Result c_list_push_back(C_List *list, void *value) { return c_list_push_back_dtor(list, value, NULL); } C_Result c_list_push_back_dtor(C_List *list, void *value, void (*dtor)(void *)) { assert(list != NULL); C_Result result = C_SUCCESS; // walk the list looking for rhe last node Node *cursor = list->head; while (cursor->next != NULL) { cursor = cursor->next; } // allocate a new node Node *new_node = (Node *)calloc(sizeof(Node), 1u); if (new_node == NULL) { result = C_FAILED_TO_ALLOCATE_NODE; goto end; } // store the supplied data abd wire up the node to the end new_node->value = value; new_node->dtor = dtor; cursor->next = new_node; end: return result; } void c_list_remove(C_List *list, const C_ListIter *iter) { assert(list != NULL); assert(iter != NULL); // walk the list looking for the node Node *cursor = list->head; while ((cursor->next != NULL) && (cursor->next != iter->node)) { cursor = cursor->next; } // if we didn't reach the end of the list then we found the node if (cursor->next != NULL) { Node *to_remove = cursor->next; Node *next = to_remove->next; // if we have a dtor the call it if (to_remove->dtor != NULL) { to_remove->dtor(to_remove->value); } // free the node and remove it from the list free(to_remove); cursor->next = next; } } C_Result c_list_iterator_create(const C_List *list, C_ListIter **iter) { assert(list != NULL); assert(iter != NULL); C_Result result = C_SUCCESS; // allocate the iterator C_ListIter *new_iter = (C_ListIter *)calloc(sizeof(C_ListIter), 1u); if (new_iter == NULL) { result = C_FAILED_TO_ALLOCATE_ITERATOR; goto end; } c_list_iterator_reset(list, &new_iter); // assign the iterator to the user supplied pointer *iter = new_iter; end: return result; } void c_list_iterator_destroy(C_ListIter *iter) { free(iter); } void c_list_iterator_advance(C_ListIter **iter) { assert(*iter != NULL); (*iter)->node = (*iter)->node->next; } void c_list_iterator_reset(const C_List *list, C_ListIter **iter) { assert(*iter != NULL); (*iter)->node = list->head->next; } bool c_list_iterator_at_end(C_ListIter *iter) { assert(iter != NULL); return iter->node == NULL; } void *c_list_iterator_value(const C_ListIter *iter) { assert(iter != NULL); return iter->node->value; } ================================================ FILE: Game I/c_list.h ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #pragma once #include #include "c_result.h" /** * Simple linked list data structure which can store void*. */ /** * Handle to internal list data. */ typedef struct C_List C_List; /** * Handle to internal list iterator data. */ typedef struct C_ListIter C_ListIter; /** * Create a new list. * * @param list * Out parameter for created list. * * @returns * C_SUCCESS on success * Another Result type on error */ C_Result c_list_create(C_List **list); /** * Destroy a list. * * Will call dtor function for each node (if supplied). * * @param list * List to destroy. */ void c_list_destroy(C_List *list); /** * Push a new value to the end of the list. * * @param list * List to add to. * * @param value * Value to add. * * @returns * C_SUCCESS on success * Another Result type on error */ C_Result c_list_push_back(C_List *list, void *value); /** * Push a new value to the end of the list, with a dtor function which will get called when the node is removed or the * list is destroyed. * * @param list * List to add to. * * @param value * Value to add. * * @param dtor * Function to call to cleanup value. * * @returns * C_SUCCESS on success * Another Result type on error */ C_Result c_list_push_back_dtor(C_List *list, void *value, void (*dtor)(void *)); /** * Remove the node referenced by an iterator from a list. * * @param list * List to remove node from. * * @param iter * Iterator to node to remove. */ void c_list_remove(C_List *list, const C_ListIter *iter); /** * Create a new iterator to the first node. * * Note this will be NULL if the list is empty. * * @param list * List to create iterator in. * * @param iter * Out parameter for created iterator. * * @returns * C_SUCCESS on success * Another Result type on error */ C_Result c_list_iterator_create(const C_List *list, C_ListIter **iter); /** * Destroy an iterator. * * @param iter * Iterator to destroy. */ void c_list_iterator_destroy(C_ListIter *iter); /** * Advance an iterator to the next node. * * @param iter * Out parameter for advanced iterator. */ void c_list_iterator_advance(C_ListIter **iter); /** * Reset an iterator back to the start of the list. * * @param list * List to reset iterator in. * * @param iter * Out paramater for reset iterator. */ void c_list_iterator_reset(const C_List *list, C_ListIter **iter); /** * Check if an iterator is one past the end of the list. * * @param iter * Iterator to check. * * @returns * True if iterator is one past the end of the list, otherwise false. */ bool c_list_iterator_at_end(C_ListIter *iter); /** * Get the value the iterator is referencing. * * @param iter * Iterator to get value of. * * @returns * Value at iterator. */ void *c_list_iterator_value(const C_ListIter *iter); ================================================ FILE: Game I/c_rectangle.c ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #include "c_rectangle.h" #include #include #include "c_vector2.h" C_Rectangle c_rectangle_create(const C_Vector2 *position, float width, float height) { return c_rectangle_create_xy(position->x, position->y, width, height); } C_Rectangle c_rectangle_create_xy(float x, float y, float width, float height) { C_Rectangle rect = {.position = {.x = x, .y = y}, .width = width, .height = height}; return rect; } void c_rectangle_translate(C_Rectangle *rectangle, const C_Vector2 *translation) { c_vector2_add(&rectangle->position, translation); } void c_rectangle_translate_xy(C_Rectangle *rectangle, float x, float y) { c_vector2_add_xy(&rectangle->position, x, y); } void c_rectangle_set_position(C_Rectangle *rectangle, const C_Vector2 *position) { rectangle->position = *position; } void c_rectangle_set_position_xy(C_Rectangle *rectangle, float x, float y) { rectangle->position.x = x; rectangle->position.y = y; } void c_rectangle_print(const C_Rectangle *rectangle) { printf( "{ x: %f, y: %f, w: %f, h: %f }\n", rectangle->position.x, rectangle->position.y, rectangle->width, rectangle->height); } ================================================ FILE: Game I/c_rectangle.h ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #pragma once #include "c_vector2.h" /** * A Rectangle represents an axis aligned box defined by the coordinates of its upper left corner as well as width and * height. */ /** * Struct for rectangle data. Deliberately public. */ typedef struct C_Rectangle { C_Vector2 position; float width; float height; } C_Rectangle; /** * Create a new Rectangle. * * @param position * Position of rectangle (upper left corner). * * @param width * Width of rectangle. * * @param height * Height of rectangle. * * @returns * Rectangle constructed with supplied values. */ C_Rectangle c_rectangle_create(const C_Vector2 *position, float width, float height); /** * Create a new Rectangle. * * @param x * X coordinate of position (upper left corner). * * @param y * Y coordinate of position (upper left corner). * * @param width * Width of rectangle. * * @param height * Height of rectangle. * * @returns * Rectangle constructed with supplied values. */ C_Rectangle c_rectangle_create_xy(float x, float y, float width, float height); /** * Translate the position of a rectangle. * * @param rectangle * Rectangle to translate. * * @param translation * Translation amount. */ void c_rectangle_translate(C_Rectangle *rectangle, const C_Vector2 *translation); /** * Translate the position of a rectangle. * * @param rectangle * Rectangle to translate. * * @param x * Amount to move along x axis. * * @param y * Amount to move along y axis. */ void c_rectangle_translate_xy(C_Rectangle *rectangle, float x, float y); /** * Set the position of a rectangle. * * @param rectangle * Rectangle to set position of. * * @param position * New rectangle position. */ void c_rectangle_set_position(C_Rectangle *rectangle, const C_Vector2 *position); /** * Set the position of a rectangle. * * @param rectangle * Rectangle to set position of. * * @param x * X coordinate of new position. * * @param y * Y coordinate of new position. */ void c_rectangle_set_position_xy(C_Rectangle *rectangle, float x, float y); /** * Print rectangle to stdout. * * @param rectangle * Rectangle to print. */ void c_rectangle_print(const C_Rectangle *rectangle); ================================================ FILE: Game I/c_result.h ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #pragma once /** * Enumeration of all possible return codes. */ typedef enum C_Result { C_SUCCESS, C_NO_MORE_EVENTS, C_SDL_INIT_FAILED, C_FAILED_TO_ALLOCATE_WINDOW, C_FAILED_TO_CREATE_WINDOW, C_FAILED_TO_GET_SURFACE, C_FAILED_TO_FILL_RECT, C_FAILED_TO_UPDATE_SURFACE, C_FAILED_TO_CREATE_RENDERER, C_FAILED_TO_MAP_KEY, C_FAILED_TO_CLEAR_RENDERER, C_FAILED_TO_SET_RENDER_COLOUR, C_FAILED_TO_DRAW_FILLED_RECT, C_FAILED_TO_ALLOCATE_LIST, C_FAILED_TO_ALLOCATE_NODE, C_FAILED_TO_ALLOCATE_ITERATOR, } C_Result; ================================================ FILE: Game I/c_vector2.c ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #include "c_vector2.h" #include #include C_Vector2 c_vector2_create() { return c_vector2_create_xy(0.0f, 0.0f); } C_Vector2 c_vector2_create_xy(float x, float y) { C_Vector2 vec = {.x = x, .y = y}; return vec; } void c_vector2_add(C_Vector2 *vec1, const C_Vector2 *vec2) { assert(vec1 != NULL); assert(vec2 != NULL); vec1->x += vec2->x; vec1->y += vec2->y; } void c_vector2_add_xy(C_Vector2 *vec, float x, float y) { assert(vec != NULL); vec->x += x; vec->y += y; } void c_vector2_print(const C_Vector2 *vec) { assert(vec != NULL); printf("{ x: %f, y: %f }\n", vec->x, vec->y); } ================================================ FILE: Game I/c_vector2.h ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #pragma once /** * A Vector2 represents a two component (x and y) vector. */ /** * Struct for vector data. Deliberately public. */ typedef struct C_Vector2 { float x; float y; } C_Vector2; /** * Create a new Vector2 with both components 0.0. * * @returns * Vector2 with x and y set to 0.0. */ C_Vector2 c_vector2_create(); /** * Create a new Vector2 with supplied component values. * * @param x * X component. * * @param y * Y component. * * @returns * Vector2 with x and y set to supplied values. */ C_Vector2 c_vector2_create_xy(float x, float y); /** * Add one vector to another. * * @param vec1 * The source vector, this will be modified. * * @param vec2 * The vector to add to vec1. */ void c_vector2_add(C_Vector2 *vec1, const C_Vector2 *vec2); /** * Add values to a vector. * * @param vec * The source vector, this will be modified. * * @param x * Value to add to x component. * * @param y * Value to add to y component. */ void c_vector2_add_xy(C_Vector2 *vec, float x, float y); /** * Print vector to stdout. * * @param vec * The vector to print. */ void c_vector2_print(const C_Vector2 *vec); ================================================ FILE: Game I/c_window.c ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #include "c_window.h" #include #include #include #include #include "SDL.h" #include "c_key_event.h" #include "c_result.h" typedef struct C_Window { SDL_Window *window; SDL_Renderer *renderer; } C_Window; static C_Result map_sdl_key(C_Key *key, SDL_Keycode sdl_code) { switch (sdl_code) { case SDLK_ESCAPE: *key = C_KEY_ESCAPE; return C_SUCCESS; case SDLK_LEFT: *key = C_KEY_LEFT; return C_SUCCESS; case SDLK_RIGHT: *key = C_KEY_RIGHT; return C_SUCCESS; default: return C_NO_MORE_EVENTS; } } C_Result c_window_create(C_Window **window) { C_Result res = C_SUCCESS; // perform the initial SDL initialisation if (SDL_Init(SDL_INIT_VIDEO) != 0) { res = C_SDL_INIT_FAILED; goto fail; } // allocate space for the window object C_Window *new_window = (C_Window *)calloc(1u, sizeof(C_Window)); if (new_window == NULL) { res = C_FAILED_TO_ALLOCATE_WINDOW; goto fail; } // create an SDL window new_window->window = SDL_CreateWindow("c_game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 800, SDL_WINDOW_SHOWN); if (new_window->window == NULL) { res = C_FAILED_TO_CREATE_WINDOW; goto fail; } // create an SDL renderer new_window->renderer = SDL_CreateRenderer(new_window->window, -1, 0); if (new_window->renderer == NULL) { res = C_FAILED_TO_CREATE_RENDERER; goto fail; } // assign the window to the user supplied pointer *window = new_window; return res; fail: // clean up and return error code c_window_destroy(new_window); return res; } void c_window_destroy(C_Window *window) { if (window == NULL) { return; } if (window->window != NULL) { SDL_DestroyWindow(window->window); } free(window); SDL_Quit(); } C_Result c_window_get_event(const C_Window *window, C_KeyEvent *event) { assert(window != NULL); assert(event != NULL); C_Result result = C_NO_MORE_EVENTS; // try and get an SDL event SDL_Event sdl_event; if (SDL_PollEvent(&sdl_event) != 0u) { bool try_map_key = false; if (sdl_event.type == SDL_KEYDOWN) { event->key_state = C_KEYSTATE_DOWN; try_map_key = true; } else if (sdl_event.type == SDL_KEYUP) { event->key_state = C_KEYSTATE_UP; try_map_key = true; } if (try_map_key) { // if we get here then we know we had a key event (either press or release), so convert the SDL key code // to our internal representation result = map_sdl_key(&event->key, sdl_event.key.keysym.sym); } } return result; } C_Result c_window_pre_render(const C_Window *window) { C_Result result = C_SUCCESS; // clear the window to black if (SDL_SetRenderDrawColor(window->renderer, 0x0, 0x0, 0x0, 0x0) != 0) { result = C_FAILED_TO_SET_RENDER_COLOUR; goto end; } if (SDL_RenderClear(window->renderer) != 0) { result = C_FAILED_TO_CLEAR_RENDERER; goto end; } end: return result; } void c_window_post_render(const C_Window *window) { return SDL_RenderPresent(window->renderer); } C_Result c_window_draw_rectangle(const C_Window *window, const C_Rectangle *rectangle, uint8_t r, uint8_t g, uint8_t b) { C_Result result = C_SUCCESS; // convert our internal rect to an SDL rect SDL_Rect sdl_rect = { .x = rectangle->position.x, .y = rectangle->position.y, .w = rectangle->width, .h = rectangle->height}; // set the draw colour if (SDL_SetRenderDrawColor(window->renderer, r, g, b, 0xff) != 0) { result = C_FAILED_TO_SET_RENDER_COLOUR; goto end; } // draw! if (SDL_RenderFillRect(window->renderer, &sdl_rect) != 0) { result = C_FAILED_TO_DRAW_FILLED_RECT; goto end; } end: return result; } ================================================ FILE: Game I/c_window.h ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #pragma once #include #include "c_key_event.h" #include "c_rectangle.h" #include "c_result.h" /** * Window is responsible fro creating and destroying a platform window as well as rendering to it and getting event. */ /** * Handle to internal window data. */ typedef struct C_Window C_Window; /** * Create a new platform window. * * Note this library only supports creating one window, any calls to this function after the first successful call are * undefined. * * @param window * Out paramater for created window object. * * @returns * C_SUCCESS on success * Another Result type on error */ C_Result c_window_create(C_Window **window); /** * Destroy a window. * * @param window * The window to destroy. */ void c_window_destroy(C_Window *window); /** * Get an event if one is available. * * @param window * Window to get events for. * * @param event * Out paramater to write event data to. * * @returns * C_SUCCESS on success * C_NO_MORE_EVENTS if there was no event to get * Another Result type on error */ C_Result c_window_get_event(const C_Window *window, C_KeyEvent *event); /** * Perform an pre-render tasks. * * @param window * Window to render to. * * @returns * C_SUCCESS on success * Another Result type on error */ C_Result c_window_pre_render(const C_Window *window); /** * Perform an post-render tasks. * * @param window * Window to render to. */ void c_window_post_render(const C_Window *window); /** * Draw a rectangle to the screen. * * This *must* be called after c_window_pre_render and before c_window_post_render for any given frame. * * @param window * The window to render to. * * @param rectangle * The rectangle to draw. * * @param r * The red component of the rectangle colour. * * @param g * The green component of the rectangle colour. * * @param b * The blue component of the rectangle colour. * * @returns * C_SUCCESS on success * Another Result type on error */ C_Result c_window_draw_rectangle(const C_Window *window, const C_Rectangle *rectangle, uint8_t r, uint8_t g, uint8_t b); ================================================ FILE: Game I/main.c ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include "c_key_event.h" #include "c_list.h" #include "c_rectangle.h" #include "c_window.h" /** * Struct encapsulating the data for a renderable entity. */ typedef struct Entity { C_Rectangle rectangle; uint8_t r; uint8_t g; uint8_t b; } Entity; /** * Helper macro for checking if a value is C_SUCCESS. If not it prints a supplied messaged and exits. */ #define CHECK_SUCCESS(X, MSG) \ do \ { \ C_Result r = X; \ if (r != C_SUCCESS) \ { \ printf("%s [error: %i]\n", MSG, r); \ exit(1); \ } \ } while (false) /** * Helper function to create a row of ten bricks. * * @param entities * List to store entities in. * * @param y * Y coordinate of row. * * @param r * Red component of brick colour. * * @param g * Green component of brick colour. * * @param b * Blue component of brick colour. */ static void create_brick_row(C_List *entities, float y, uint8_t r, uint8_t g, uint8_t b) { float x = 20.0f; for (int i = 0; i < 10; ++i) { Entity *e = (Entity *)calloc(sizeof(Entity), 1u); e->rectangle.position.x = x; e->rectangle.position.y = y; e->rectangle.width = 58.0f; e->rectangle.height = 20.0f; e->r = r; e->g = g; e->b = b; CHECK_SUCCESS(c_list_push_back_dtor(entities, e, &free), "failed to add brick"); x += 78.0f; } } /** * Helper function to update the ball. * * @param ball * Entity for ball. * * @param ball_velocity * Velocity of ball. */ static void update_ball(Entity *ball, C_Vector2 *ball_velocity) { c_vector2_add(&ball->rectangle.position, ball_velocity); // if ball does out of the screen then invert the y velocity if ((ball->rectangle.position.y < 0.0f) || (ball->rectangle.position.y > 800.0f)) { ball_velocity->y *= -1.0f; } if ((ball->rectangle.position.x < 0.0f) || (ball->rectangle.position.x > 800.0f)) { ball_velocity->x *= -1.0f; } } /** * Helper function to check if two entities are colliding. * * @param entity1 * First entity to check. * * @param entity2 * Second entity to check. * * @returns * True if entities collide, false otherwise. */ bool static check_collision(const Entity *entity1, const Entity *entity2) { return ( (entity1->rectangle.position.x < entity2->rectangle.position.x + entity2->rectangle.width) && (entity1->rectangle.position.x + entity1->rectangle.width > entity2->rectangle.position.x) && (entity1->rectangle.position.y < entity2->rectangle.position.y + entity2->rectangle.height) && (entity1->rectangle.height + entity1->rectangle.position.y > entity2->rectangle.position.y)); } /** * Helper function to handle collisions between the ball and other entities. * * @param entities * List of all entities. * * @param ball * Ball entity. * * @param ball_velocity * The velocity of the ball. * * @param paddle * Paddle entity. */ static void handle_collisions(C_List *entities, Entity *ball, C_Vector2 *ball_velocity, const Entity *paddle) { // keep iterator scoped so we can't use it after it's been destroyed { C_ListIter *iter; CHECK_SUCCESS(c_list_iterator_create(entities, &iter), "could not create iterator"); // move past ball and paddle c_list_iterator_advance(&iter); c_list_iterator_advance(&iter); // see if the ball intersects with any bricks while (!c_list_iterator_at_end(iter)) { Entity *block = (Entity *)c_list_iterator_value(iter); if (check_collision(ball, block)) { c_list_remove(entities, iter); ball_velocity->y *= -1.0f; // if we modify the list this will invalidate the iterator, so stop break; } c_list_iterator_advance(&iter); } c_list_iterator_destroy(iter); } // handle ball - paddle collision if (check_collision(ball, paddle)) { if (ball->rectangle.position.x < paddle->rectangle.position.x + 6.0f) { ball_velocity->x = -0.7f; ball_velocity->y = -0.7f; } else if (ball->rectangle.position.x < paddle->rectangle.position.x + 14.0f) { ball_velocity->x = 0.0f; ball_velocity->y = -1.0f; } else { ball_velocity->x = 0.7f; ball_velocity->y = -0.7f; } } } int main() { printf("hello world\n"); Entity paddle = { .rectangle = c_rectangle_create_xy(300.0f, 780.0f, 300.0f, 20.0f), .r = 0xff, .g = 0xff, .b = 0xff}; Entity ball = {.rectangle = c_rectangle_create_xy(420.0f, 400.0f, 10.0f, 10.0f), .r = 0xff, .g = 0xff, .b = 0xff}; C_Vector2 paddle_velocity = c_vector2_create(); C_Vector2 ball_velocity = c_vector2_create_xy(0.0f, 0.5f); C_List *entities = NULL; CHECK_SUCCESS(c_list_create(&entities), "failed to create entity list"); CHECK_SUCCESS(c_list_push_back(entities, &paddle), "failed to add paddle to list"); CHECK_SUCCESS(c_list_push_back(entities, &ball), "failed to add ball to list"); create_brick_row(entities, 50.0f, 0xff, 0x00, 0x00); create_brick_row(entities, 80.0f, 0xff, 0x00, 0x00); create_brick_row(entities, 110.0f, 0xff, 0xa5, 0x00); create_brick_row(entities, 140.0f, 0xff, 0xa5, 0x00); create_brick_row(entities, 170.0f, 0x00, 0xff, 0x00); create_brick_row(entities, 200.0f, 0x00, 0xff, 0x00); C_ListIter *iter = NULL; CHECK_SUCCESS(c_list_iterator_create(entities, &iter), "failed to get entity iterator"); // create window C_Window *window; CHECK_SUCCESS(c_window_create(&window), "failed to create window"); C_KeyEvent event; bool running = true; const float paddle_speed = 1.0f; bool left_press = false; bool right_press = false; while (running) { // process all events for (;;) { C_Result event_result = c_window_get_event(window, &event); if (event_result == C_SUCCESS) { if ((event.key_state == C_KEYSTATE_DOWN) && (event.key == C_KEY_ESCAPE)) { running = false; } else if (event.key == C_KEY_LEFT) { left_press = (event.key_state == C_KEYSTATE_DOWN) ? true : false; } else if (event.key == C_KEY_RIGHT) { right_press = (event.key_state == C_KEYSTATE_DOWN) ? true : false; } } else if (event_result == C_NO_MORE_EVENTS) { break; } else { printf("error getting event\n"); exit(1); } } if ((left_press && right_press) || (!left_press && !right_press)) { paddle_velocity.x = 0.0f; } else if (left_press) { paddle_velocity.x = -paddle_speed; } else if (right_press) { paddle_velocity.x = paddle_speed; } c_vector2_add(&paddle.rectangle.position, &paddle_velocity); update_ball(&ball, &ball_velocity); handle_collisions(entities, &ball, &ball_velocity, &paddle); // reset iterator as we may have modified the list and we will want to start from the beginning anyway c_list_iterator_reset(entities, &iter); // render our scene CHECK_SUCCESS(c_window_pre_render(window), "pre render failed"); while (!c_list_iterator_at_end(iter)) { Entity *entity = (Entity *)c_list_iterator_value(iter); CHECK_SUCCESS( c_window_draw_rectangle(window, &entity->rectangle, entity->r, entity->g, entity->b), "failed to render entity"); c_list_iterator_advance(&iter); } c_window_post_render(window); } c_list_iterator_destroy(iter); c_window_destroy(window); printf("goodbye\n"); return 0; } ================================================ FILE: Game II/CMakeLists.txt ================================================ add_executable(cpp_game colour.cpp entity.cpp main.cpp rectangle.cpp vector2.cpp window.cpp ) target_link_directories(cpp_game PRIVATE ${sdl_BINARY_DIR}) target_include_directories(cpp_game PRIVATE ${sdl_SOURCE_DIR}/include) target_compile_features(cpp_game PRIVATE cxx_std_20) target_link_libraries(cpp_game SDL2::SDL2-static) ================================================ FILE: Game II/colour.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #include "colour.h" #include #include namespace cpp { Colour::Colour() : Colour(0xffffff) { } Colour::Colour(std::uint8_t r, std::uint8_t g, std::uint8_t b) : r(r) , g(g) , b(b) { } Colour::Colour(std::uint32_t colour) : Colour((colour >> 16) & 0xff, (colour >> 7) & 0xff, colour & 0xff) { } bool operator==(const Colour &c1, const Colour &c2) { return (c1.r == c2.r) && (c1.g == c2.g) && (c1.b == c2.b); } bool operator!=(const Colour &c1, const Colour &c2) { return !(c1 == c2); } std::ostream &operator<<(std::ostream &os, const Colour &c) { os << "{ r: " << c.r << ", g: " << c.g << ", b: " << c.b << " }"; return os; } } ================================================ FILE: Game II/colour.h ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #pragma once #include #include namespace cpp { /** * A Colour represents an RGB component (where each component is 8 bits). */ class Colour { public: /** * Construct a new white colour. */ Colour(); /** * Construct a new colour from r, g and b components. * * @param r * Red component. * * @param g * Green component. * * @param b * Blue component. */ Colour(std::uint8_t r, std::uint8_t g, std::uint8_t b); /** * Construct a new colour from a hex colour number. The expected format of the number is 0xRRGGBB. * * @param colour * Colour value (0xRRGGBB). */ Colour(std::uint32_t colour); /** * Stream operator. * * @param os * Stream to write to. * * @param c * Colour to write to stream. * * @returns * Reference to supplied stream. */ friend std::ostream &operator<<(std::ostream &os, const Colour &c); /** Red component. */ std::uint8_t r; /** Green component. */ std::uint8_t g; /** Blue component. */ std::uint8_t b; }; /** * Check if two colours are equal. * * @param c1 * First colour to check. * * @param c2 * Second colour to check. * * @returns * True if both colours are equal, otherwise false. */ bool operator==(const Colour &c1, const Colour &c2); /** * Check if two colours are not equal. * * @param c1 * First colour to check. * * @param c2 * Second colour to check. * * @returns * True if both colours are not equal, otherwise false. */ bool operator!=(const Colour &c1, const Colour &c2); // see docs on class definition std::ostream &operator<<(std::ostream &os, const Colour &c); } ================================================ FILE: Game II/entity.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #include "entity.h" #include #include "colour.h" #include "rectangle.h" #include "vector2.h" namespace cpp { Entity::Entity(const Rectangle &rectangle, const Colour &colour) : rectangle_(rectangle) , colour_(colour) { } Rectangle Entity::rectangle() const { return rectangle_; } Colour Entity::colour() const { return colour_; } void Entity::translate(const Vector2 &translation) { rectangle_.translate(translation); } bool Entity::intersects(const Entity &e) const { return rectangle_.intersects(e.rectangle_); } bool operator==(const Entity &e1, const Entity &e2) { return (e1.colour() == e2.colour()) && (e1.rectangle() == e2.rectangle()); } bool operator!=(const Entity &e1, const Entity &e2) { return !(e1 == e2); } std::ostream &operator<<(std::ostream &os, const Entity &e) { os << "{ " << e.colour() << ", " << e.rectangle() << " }"; return os; } } ================================================ FILE: Game II/entity.h ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #pragma once #include "colour.h" #include "rectangle.h" #include "vector2.h" namespace cpp { /** * An Entity represents a renderable rectangle. */ class Entity { public: /** * Construct a new entity. * * @param rectangle * Rectangle representing the area to draw. * * @param colour * The colour to render the entity. */ Entity(const Rectangle &rectangle, const Colour &colour); /** * Get the entities rectangle. * * @returns * Entity rectangle. */ Rectangle rectangle() const; /** * Get the entities colour. * * @returns * Entity colour. */ Colour colour() const; /** * Translate the entity. * * @param translation * Translation amount. */ void translate(const Vector2 &translation); /** * Check if another entity intersects this. * * @param e * Entity to check for intersection. * * @returns * True if supplied entity intersects this, otherwise false. */ bool intersects(const Entity &e) const; /** * Stream operator. * * @param os * Stream to write to. * * @param e * Entity to write to stream. * * @returns * Reference to supplied stream. */ friend std::ostream &operator<<(std::ostream &os, const Entity &e); private: /** Drawable area. */ Rectangle rectangle_; /** Draw colour. */ Colour colour_; }; /** * Check if two entities are equal. * * @param e1 * First entity to check. * * @param e2 * Second entity to check. * * @returns * True if both entities are equal, otherwise false. */ bool operator==(const Entity &e1, const Entity &e2); /** * Check if two entities are equal. * * @param e1 * First entity to check. * * @param e2 * Second entity to check. * * @returns * True if both entities are equal, otherwise false. */ bool operator!=(const Entity &e1, const Entity &e2); // see docs on class definition std::ostream &operator<<(std::ostream &os, const Entity &e); } ================================================ FILE: Game II/key_event.h ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #pragma once namespace cpp { /** * Enumeration of possible key states. */ enum class KeyState { DOWN, UP }; /** * Enumeration of possible input keys (maybe incomplete). */ enum class Key { ESCAPE, LEFT, RIGHT, }; /** * Struct encapsulating the data for a key press event. */ struct KeyEvent { KeyState key_state; Key key; }; } ================================================ FILE: Game II/main.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #include #include #include "colour.h" #include "entity.h" #include "key_event.h" #include "rectangle.h" #include "vector2.h" #include "window.h" namespace { /** * Helper function to create a row of 10 bricks. * * @param entities * Collection to add new entities to. * * @param y * Y coordinate of row. * * @param colour * Colour of bricks. */ void create_brick_row(std::vector &entities, float y, const cpp::Colour &colour) { auto x = 20.0f; for (auto i = 0u; i < 10u; ++i) { entities.push_back({{{x, y}, 58.0f, 20.0f}, colour}); x += 78.0f; } } /** * Helper function to check for and resolve collisions between the ball and other entities. * * @param ball * Ball to check for collisions. * * @param ball_velocity * Velocity of ball, might get mutated during collision response. * * @param paddle * Paddle to check for collisions with. * * @param entities * Collection of all entities, brick entities will be removed if a collision is detected. */ void check_collisions( const cpp::Entity &ball, cpp::Vector2 &ball_velocity, const cpp::Entity &paddle, std::vector &entities) { // check and handle ball and paddle collision if (paddle.intersects(ball)) { const auto ball_pos = ball.rectangle().position; const auto paddle_pos = paddle.rectangle().position; if (ball_pos.x < paddle_pos.x + 100.0f) { ball_velocity.x = -0.7f; ball_velocity.y = -0.7f; } else if (ball_pos.x < paddle_pos.x + 200.0f) { ball_velocity.x = 0.0f; ball_velocity.y = -1.0f; } else { ball_velocity.x = 0.7f; ball_velocity.y = -0.7f; } } else { // only check brick intersections if we didn't intersect the paddle, unlikely these will both happen in the same // frame due to the layout of the game // iterate over all entities, skipping the first two as these are the paddle and ball auto bricks_view = entities | std::views::drop(2u); auto hit_brick = std::ranges::find_if(bricks_view, [&ball](const auto &brick) { return ball.intersects(brick); }); if (hit_brick != std::ranges::end(bricks_view)) { // we hit a brick so update ball velocity and remove brick entity ball_velocity.y *= -1.0f; entities.erase(hit_brick); } } } /** * Helper function to update the ball. Will check if the ball leaves the window and adjust the velocity so it "bounces" * off walls. * * @param ball * Ball entity to update. * * @param velocity * Ball velocity, will be mutated if ball goes off screen. */ void update_ball(cpp::Entity &ball, cpp::Vector2 &velocity) { ball.translate(velocity); const auto ball_pos = ball.rectangle().position; if ((ball_pos.y > 800.0f) || (ball_pos.y < 0.0f)) { velocity.y *= -1.0f; } if ((ball_pos.x > 800.0f) || (ball_pos.x < 0.0f)) { velocity.x *= -1.0f; } } /** * Helper function to update the paddle. * * @param paddle * Paddle entity to update. * * @param velocity * Paddle velocity. */ void update_paddle(cpp::Entity &paddle, const cpp::Vector2 &velocity) { paddle.translate(velocity); } } int main() { std::cout << "hello world\n"; const cpp::Window window{}; auto running = true; std::vector entities{ {{{300.0f, 780.0f}, 300.0f, 20.0f}, 0xFFFFFF}, {{{420.0f, 400.0f}, 10.0f, 10.0f}, 0xFFFFFF}}; create_brick_row(entities, 50.0f, 0xff0000); create_brick_row(entities, 80.0f, 0xff0000); create_brick_row(entities, 110.0f, 0xffa500); create_brick_row(entities, 140.0f, 0xffa500); create_brick_row(entities, 170.0f, 0x00ff00); create_brick_row(entities, 200.0f, 0x00ff00); cpp::Vector2 ball_velocity{0.0f, 1.0f}; cpp::Vector2 paddle_velocity{0.0f, 0.0f}; const float paddle_speed = 1.0f; auto left_press = false; auto right_press = false; while (running) { for (;;) { if (const auto event = window.get_event(); event) { using enum cpp::Key; using enum cpp::KeyState; if ((event->key_state == DOWN) && (event->key == ESCAPE)) { running = false; } else if (event->key == LEFT) { left_press = (event->key_state == DOWN) ? true : false; } else if (event->key == RIGHT) { right_press = (event->key_state == DOWN) ? true : false; } } else { break; } } if ((left_press && right_press) || (!left_press && !right_press)) { paddle_velocity.x = 0.0f; } else if (left_press) { paddle_velocity.x = -paddle_speed; } else if (right_press) { paddle_velocity.x = paddle_speed; } // scope the references to the paddle and ball, if check_collisions results in an entity being removed then // that will invalidate our references, so prevent them from being accidentally used later { auto &paddle = entities[0]; auto &ball = entities[1]; update_paddle(paddle, paddle_velocity); update_ball(ball, ball_velocity); check_collisions(ball, ball_velocity, paddle, entities); } window.render(entities); } std::cout << "goodbye\n"; return 0; } ================================================ FILE: Game II/rectangle.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #include "rectangle.h" #include #include "vector2.h" namespace cpp { Rectangle::Rectangle(const Vector2 &position, float width, float height) : position(position) , width(width) , height(height) { } void Rectangle::translate(const Vector2 &translation) { position += translation; } bool Rectangle::intersects(const Rectangle &rect) const { return ( (position.x < rect.position.x + rect.width) && (position.x + width > rect.position.x) && (position.y < rect.position.y + rect.height) && (height + position.y > rect.position.y)); } bool operator==(const Rectangle &r1, const Rectangle &r2) { return (r1.position == r2.position) && (r1.width == r2.width) && (r1.height == r2.height); } bool operator!=(const Rectangle &r1, const Rectangle &r2) { return !(r1 == r2); } std::ostream &operator<<(std::ostream &os, const Rectangle &rect) { os << "{ position: " << rect.position << ", w: " << rect.width << ", h: " << rect.height << " }"; return os; } } ================================================ FILE: Game II/rectangle.h ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #pragma once #include #include "vector2.h" namespace cpp { /** * A Rectangle represents an axis aligned box defined by the coordinates of its upper left corner as well as width and * height. */ class Rectangle { public: /** * Construct a new Rectangle. * * @param position * Position of rectangle (upper left corner). * * @param width * Width of rectangle. * * @param height * Height of rectangle. */ Rectangle(const Vector2 &position, float width, float height); /** * Stream operator. * * @param os * Stream to write to. * * @param rect * Rectangle to write to stream. * * @returns * Reference to supplied stream. */ friend std::ostream &operator<<(std::ostream &os, const Rectangle &rect); /** * Translate the position of a rectangle. * * @param translation * Translation amount. */ void translate(const Vector2 &translation); /** * Check if another rectangle intersects this. * * @param rect * Rectangle to check for intersection. * * @returns * True if supplied rectangle intersects this, otherwise false. */ bool intersects(const Rectangle &rect) const; /** Position of upper left corner of rectangle. */ Vector2 position; /** Rectangle width. */ float width; /** Rectangle height. */ float height; }; /** * Check if two rectangles are equal. * * @param r1 * First rectangle to check. * * @param r2 * Second rectangle to check. * * @returns * True if both rectangles are equal, otherwise false. */ bool operator==(const Rectangle &r1, const Rectangle &r2); /** * Check if two rectangles are not equal. * * @param r1 * First rectangle to check. * * @param r2 * Second rectangle to check. * * @returns * True if both rectangles are not equal, otherwise false. */ bool operator!=(const Rectangle &r1, const Rectangle &r2); // see docs on class definition std::ostream &operator<<(std::ostream &os, const Rectangle &rect); } ================================================ FILE: Game II/vector2.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #include "vector2.h" #include namespace cpp { Vector2::Vector2() : Vector2(0.0f, 0.0f) { } Vector2::Vector2(float x, float y) : x(x) , y(y) { } bool operator==(const Vector2 &v1, const Vector2 &v2) { return (v1.x == v2.x) && (v1.y == v2.y); } bool operator!=(const Vector2 &v1, const Vector2 &v2) { return !(v1 == v2); } Vector2 operator+(const Vector2 &v1, const Vector2 &v2) { Vector2 new_vec{v1}; new_vec += v2; return new_vec; } Vector2 &operator+=(Vector2 &v1, const Vector2 &v2) { v1.x += v2.x; v1.y += v2.y; return v1; } std::ostream &operator<<(std::ostream &os, const Vector2 &v) { os << "{ x: " << v.x << ", y: " << v.y << "}"; return os; } } ================================================ FILE: Game II/vector2.h ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #pragma once #include namespace cpp { /** * A Vector2 represents a two component (x and y) vector. */ class Vector2 { public: /** * Construct a new Vector2, with both components 0.0. */ Vector2(); /** * Construct a new Vector2, with supplied component values. * * @param x * X component. * * @param y * Y component. */ Vector2(float x, float y); /** * Stream operator. * * @param os * Stream to write to. * * @param v * Vector to write to stream. * * @returns * Reference to supplied stream. */ friend std::ostream &operator<<(std::ostream &os, const Vector2 &v); /** X component. */ float x; /** Y component. */ float y; }; /** * Check if two vectors are equal. * * @param v1 * First vector to check. * * @param v2 * Second vector to check. * * @returns * True if both vectors are equal, otherwise false. */ bool operator==(const Vector2 &v1, const Vector2 &v2); /** * Check if two vectors are not equal. * * @param v1 * First vector to check. * * @param v2 * Second vector to check. * * @returns * True if both vectors are not equal, otherwise false. */ bool operator!=(const Vector2 &v1, const Vector2 &v2); /** * Construct a new vector by adding two supplied vectors. * * @param v1 * First vector to add. * * @param v2 * Second vector to add. * * @returns * v1 + v2. */ Vector2 operator+(const Vector2 &v1, const Vector2 &v2); /** * Add assign one vector to another. * * @param v1 * Vector to add to, will be mutated. * * @param v2 * Second vector to add. * * @returns * v1 += v2. */ Vector2 &operator+=(Vector2 &v1, const Vector2 &v2); // see docs on class definition std::ostream &operator<<(std::ostream &os, const Vector2 &v); } ================================================ FILE: Game II/window.cpp ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #include "window.h" #include #include #include #include #include "SDL.h" #include "entity.h" #include "key_event.h" namespace { /** * Helper function to map an SDL key code to an internal type. * * @param sql_code * SDL key code. * * @returns * Internal representation of the supplied key code, or empty optional if no mapping exists. */ std::optional map_sdl_key(SDL_Keycode sdl_code) { switch (sdl_code) { using enum cpp::Key; case SDLK_ESCAPE: return ESCAPE; case SDLK_LEFT: return LEFT; case SDLK_RIGHT: return RIGHT; default: return std::nullopt; } } } namespace cpp { Window::Window() : window_(nullptr, &SDL_DestroyWindow) , renderer_(nullptr, &SDL_DestroyRenderer) { if (::SDL_Init(SDL_INIT_VIDEO) != 0) { throw std::runtime_error("failed to init SDL"); } window_.reset( ::SDL_CreateWindow("cpp_game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 800, SDL_WINDOW_SHOWN)); if (!window_) { throw std::runtime_error("failed to create window"); } renderer_.reset(::SDL_CreateRenderer(window_.get(), -1, 0u)); if (!renderer_) { throw std::runtime_error("failed to create renderer"); } } std::optional Window::get_event() const { std::optional event{}; SDL_Event sdl_event = {0}; if (::SDL_PollEvent(&sdl_event) != 0u) { std::optional key_state; if (sdl_event.type == SDL_KEYDOWN) { key_state = KeyState::DOWN; } else if (sdl_event.type == SDL_KEYUP) { key_state = KeyState::UP; } // if we got a key state then it's safe to inspect the key code if (key_state) { if (const auto key = map_sdl_key(sdl_event.key.keysym.sym); key) { // got state and key - so create the KeyEvent event = KeyEvent{.key_state = *key_state, .key = *key}; } } } return event; } void Window::render(const std::vector &entities) const { if (::SDL_SetRenderDrawColor(renderer_.get(), 0x0, 0x0, 0x0, 0xff) != 0) { throw std::runtime_error("failed to set render draw colour"); } if (::SDL_RenderClear(renderer_.get()) != 0) { throw std::runtime_error("failed to clear renderer"); } for (const auto &entity : entities) { const auto entity_rect = entity.rectangle(); const auto entity_colour = entity.colour(); const SDL_Rect sdl_rect = { .x = static_cast(entity_rect.position.x), .y = static_cast(entity_rect.position.y), .w = static_cast(entity_rect.width), .h = static_cast(entity_rect.height), }; if (::SDL_SetRenderDrawColor(renderer_.get(), entity_colour.r, entity_colour.g, entity_colour.b, 0xff) != 0) { throw std::runtime_error("failed to draw entity"); } if (::SDL_RenderFillRect(renderer_.get(), &sdl_rect) != 0) { throw std::runtime_error("failed to draw filled rect"); } } ::SDL_RenderPresent(renderer_.get()); } } ================================================ FILE: Game II/window.h ================================================ //////////////////////////////////////////////////////////////////////////////// // Distributed under the Boost Software License, Version 1.0. // // (See accompanying file LICENSE or copy at // // https://www.boost.org/LICENSE_1_0.txt) // //////////////////////////////////////////////////////////////////////////////// #pragma once #include #include #include #include "entity.h" #include "key_event.h" struct SDL_Window; struct SDL_Renderer; using SDLWindowDelete = void (*)(SDL_Window *); using SDLRendererDelete = void (*)(SDL_Renderer *); namespace cpp { /** * Window is responsible for creating and destroying a platform window as well as rendering to it and getting events. */ class Window { public: /** * Construct a new Window. */ Window(); Window(const Window &) = delete; Window &operator=(const Window &) = delete; Window(Window &&) = default; Window &operator=(Window &&) = default; /** * Get an event if one is available. * * @returns * A KeyEvent if an event was available, otherwise an empty optional. */ std::optional get_event() const; /** * Render a collection of entities. * * @param entities * Entities to render. */ void render(const std::vector &entities) const; private: /** SDL window object. */ std::unique_ptr window_; /** SDL renderer object. */ std::unique_ptr renderer_; }; } ================================================ FILE: GeTargs.c ================================================ /* New getargs implementation */ #include "Python.h" #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "pycore_pylifecycle.h" // _PyArg_Fini #include #include #ifdef __cplusplus extern "C" { #endif /* Export Stable ABIs (abi only) */ PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, const char *, ...); PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, const char *, ...); PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywords_SizeT(PyObject *, PyObject *, const char *, char **, ...); PyAPI_FUNC(int) _PyArg_VaParse_SizeT(PyObject *, const char *, va_list); PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *, PyObject *, const char *, char **, va_list); #define FLAG_COMPAT 1 typedef int (*destr_t)(PyObject *, void *); /* Keep track of "objects" that have been allocated or initialized and which will need to be deallocated or cleaned up somehow if overall parsing fails. */ typedef struct { void *item; destr_t destructor; } freelistentry_t; typedef struct { freelistentry_t *entries; int first_available; int entries_malloced; } freelist_t; #define STATIC_FREELIST_ENTRIES 8 /* Forward */ static int vgetargs1_impl(PyObject *args, PyObject *const *stack, Py_ssize_t nargs, const char *format, va_list *p_va, int flags); static int vgetargs1(PyObject *, const char *, va_list *, int); static void seterror(Py_ssize_t, const char *, int *, const char *, const char *); static const char *convertitem(PyObject *, const char **, va_list *, int, int *, char *, size_t, freelist_t *); static const char *converttuple(PyObject *, const char **, va_list *, int, int *, char *, size_t, int, freelist_t *); static const char *convertsimple(PyObject *, const char **, va_list *, int, char *, size_t, freelist_t *); static Py_ssize_t convertbuffer(PyObject *, const void **p, const char **); static int getbuffer(PyObject *, Py_buffer *, const char**); static int vgetargskeywords(PyObject *, PyObject *, const char *, char **, va_list *, int); static int vgetargskeywordsfast(PyObject *, PyObject *, struct _PyArg_Parser *, va_list *, int); static int vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, PyObject *keywords, PyObject *kwnames, struct _PyArg_Parser *parser, va_list *p_va, int flags); static const char *skipitem(const char **, va_list *, int); int PyArg_Parse(PyObject *args, const char *format, ...) { int retval; va_list va; va_start(va, format); retval = vgetargs1(args, format, &va, FLAG_COMPAT); va_end(va); return retval; } PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *args, const char *format, ...) { int retval; va_list va; va_start(va, format); retval = vgetargs1(args, format, &va, FLAG_COMPAT); va_end(va); return retval; } int PyArg_ParseTuple(PyObject *args, const char *format, ...) { int retval; va_list va; va_start(va, format); retval = vgetargs1(args, format, &va, 0); va_end(va); return retval; } int _PyArg_ParseTuple_SizeT(PyObject *args, const char *format, ...) { int retval; va_list va; va_start(va, format); retval = vgetargs1(args, format, &va, 0); va_end(va); return retval; } int _PyArg_ParseStack(PyObject *const *args, Py_ssize_t nargs, const char *format, ...) { int retval; va_list va; va_start(va, format); retval = vgetargs1_impl(NULL, args, nargs, format, &va, 0); va_end(va); return retval; } int PyArg_VaParse(PyObject *args, const char *format, va_list va) { va_list lva; int retval; va_copy(lva, va); retval = vgetargs1(args, format, &lva, 0); va_end(lva); return retval; } int _PyArg_VaParse_SizeT(PyObject *args, const char *format, va_list va) { va_list lva; int retval; va_copy(lva, va); retval = vgetargs1(args, format, &lva, 0); va_end(lva); return retval; } /* Handle cleanup of allocated memory in case of exception */ static int cleanup_ptr(PyObject *self, void *ptr) { void **pptr = (void **)ptr; PyMem_Free(*pptr); *pptr = NULL; return 0; } static int cleanup_buffer(PyObject *self, void *ptr) { Py_buffer *buf = (Py_buffer *)ptr; if (buf) { PyBuffer_Release(buf); } return 0; } static int addcleanup(void *ptr, freelist_t *freelist, destr_t destructor) { int index; index = freelist->first_available; freelist->first_available += 1; freelist->entries[index].item = ptr; freelist->entries[index].destructor = destructor; return 0; } static int cleanreturn(int retval, freelist_t *freelist) { int index; if (retval == 0) { /* A failure occurred, therefore execute all of the cleanup functions. */ for (index = 0; index < freelist->first_available; ++index) { freelist->entries[index].destructor(NULL, freelist->entries[index].item); } } if (freelist->entries_malloced) PyMem_Free(freelist->entries); return retval; } static int vgetargs1_impl(PyObject *compat_args, PyObject *const *stack, Py_ssize_t nargs, const char *format, va_list *p_va, int flags) { char msgbuf[256]; int levels[32]; const char *fname = NULL; const char *message = NULL; int min = -1; int max = 0; int level = 0; int endfmt = 0; const char *formatsave = format; Py_ssize_t i; const char *msg; int compat = flags & FLAG_COMPAT; freelistentry_t static_entries[STATIC_FREELIST_ENTRIES]; freelist_t freelist; assert(nargs == 0 || stack != NULL); freelist.entries = static_entries; freelist.first_available = 0; freelist.entries_malloced = 0; flags = flags & ~FLAG_COMPAT; while (endfmt == 0) { int c = *format++; switch (c) { case '(': if (level == 0) max++; level++; if (level >= 30) Py_FatalError("too many tuple nesting levels " "in argument format string"); break; case ')': if (level == 0) Py_FatalError("excess ')' in getargs format"); else level--; break; case '\0': endfmt = 1; break; case ':': fname = format; endfmt = 1; break; case ';': message = format; endfmt = 1; break; case '|': if (level == 0) min = max; break; default: if (level == 0) { if (Py_ISALPHA(c)) if (c != 'e') /* skip encoded */ max++; } break; } } if (level != 0) Py_FatalError(/* '(' */ "missing ')' in getargs format"); if (min < 0) min = max; format = formatsave; if (max > STATIC_FREELIST_ENTRIES) { freelist.entries = PyMem_NEW(freelistentry_t, max); if (freelist.entries == NULL) { PyErr_NoMemory(); return 0; } freelist.entries_malloced = 1; } if (compat) { if (max == 0) { if (compat_args == NULL) return 1; PyErr_Format(PyExc_TypeError, "%.200s%s takes no arguments", fname==NULL ? "function" : fname, fname==NULL ? "" : "()"); return cleanreturn(0, &freelist); } else if (min == 1 && max == 1) { if (compat_args == NULL) { PyErr_Format(PyExc_TypeError, "%.200s%s takes at least one argument", fname==NULL ? "function" : fname, fname==NULL ? "" : "()"); return cleanreturn(0, &freelist); } msg = convertitem(compat_args, &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg == NULL) return cleanreturn(1, &freelist); seterror(levels[0], msg, levels+1, fname, message); return cleanreturn(0, &freelist); } else { PyErr_SetString(PyExc_SystemError, "old style getargs format uses new features"); return cleanreturn(0, &freelist); } } if (nargs < min || max < nargs) { if (message == NULL) PyErr_Format(PyExc_TypeError, "%.150s%s takes %s %d argument%s (%zd given)", fname==NULL ? "function" : fname, fname==NULL ? "" : "()", min==max ? "exactly" : nargs < min ? "at least" : "at most", nargs < min ? min : max, (nargs < min ? min : max) == 1 ? "" : "s", nargs); else PyErr_SetString(PyExc_TypeError, message); return cleanreturn(0, &freelist); } for (i = 0; i < nargs; i++) { if (*format == '|') format++; msg = convertitem(stack[i], &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { seterror(i+1, msg, levels, fname, message); return cleanreturn(0, &freelist); } } if (*format != '\0' && !Py_ISALPHA(*format) && *format != '(' && *format != '|' && *format != ':' && *format != ';') { PyErr_Format(PyExc_SystemError, "bad format string: %.200s", formatsave); return cleanreturn(0, &freelist); } return cleanreturn(1, &freelist); } static int vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) { PyObject **stack; Py_ssize_t nargs; if (!(flags & FLAG_COMPAT)) { assert(args != NULL); if (!PyTuple_Check(args)) { PyErr_SetString(PyExc_SystemError, "new style getargs format but argument is not a tuple"); return 0; } stack = _PyTuple_ITEMS(args); nargs = PyTuple_GET_SIZE(args); } else { stack = NULL; nargs = 0; } return vgetargs1_impl(args, stack, nargs, format, p_va, flags); } static void seterror(Py_ssize_t iarg, const char *msg, int *levels, const char *fname, const char *message) { char buf[512]; int i; char *p = buf; if (PyErr_Occurred()) return; else if (message == NULL) { if (fname != NULL) { PyOS_snprintf(p, sizeof(buf), "%.200s() ", fname); p += strlen(p); } if (iarg != 0) { PyOS_snprintf(p, sizeof(buf) - (p - buf), "argument %zd", iarg); i = 0; p += strlen(p); while (i < 32 && levels[i] > 0 && (int)(p-buf) < 220) { PyOS_snprintf(p, sizeof(buf) - (p - buf), ", item %d", levels[i]-1); p += strlen(p); i++; } } else { PyOS_snprintf(p, sizeof(buf) - (p - buf), "argument"); p += strlen(p); } PyOS_snprintf(p, sizeof(buf) - (p - buf), " %.256s", msg); message = buf; } if (msg[0] == '(') { PyErr_SetString(PyExc_SystemError, message); } else { PyErr_SetString(PyExc_TypeError, message); } } /* Convert a tuple argument. On entry, *p_format points to the character _after_ the opening '('. On successful exit, *p_format points to the closing ')'. If successful: *p_format and *p_va are updated, *levels and *msgbuf are untouched, and NULL is returned. If the argument is invalid: *p_format is unchanged, *p_va is undefined, *levels is a 0-terminated list of item numbers, *msgbuf contains an error message, whose format is: "must be , not ", where: is the name of the expected type, and is the name of the actual type, and msgbuf is returned. */ static const char * converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, int *levels, char *msgbuf, size_t bufsize, int toplevel, freelist_t *freelist) { int level = 0; int n = 0; const char *format = *p_format; int i; Py_ssize_t len; for (;;) { int c = *format++; if (c == '(') { if (level == 0) n++; level++; } else if (c == ')') { if (level == 0) break; level--; } else if (c == ':' || c == ';' || c == '\0') break; else if (level == 0 && Py_ISALPHA(c)) n++; } if (!PySequence_Check(arg) || PyBytes_Check(arg)) { levels[0] = 0; PyOS_snprintf(msgbuf, bufsize, toplevel ? "expected %d arguments, not %.50s" : "must be %d-item sequence, not %.50s", n, arg == Py_None ? "None" : Py_TYPE(arg)->tp_name); return msgbuf; } len = PySequence_Size(arg); if (len != n) { levels[0] = 0; if (toplevel) { PyOS_snprintf(msgbuf, bufsize, "expected %d argument%s, not %zd", n, n == 1 ? "" : "s", len); } else { PyOS_snprintf(msgbuf, bufsize, "must be sequence of length %d, not %zd", n, len); } return msgbuf; } format = *p_format; for (i = 0; i < n; i++) { const char *msg; PyObject *item; item = PySequence_GetItem(arg, i); if (item == NULL) { PyErr_Clear(); levels[0] = i+1; levels[1] = 0; strncpy(msgbuf, "is not retrievable", bufsize); return msgbuf; } msg = convertitem(item, &format, p_va, flags, levels+1, msgbuf, bufsize, freelist); /* PySequence_GetItem calls tp->sq_item, which INCREFs */ Py_XDECREF(item); if (msg != NULL) { levels[0] = i+1; return msg; } } *p_format = format; return NULL; } /* Convert a single item. */ static const char * convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags, int *levels, char *msgbuf, size_t bufsize, freelist_t *freelist) { const char *msg; const char *format = *p_format; if (*format == '(' /* ')' */) { format++; msg = converttuple(arg, &format, p_va, flags, levels, msgbuf, bufsize, 0, freelist); if (msg == NULL) format++; } else { msg = convertsimple(arg, &format, p_va, flags, msgbuf, bufsize, freelist); if (msg != NULL) levels[0] = 0; } if (msg == NULL) *p_format = format; return msg; } /* Format an error message generated by convertsimple(). displayname must be UTF-8 encoded. */ void _PyArg_BadArgument(const char *fname, const char *displayname, const char *expected, PyObject *arg) { PyErr_Format(PyExc_TypeError, "%.200s() %.200s must be %.50s, not %.50s", fname, displayname, expected, arg == Py_None ? "None" : Py_TYPE(arg)->tp_name); } static const char * converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize) { assert(expected != NULL); assert(arg != NULL); if (expected[0] == '(') { PyOS_snprintf(msgbuf, bufsize, "%.100s", expected); } else { PyOS_snprintf(msgbuf, bufsize, "must be %.50s, not %.50s", expected, arg == Py_None ? "None" : Py_TYPE(arg)->tp_name); } return msgbuf; } #define CONV_UNICODE "(unicode conversion error)" /* Convert a non-tuple argument. Return NULL if conversion went OK, or a string with a message describing the failure. The message is formatted as "must be , not ". When failing, an exception may or may not have been raised. Don't call if a tuple is expected. When you add new format codes, please don't forget poor skipitem() below. */ static const char * convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, char *msgbuf, size_t bufsize, freelist_t *freelist) { #define RETURN_ERR_OCCURRED return msgbuf const char *format = *p_format; char c = *format++; const char *sarg; switch (c) { case 'b': { /* unsigned byte -- very short int */ char *p = va_arg(*p_va, char *); long ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else if (ival < 0) { PyErr_SetString(PyExc_OverflowError, "unsigned byte integer is less than minimum"); RETURN_ERR_OCCURRED; } else if (ival > UCHAR_MAX) { PyErr_SetString(PyExc_OverflowError, "unsigned byte integer is greater than maximum"); RETURN_ERR_OCCURRED; } else *p = (unsigned char) ival; break; } case 'B': {/* byte sized bitfield - both signed and unsigned values allowed */ char *p = va_arg(*p_va, char *); unsigned long ival = PyLong_AsUnsignedLongMask(arg); if (ival == (unsigned long)-1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = (unsigned char) ival; break; } case 'h': {/* signed short int */ short *p = va_arg(*p_va, short *); long ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else if (ival < SHRT_MIN) { PyErr_SetString(PyExc_OverflowError, "signed short integer is less than minimum"); RETURN_ERR_OCCURRED; } else if (ival > SHRT_MAX) { PyErr_SetString(PyExc_OverflowError, "signed short integer is greater than maximum"); RETURN_ERR_OCCURRED; } else *p = (short) ival; break; } case 'H': { /* short int sized bitfield, both signed and unsigned allowed */ unsigned short *p = va_arg(*p_va, unsigned short *); unsigned long ival = PyLong_AsUnsignedLongMask(arg); if (ival == (unsigned long)-1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = (unsigned short) ival; break; } case 'i': {/* signed int */ int *p = va_arg(*p_va, int *); long ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else if (ival > INT_MAX) { PyErr_SetString(PyExc_OverflowError, "signed integer is greater than maximum"); RETURN_ERR_OCCURRED; } else if (ival < INT_MIN) { PyErr_SetString(PyExc_OverflowError, "signed integer is less than minimum"); RETURN_ERR_OCCURRED; } else *p = ival; break; } case 'I': { /* int sized bitfield, both signed and unsigned allowed */ unsigned int *p = va_arg(*p_va, unsigned int *); unsigned long ival = PyLong_AsUnsignedLongMask(arg); if (ival == (unsigned long)-1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = (unsigned int) ival; break; } case 'n': /* Py_ssize_t */ { PyObject *iobj; Py_ssize_t *p = va_arg(*p_va, Py_ssize_t *); Py_ssize_t ival = -1; iobj = _PyNumber_Index(arg); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); } if (ival == -1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; *p = ival; break; } case 'l': {/* long int */ long *p = va_arg(*p_va, long *); long ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = ival; break; } case 'k': { /* long sized bitfield */ unsigned long *p = va_arg(*p_va, unsigned long *); unsigned long ival; if (PyLong_Check(arg)) ival = PyLong_AsUnsignedLongMask(arg); else return converterr("int", arg, msgbuf, bufsize); *p = ival; break; } case 'L': {/* long long */ long long *p = va_arg( *p_va, long long * ); long long ival = PyLong_AsLongLong(arg); if (ival == (long long)-1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = ival; break; } case 'K': { /* long long sized bitfield */ unsigned long long *p = va_arg(*p_va, unsigned long long *); unsigned long long ival; if (PyLong_Check(arg)) ival = PyLong_AsUnsignedLongLongMask(arg); else return converterr("int", arg, msgbuf, bufsize); *p = ival; break; } case 'f': {/* float */ float *p = va_arg(*p_va, float *); double dval = PyFloat_AsDouble(arg); if (dval == -1.0 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = (float) dval; break; } case 'd': {/* double */ double *p = va_arg(*p_va, double *); double dval = PyFloat_AsDouble(arg); if (dval == -1.0 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = dval; break; } case 'D': {/* complex double */ Py_complex *p = va_arg(*p_va, Py_complex *); Py_complex cval; cval = PyComplex_AsCComplex(arg); if (PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = cval; break; } case 'c': {/* char */ char *p = va_arg(*p_va, char *); if (PyBytes_Check(arg) && PyBytes_Size(arg) == 1) *p = PyBytes_AS_STRING(arg)[0]; else if (PyByteArray_Check(arg) && PyByteArray_Size(arg) == 1) *p = PyByteArray_AS_STRING(arg)[0]; else return converterr("a byte string of length 1", arg, msgbuf, bufsize); break; } case 'C': {/* unicode char */ int *p = va_arg(*p_va, int *); int kind; const void *data; if (!PyUnicode_Check(arg)) return converterr("a unicode character", arg, msgbuf, bufsize); if (PyUnicode_GET_LENGTH(arg) != 1) return converterr("a unicode character", arg, msgbuf, bufsize); kind = PyUnicode_KIND(arg); data = PyUnicode_DATA(arg); *p = PyUnicode_READ(kind, data, 0); break; } case 'p': {/* boolean *p*redicate */ int *p = va_arg(*p_va, int *); int val = PyObject_IsTrue(arg); if (val > 0) *p = 1; else if (val == 0) *p = 0; else RETURN_ERR_OCCURRED; break; } /* XXX WAAAAH! 's', 'y', 'z', 'u', 'Z', 'e', 'w' codes all need to be cleaned up! */ case 'y': {/* any bytes-like object */ void **p = (void **)va_arg(*p_va, char **); const char *buf; Py_ssize_t count; if (*format == '*') { if (getbuffer(arg, (Py_buffer*)p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); format++; if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); } break; } count = convertbuffer(arg, (const void **)p, &buf); if (count < 0) return converterr(buf, arg, msgbuf, bufsize); if (*format == '#') { Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*); *psize = count; format++; } else { if (strlen(*p) != (size_t)count) { PyErr_SetString(PyExc_ValueError, "embedded null byte"); RETURN_ERR_OCCURRED; } } break; } case 's': /* text string or bytes-like object */ case 'z': /* text string, bytes-like object or None */ { if (*format == '*') { /* "s*" or "z*" */ Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *); if (c == 'z' && arg == Py_None) PyBuffer_FillInfo(p, NULL, NULL, 0, 1, 0); else if (PyUnicode_Check(arg)) { Py_ssize_t len; sarg = PyUnicode_AsUTF8AndSize(arg, &len); if (sarg == NULL) return converterr(CONV_UNICODE, arg, msgbuf, bufsize); PyBuffer_FillInfo(p, arg, (void *)sarg, len, 1, 0); } else { /* any bytes-like object */ const char *buf; if (getbuffer(arg, p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); } if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); } format++; } else if (*format == '#') { /* a string or read-only bytes-like object */ /* "s#" or "z#" */ const void **p = (const void **)va_arg(*p_va, const char **); Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*); if (c == 'z' && arg == Py_None) { *p = NULL; *psize = 0; } else if (PyUnicode_Check(arg)) { Py_ssize_t len; sarg = PyUnicode_AsUTF8AndSize(arg, &len); if (sarg == NULL) return converterr(CONV_UNICODE, arg, msgbuf, bufsize); *p = sarg; *psize = len; } else { /* read-only bytes-like object */ /* XXX Really? */ const char *buf; Py_ssize_t count = convertbuffer(arg, p, &buf); if (count < 0) return converterr(buf, arg, msgbuf, bufsize); *psize = count; } format++; } else { /* "s" or "z" */ const char **p = va_arg(*p_va, const char **); Py_ssize_t len; sarg = NULL; if (c == 'z' && arg == Py_None) *p = NULL; else if (PyUnicode_Check(arg)) { sarg = PyUnicode_AsUTF8AndSize(arg, &len); if (sarg == NULL) return converterr(CONV_UNICODE, arg, msgbuf, bufsize); if (strlen(sarg) != (size_t)len) { PyErr_SetString(PyExc_ValueError, "embedded null character"); RETURN_ERR_OCCURRED; } *p = sarg; } else return converterr(c == 'z' ? "str or None" : "str", arg, msgbuf, bufsize); } break; } case 'e': {/* encoded string */ char **buffer; const char *encoding; PyObject *s; int recode_strings; Py_ssize_t size; const char *ptr; /* Get 'e' parameter: the encoding name */ encoding = (const char *)va_arg(*p_va, const char *); if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); /* Get output buffer parameter: 's' (recode all objects via Unicode) or 't' (only recode non-string objects) */ if (*format == 's') recode_strings = 1; else if (*format == 't') recode_strings = 0; else return converterr( "(unknown parser marker combination)", arg, msgbuf, bufsize); buffer = (char **)va_arg(*p_va, char **); format++; if (buffer == NULL) return converterr("(buffer is NULL)", arg, msgbuf, bufsize); /* Encode object */ if (!recode_strings && (PyBytes_Check(arg) || PyByteArray_Check(arg))) { s = Py_NewRef(arg); if (PyBytes_Check(arg)) { size = PyBytes_GET_SIZE(s); ptr = PyBytes_AS_STRING(s); } else { size = PyByteArray_GET_SIZE(s); ptr = PyByteArray_AS_STRING(s); } } else if (PyUnicode_Check(arg)) { /* Encode object; use default error handling */ s = PyUnicode_AsEncodedString(arg, encoding, NULL); if (s == NULL) return converterr("(encoding failed)", arg, msgbuf, bufsize); assert(PyBytes_Check(s)); size = PyBytes_GET_SIZE(s); ptr = PyBytes_AS_STRING(s); if (ptr == NULL) ptr = ""; } else { return converterr( recode_strings ? "str" : "str, bytes or bytearray", arg, msgbuf, bufsize); } /* Write output; output is guaranteed to be 0-terminated */ if (*format == '#') { /* Using buffer length parameter '#': - if *buffer is NULL, a new buffer of the needed size is allocated and the data copied into it; *buffer is updated to point to the new buffer; the caller is responsible for PyMem_Free()ing it after usage - if *buffer is not NULL, the data is copied to *buffer; *buffer_len has to be set to the size of the buffer on input; buffer overflow is signalled with an error; buffer has to provide enough room for the encoded string plus the trailing 0-byte - in both cases, *buffer_len is updated to the size of the buffer /excluding/ the trailing 0-byte */ Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*); format++; if (psize == NULL) { Py_DECREF(s); return converterr( "(buffer_len is NULL)", arg, msgbuf, bufsize); } if (*buffer == NULL) { *buffer = PyMem_NEW(char, size + 1); if (*buffer == NULL) { Py_DECREF(s); PyErr_NoMemory(); RETURN_ERR_OCCURRED; } if (addcleanup(buffer, freelist, cleanup_ptr)) { Py_DECREF(s); return converterr( "(cleanup problem)", arg, msgbuf, bufsize); } } else { if (size + 1 > *psize) { Py_DECREF(s); PyErr_Format(PyExc_ValueError, "encoded string too long " "(%zd, maximum length %zd)", (Py_ssize_t)size, (Py_ssize_t)(*psize - 1)); RETURN_ERR_OCCURRED; } } memcpy(*buffer, ptr, size+1); *psize = size; } else { /* Using a 0-terminated buffer: - the encoded string has to be 0-terminated for this variant to work; if it is not, an error raised - a new buffer of the needed size is allocated and the data copied into it; *buffer is updated to point to the new buffer; the caller is responsible for PyMem_Free()ing it after usage */ if ((Py_ssize_t)strlen(ptr) != size) { Py_DECREF(s); return converterr( "encoded string without null bytes", arg, msgbuf, bufsize); } *buffer = PyMem_NEW(char, size + 1); if (*buffer == NULL) { Py_DECREF(s); PyErr_NoMemory(); RETURN_ERR_OCCURRED; } if (addcleanup(buffer, freelist, cleanup_ptr)) { Py_DECREF(s); return converterr("(cleanup problem)", arg, msgbuf, bufsize); } memcpy(*buffer, ptr, size+1); } Py_DECREF(s); break; } case 'S': { /* PyBytes object */ PyObject **p = va_arg(*p_va, PyObject **); if (PyBytes_Check(arg)) *p = arg; else return converterr("bytes", arg, msgbuf, bufsize); break; } case 'Y': { /* PyByteArray object */ PyObject **p = va_arg(*p_va, PyObject **); if (PyByteArray_Check(arg)) *p = arg; else return converterr("bytearray", arg, msgbuf, bufsize); break; } case 'U': { /* PyUnicode object */ PyObject **p = va_arg(*p_va, PyObject **); if (PyUnicode_Check(arg)) { *p = arg; } else return converterr("str", arg, msgbuf, bufsize); break; } case 'O': { /* object */ PyTypeObject *type; PyObject **p; if (*format == '!') { type = va_arg(*p_va, PyTypeObject*); p = va_arg(*p_va, PyObject **); format++; if (PyType_IsSubtype(Py_TYPE(arg), type)) *p = arg; else return converterr(type->tp_name, arg, msgbuf, bufsize); } else if (*format == '&') { typedef int (*converter)(PyObject *, void *); converter convert = va_arg(*p_va, converter); void *addr = va_arg(*p_va, void *); int res; format++; if (! (res = (*convert)(arg, addr))) return converterr("(unspecified)", arg, msgbuf, bufsize); if (res == Py_CLEANUP_SUPPORTED && addcleanup(addr, freelist, convert) == -1) return converterr("(cleanup problem)", arg, msgbuf, bufsize); } else { p = va_arg(*p_va, PyObject **); *p = arg; } break; } case 'w': { /* "w*": memory buffer, read-write access */ void **p = va_arg(*p_va, void **); if (*format != '*') return converterr( "(invalid use of 'w' format character)", arg, msgbuf, bufsize); format++; /* Caller is interested in Py_buffer, and the object supports it directly. */ if (PyObject_GetBuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) { PyErr_Clear(); return converterr("read-write bytes-like object", arg, msgbuf, bufsize); } if (!PyBuffer_IsContiguous((Py_buffer*)p, 'C')) { PyBuffer_Release((Py_buffer*)p); return converterr("contiguous buffer", arg, msgbuf, bufsize); } if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); } break; } default: return converterr("(impossible)", arg, msgbuf, bufsize); } *p_format = format; return NULL; #undef RETURN_ERR_OCCURRED } static Py_ssize_t convertbuffer(PyObject *arg, const void **p, const char **errmsg) { PyBufferProcs *pb = Py_TYPE(arg)->tp_as_buffer; Py_ssize_t count; Py_buffer view; *errmsg = NULL; *p = NULL; if (pb != NULL && pb->bf_releasebuffer != NULL) { *errmsg = "read-only bytes-like object"; return -1; } if (getbuffer(arg, &view, errmsg) < 0) return -1; count = view.len; *p = view.buf; PyBuffer_Release(&view); return count; } static int getbuffer(PyObject *arg, Py_buffer *view, const char **errmsg) { if (PyObject_GetBuffer(arg, view, PyBUF_SIMPLE) != 0) { *errmsg = "bytes-like object"; return -1; } if (!PyBuffer_IsContiguous(view, 'C')) { PyBuffer_Release(view); *errmsg = "contiguous buffer"; return -1; } return 0; } /* Support for keyword arguments donated by Geoff Philbrick */ /* Return false (0) for error, else true. */ int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *keywords, const char *format, char **kwlist, ...) { int retval; va_list va; if ((args == NULL || !PyTuple_Check(args)) || (keywords != NULL && !PyDict_Check(keywords)) || format == NULL || kwlist == NULL) { PyErr_BadInternalCall(); return 0; } va_start(va, kwlist); retval = vgetargskeywords(args, keywords, format, kwlist, &va, 0); va_end(va); return retval; } int _PyArg_ParseTupleAndKeywords_SizeT(PyObject *args, PyObject *keywords, const char *format, char **kwlist, ...) { int retval; va_list va; if ((args == NULL || !PyTuple_Check(args)) || (keywords != NULL && !PyDict_Check(keywords)) || format == NULL || kwlist == NULL) { PyErr_BadInternalCall(); return 0; } va_start(va, kwlist); retval = vgetargskeywords(args, keywords, format, kwlist, &va, 0); va_end(va); return retval; } int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *keywords, const char *format, char **kwlist, va_list va) { int retval; va_list lva; if ((args == NULL || !PyTuple_Check(args)) || (keywords != NULL && !PyDict_Check(keywords)) || format == NULL || kwlist == NULL) { PyErr_BadInternalCall(); return 0; } va_copy(lva, va); retval = vgetargskeywords(args, keywords, format, kwlist, &lva, 0); va_end(lva); return retval; } int _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args, PyObject *keywords, const char *format, char **kwlist, va_list va) { int retval; va_list lva; if ((args == NULL || !PyTuple_Check(args)) || (keywords != NULL && !PyDict_Check(keywords)) || format == NULL || kwlist == NULL) { PyErr_BadInternalCall(); return 0; } va_copy(lva, va); retval = vgetargskeywords(args, keywords, format, kwlist, &lva, 0); va_end(lva); return retval; } PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywordsFast(PyObject *args, PyObject *keywords, struct _PyArg_Parser *parser, ...) { int retval; va_list va; va_start(va, parser); retval = vgetargskeywordsfast(args, keywords, parser, &va, 0); va_end(va); return retval; } int _PyArg_ParseTupleAndKeywordsFast_SizeT(PyObject *args, PyObject *keywords, struct _PyArg_Parser *parser, ...) { int retval; va_list va; va_start(va, parser); retval = vgetargskeywordsfast(args, keywords, parser, &va, 0); va_end(va); return retval; } int _PyArg_ParseStackAndKeywords(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames, struct _PyArg_Parser *parser, ...) { int retval; va_list va; va_start(va, parser); retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va, 0); va_end(va); return retval; } int _PyArg_ParseStackAndKeywords_SizeT(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames, struct _PyArg_Parser *parser, ...) { int retval; va_list va; va_start(va, parser); retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va, 0); va_end(va); return retval; } PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywordsFast(PyObject *args, PyObject *keywords, struct _PyArg_Parser *parser, va_list va) { int retval; va_list lva; va_copy(lva, va); retval = vgetargskeywordsfast(args, keywords, parser, &lva, 0); va_end(lva); return retval; } static void error_unexpected_keyword_arg(PyObject *kwargs, PyObject *kwnames, PyObject *kwtuple, const char *fname) { /* make sure there are no extraneous keyword arguments */ Py_ssize_t j = 0; while (1) { PyObject *keyword; if (kwargs != NULL) { if (!PyDict_Next(kwargs, &j, &keyword, NULL)) break; } else { if (j >= PyTuple_GET_SIZE(kwnames)) break; keyword = PyTuple_GET_ITEM(kwnames, j); j++; } if (!PyUnicode_Check(keyword)) { PyErr_SetString(PyExc_TypeError, "keywords must be strings"); return; } int match = PySequence_Contains(kwtuple, keyword); if (match <= 0) { if (!match) { PyErr_Format(PyExc_TypeError, "'%S' is an invalid keyword " "argument for %.200s%s", keyword, (fname == NULL) ? "this function" : fname, (fname == NULL) ? "" : "()"); } return; } } /* Something wrong happened. There are extraneous keyword arguments, * but we don't know what. And we don't bother. */ PyErr_Format(PyExc_TypeError, "invalid keyword argument for %.200s%s", (fname == NULL) ? "this function" : fname, (fname == NULL) ? "" : "()"); } int PyArg_ValidateKeywordArguments(PyObject *kwargs) { if (!PyDict_Check(kwargs)) { PyErr_BadInternalCall(); return 0; } if (!_PyDict_HasOnlyStringKeys(kwargs)) { PyErr_SetString(PyExc_TypeError, "keywords must be strings"); return 0; } return 1; } #define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':') static int vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, char **kwlist, va_list *p_va, int flags) { char msgbuf[512]; int levels[32]; const char *fname, *msg, *custom_msg; int min = INT_MAX; int max = INT_MAX; int i, pos, len; int skip = 0; Py_ssize_t nargs, nkwargs; PyObject *current_arg; freelistentry_t static_entries[STATIC_FREELIST_ENTRIES]; freelist_t freelist; freelist.entries = static_entries; freelist.first_available = 0; freelist.entries_malloced = 0; assert(args != NULL && PyTuple_Check(args)); assert(kwargs == NULL || PyDict_Check(kwargs)); assert(format != NULL); assert(kwlist != NULL); assert(p_va != NULL); /* grab the function name or custom error msg first (mutually exclusive) */ fname = strchr(format, ':'); if (fname) { fname++; custom_msg = NULL; } else { custom_msg = strchr(format,';'); if (custom_msg) custom_msg++; } /* scan kwlist and count the number of positional-only parameters */ for (pos = 0; kwlist[pos] && !*kwlist[pos]; pos++) { } /* scan kwlist and get greatest possible nbr of args */ for (len = pos; kwlist[len]; len++) { if (!*kwlist[len]) { PyErr_SetString(PyExc_SystemError, "Empty keyword parameter name"); return cleanreturn(0, &freelist); } } if (len > STATIC_FREELIST_ENTRIES) { freelist.entries = PyMem_NEW(freelistentry_t, len); if (freelist.entries == NULL) { PyErr_NoMemory(); return 0; } freelist.entries_malloced = 1; } nargs = PyTuple_GET_SIZE(args); nkwargs = (kwargs == NULL) ? 0 : PyDict_GET_SIZE(kwargs); if (nargs + nkwargs > len) { /* Adding "keyword" (when nargs == 0) prevents producing wrong error messages in some special cases (see bpo-31229). */ PyErr_Format(PyExc_TypeError, "%.200s%s takes at most %d %sargument%s (%zd given)", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()", len, (nargs == 0) ? "keyword " : "", (len == 1) ? "" : "s", nargs + nkwargs); return cleanreturn(0, &freelist); } /* convert tuple args and keyword args in same loop, using kwlist to drive process */ for (i = 0; i < len; i++) { if (*format == '|') { if (min != INT_MAX) { PyErr_SetString(PyExc_SystemError, "Invalid format string (| specified twice)"); return cleanreturn(0, &freelist); } min = i; format++; if (max != INT_MAX) { PyErr_SetString(PyExc_SystemError, "Invalid format string ($ before |)"); return cleanreturn(0, &freelist); } } if (*format == '$') { if (max != INT_MAX) { PyErr_SetString(PyExc_SystemError, "Invalid format string ($ specified twice)"); return cleanreturn(0, &freelist); } max = i; format++; if (max < pos) { PyErr_SetString(PyExc_SystemError, "Empty parameter name after $"); return cleanreturn(0, &freelist); } if (skip) { /* Now we know the minimal and the maximal numbers of * positional arguments and can raise an exception with * informative message (see below). */ break; } if (max < nargs) { if (max == 0) { PyErr_Format(PyExc_TypeError, "%.200s%s takes no positional arguments", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()"); } else { PyErr_Format(PyExc_TypeError, "%.200s%s takes %s %d positional argument%s" " (%zd given)", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()", (min != INT_MAX) ? "at most" : "exactly", max, max == 1 ? "" : "s", nargs); } return cleanreturn(0, &freelist); } } if (IS_END_OF_FORMAT(*format)) { PyErr_Format(PyExc_SystemError, "More keyword list entries (%d) than " "format specifiers (%d)", len, i); return cleanreturn(0, &freelist); } if (!skip) { if (i < nargs) { current_arg = PyTuple_GET_ITEM(args, i); } else if (nkwargs && i >= pos) { current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]); if (current_arg) { --nkwargs; } else if (PyErr_Occurred()) { return cleanreturn(0, &freelist); } } else { current_arg = NULL; } if (current_arg) { msg = convertitem(current_arg, &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { seterror(i+1, msg, levels, fname, custom_msg); return cleanreturn(0, &freelist); } continue; } if (i < min) { if (i < pos) { assert (min == INT_MAX); assert (max == INT_MAX); skip = 1; /* At that moment we still don't know the minimal and * the maximal numbers of positional arguments. Raising * an exception is deferred until we encounter | and $ * or the end of the format. */ } else { PyErr_Format(PyExc_TypeError, "%.200s%s missing required " "argument '%s' (pos %d)", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()", kwlist[i], i+1); return cleanreturn(0, &freelist); } } /* current code reports success when all required args * fulfilled and no keyword args left, with no further * validation. XXX Maybe skip this in debug build ? */ if (!nkwargs && !skip) { return cleanreturn(1, &freelist); } } /* We are into optional args, skip through to any remaining * keyword args */ msg = skipitem(&format, p_va, flags); if (msg) { PyErr_Format(PyExc_SystemError, "%s: '%s'", msg, format); return cleanreturn(0, &freelist); } } if (skip) { PyErr_Format(PyExc_TypeError, "%.200s%s takes %s %d positional argument%s" " (%zd given)", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()", (Py_MIN(pos, min) < i) ? "at least" : "exactly", Py_MIN(pos, min), Py_MIN(pos, min) == 1 ? "" : "s", nargs); return cleanreturn(0, &freelist); } if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) { PyErr_Format(PyExc_SystemError, "more argument specifiers than keyword list entries " "(remaining format:'%s')", format); return cleanreturn(0, &freelist); } if (nkwargs > 0) { PyObject *key; Py_ssize_t j; /* make sure there are no arguments given by name and position */ for (i = pos; i < nargs; i++) { current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]); if (current_arg) { /* arg present in tuple and in dict */ PyErr_Format(PyExc_TypeError, "argument for %.200s%s given by name ('%s') " "and position (%d)", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()", kwlist[i], i+1); return cleanreturn(0, &freelist); } else if (PyErr_Occurred()) { return cleanreturn(0, &freelist); } } /* make sure there are no extraneous keyword arguments */ j = 0; while (PyDict_Next(kwargs, &j, &key, NULL)) { int match = 0; if (!PyUnicode_Check(key)) { PyErr_SetString(PyExc_TypeError, "keywords must be strings"); return cleanreturn(0, &freelist); } for (i = pos; i < len; i++) { if (_PyUnicode_EqualToASCIIString(key, kwlist[i])) { match = 1; break; } } if (!match) { PyErr_Format(PyExc_TypeError, "'%U' is an invalid keyword " "argument for %.200s%s", key, (fname == NULL) ? "this function" : fname, (fname == NULL) ? "" : "()"); return cleanreturn(0, &freelist); } } /* Something wrong happened. There are extraneous keyword arguments, * but we don't know what. And we don't bother. */ PyErr_Format(PyExc_TypeError, "invalid keyword argument for %.200s%s", (fname == NULL) ? "this function" : fname, (fname == NULL) ? "" : "()"); return cleanreturn(0, &freelist); } return cleanreturn(1, &freelist); } static int scan_keywords(const char * const *keywords, int *ptotal, int *pposonly) { /* scan keywords and count the number of positional-only parameters */ int i; for (i = 0; keywords[i] && !*keywords[i]; i++) { } *pposonly = i; /* scan keywords and get greatest possible nbr of args */ for (; keywords[i]; i++) { if (!*keywords[i]) { PyErr_SetString(PyExc_SystemError, "Empty keyword parameter name"); return -1; } } *ptotal = i; return 0; } static int parse_format(const char *format, int total, int npos, const char **pfname, const char **pcustommsg, int *pmin, int *pmax) { /* grab the function name or custom error msg first (mutually exclusive) */ const char *custommsg; const char *fname = strchr(format, ':'); if (fname) { fname++; custommsg = NULL; } else { custommsg = strchr(format,';'); if (custommsg) { custommsg++; } } int min = INT_MAX; int max = INT_MAX; for (int i = 0; i < total; i++) { if (*format == '|') { if (min != INT_MAX) { PyErr_SetString(PyExc_SystemError, "Invalid format string (| specified twice)"); return -1; } if (max != INT_MAX) { PyErr_SetString(PyExc_SystemError, "Invalid format string ($ before |)"); return -1; } min = i; format++; } if (*format == '$') { if (max != INT_MAX) { PyErr_SetString(PyExc_SystemError, "Invalid format string ($ specified twice)"); return -1; } if (i < npos) { PyErr_SetString(PyExc_SystemError, "Empty parameter name after $"); return -1; } max = i; format++; } if (IS_END_OF_FORMAT(*format)) { PyErr_Format(PyExc_SystemError, "More keyword list entries (%d) than " "format specifiers (%d)", total, i); return -1; } const char *msg = skipitem(&format, NULL, 0); if (msg) { PyErr_Format(PyExc_SystemError, "%s: '%s'", msg, format); return -1; } } min = Py_MIN(min, total); max = Py_MIN(max, total); if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) { PyErr_Format(PyExc_SystemError, "more argument specifiers than keyword list entries " "(remaining format:'%s')", format); return -1; } *pfname = fname; *pcustommsg = custommsg; *pmin = min; *pmax = max; return 0; } static PyObject * new_kwtuple(const char * const *keywords, int total, int pos) { int nkw = total - pos; PyObject *kwtuple = PyTuple_New(nkw); if (kwtuple == NULL) { return NULL; } keywords += pos; for (int i = 0; i < nkw; i++) { PyObject *str = PyUnicode_FromString(keywords[i]); if (str == NULL) { Py_DECREF(kwtuple); return NULL; } PyUnicode_InternInPlace(&str); PyTuple_SET_ITEM(kwtuple, i, str); } return kwtuple; } static int _parser_init(struct _PyArg_Parser *parser) { const char * const *keywords = parser->keywords; assert(keywords != NULL); assert(parser->pos == 0 && (parser->format == NULL || parser->fname == NULL) && parser->custom_msg == NULL && parser->min == 0 && parser->max == 0); int len, pos; if (scan_keywords(keywords, &len, &pos) < 0) { return 0; } const char *fname, *custommsg = NULL; int min = 0, max = 0; if (parser->format) { assert(parser->fname == NULL); if (parse_format(parser->format, len, pos, &fname, &custommsg, &min, &max) < 0) { return 0; } } else { assert(parser->fname != NULL); fname = parser->fname; } int owned; PyObject *kwtuple = parser->kwtuple; if (kwtuple == NULL) { kwtuple = new_kwtuple(keywords, len, pos); if (kwtuple == NULL) { return 0; } owned = 1; } else { owned = 0; } parser->pos = pos; parser->fname = fname; parser->custom_msg = custommsg; parser->min = min; parser->max = max; parser->kwtuple = kwtuple; parser->initialized = owned ? 1 : -1; assert(parser->next == NULL); parser->next = _PyRuntime.getargs.static_parsers; _PyRuntime.getargs.static_parsers = parser; return 1; } static int parser_init(struct _PyArg_Parser *parser) { // volatile as it can be modified by other threads // and should not be optimized or reordered by compiler if (*((volatile int *)&parser->initialized)) { assert(parser->kwtuple != NULL); return 1; } PyThread_acquire_lock(_PyRuntime.getargs.mutex, WAIT_LOCK); // Check again if another thread initialized the parser // while we were waiting for the lock. if (*((volatile int *)&parser->initialized)) { assert(parser->kwtuple != NULL); PyThread_release_lock(_PyRuntime.getargs.mutex); return 1; } int ret = _parser_init(parser); PyThread_release_lock(_PyRuntime.getargs.mutex); return ret; } static void parser_clear(struct _PyArg_Parser *parser) { if (parser->initialized == 1) { Py_CLEAR(parser->kwtuple); } } static PyObject* find_keyword(PyObject *kwnames, PyObject *const *kwstack, PyObject *key) { Py_ssize_t i, nkwargs; nkwargs = PyTuple_GET_SIZE(kwnames); for (i = 0; i < nkwargs; i++) { PyObject *kwname = PyTuple_GET_ITEM(kwnames, i); /* kwname == key will normally find a match in since keyword keys should be interned strings; if not retry below in a new loop. */ if (kwname == key) { return kwstack[i]; } } for (i = 0; i < nkwargs; i++) { PyObject *kwname = PyTuple_GET_ITEM(kwnames, i); assert(PyUnicode_Check(kwname)); if (_PyUnicode_EQ(kwname, key)) { return kwstack[i]; } } return NULL; } static int vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs, PyObject *kwnames, struct _PyArg_Parser *parser, va_list *p_va, int flags) { PyObject *kwtuple; char msgbuf[512]; int levels[32]; const char *format; const char *msg; PyObject *keyword; int i, pos, len; Py_ssize_t nkwargs; PyObject *current_arg; freelistentry_t static_entries[STATIC_FREELIST_ENTRIES]; freelist_t freelist; PyObject *const *kwstack = NULL; freelist.entries = static_entries; freelist.first_available = 0; freelist.entries_malloced = 0; assert(kwargs == NULL || PyDict_Check(kwargs)); assert(kwargs == NULL || kwnames == NULL); assert(p_va != NULL); if (parser == NULL) { PyErr_BadInternalCall(); return 0; } if (kwnames != NULL && !PyTuple_Check(kwnames)) { PyErr_BadInternalCall(); return 0; } if (!parser_init(parser)) { return 0; } kwtuple = parser->kwtuple; pos = parser->pos; len = pos + (int)PyTuple_GET_SIZE(kwtuple); if (len > STATIC_FREELIST_ENTRIES) { freelist.entries = PyMem_NEW(freelistentry_t, len); if (freelist.entries == NULL) { PyErr_NoMemory(); return 0; } freelist.entries_malloced = 1; } if (kwargs != NULL) { nkwargs = PyDict_GET_SIZE(kwargs); } else if (kwnames != NULL) { nkwargs = PyTuple_GET_SIZE(kwnames); kwstack = args + nargs; } else { nkwargs = 0; } if (nargs + nkwargs > len) { /* Adding "keyword" (when nargs == 0) prevents producing wrong error messages in some special cases (see bpo-31229). */ PyErr_Format(PyExc_TypeError, "%.200s%s takes at most %d %sargument%s (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", len, (nargs == 0) ? "keyword " : "", (len == 1) ? "" : "s", nargs + nkwargs); return cleanreturn(0, &freelist); } if (parser->max < nargs) { if (parser->max == 0) { PyErr_Format(PyExc_TypeError, "%.200s%s takes no positional arguments", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()"); } else { PyErr_Format(PyExc_TypeError, "%.200s%s takes %s %d positional argument%s (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", (parser->min < parser->max) ? "at most" : "exactly", parser->max, parser->max == 1 ? "" : "s", nargs); } return cleanreturn(0, &freelist); } format = parser->format; assert(format != NULL || len == 0); /* convert tuple args and keyword args in same loop, using kwtuple to drive process */ for (i = 0; i < len; i++) { if (*format == '|') { format++; } if (*format == '$') { format++; } assert(!IS_END_OF_FORMAT(*format)); if (i < nargs) { current_arg = args[i]; } else if (nkwargs && i >= pos) { keyword = PyTuple_GET_ITEM(kwtuple, i - pos); if (kwargs != NULL) { current_arg = PyDict_GetItemWithError(kwargs, keyword); if (!current_arg && PyErr_Occurred()) { return cleanreturn(0, &freelist); } } else { current_arg = find_keyword(kwnames, kwstack, keyword); } if (current_arg) { --nkwargs; } } else { current_arg = NULL; } if (current_arg) { msg = convertitem(current_arg, &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { seterror(i+1, msg, levels, parser->fname, parser->custom_msg); return cleanreturn(0, &freelist); } continue; } if (i < parser->min) { /* Less arguments than required */ if (i < pos) { Py_ssize_t min = Py_MIN(pos, parser->min); PyErr_Format(PyExc_TypeError, "%.200s%s takes %s %d positional argument%s" " (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", min < parser->max ? "at least" : "exactly", min, min == 1 ? "" : "s", nargs); } else { keyword = PyTuple_GET_ITEM(kwtuple, i - pos); PyErr_Format(PyExc_TypeError, "%.200s%s missing required " "argument '%U' (pos %d)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", keyword, i+1); } return cleanreturn(0, &freelist); } /* current code reports success when all required args * fulfilled and no keyword args left, with no further * validation. XXX Maybe skip this in debug build ? */ if (!nkwargs) { return cleanreturn(1, &freelist); } /* We are into optional args, skip through to any remaining * keyword args */ msg = skipitem(&format, p_va, flags); assert(msg == NULL); } assert(IS_END_OF_FORMAT(*format) || (*format == '|') || (*format == '$')); if (nkwargs > 0) { /* make sure there are no arguments given by name and position */ for (i = pos; i < nargs; i++) { keyword = PyTuple_GET_ITEM(kwtuple, i - pos); if (kwargs != NULL) { current_arg = PyDict_GetItemWithError(kwargs, keyword); if (!current_arg && PyErr_Occurred()) { return cleanreturn(0, &freelist); } } else { current_arg = find_keyword(kwnames, kwstack, keyword); } if (current_arg) { /* arg present in tuple and in dict */ PyErr_Format(PyExc_TypeError, "argument for %.200s%s given by name ('%U') " "and position (%d)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", keyword, i+1); return cleanreturn(0, &freelist); } } error_unexpected_keyword_arg(kwargs, kwnames, kwtuple, parser->fname); return cleanreturn(0, &freelist); } return cleanreturn(1, &freelist); } static int vgetargskeywordsfast(PyObject *args, PyObject *keywords, struct _PyArg_Parser *parser, va_list *p_va, int flags) { PyObject **stack; Py_ssize_t nargs; if (args == NULL || !PyTuple_Check(args) || (keywords != NULL && !PyDict_Check(keywords))) { PyErr_BadInternalCall(); return 0; } stack = _PyTuple_ITEMS(args); nargs = PyTuple_GET_SIZE(args); return vgetargskeywordsfast_impl(stack, nargs, keywords, NULL, parser, p_va, flags); } #undef _PyArg_UnpackKeywords PyObject * const * _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs, PyObject *kwnames, struct _PyArg_Parser *parser, int minpos, int maxpos, int minkw, PyObject **buf) { PyObject *kwtuple; PyObject *keyword; int i, posonly, minposonly, maxargs; int reqlimit = minkw ? maxpos + minkw : minpos; Py_ssize_t nkwargs; PyObject *current_arg; PyObject * const *kwstack = NULL; assert(kwargs == NULL || PyDict_Check(kwargs)); assert(kwargs == NULL || kwnames == NULL); if (parser == NULL) { PyErr_BadInternalCall(); return NULL; } if (kwnames != NULL && !PyTuple_Check(kwnames)) { PyErr_BadInternalCall(); return NULL; } if (args == NULL && nargs == 0) { args = buf; } if (!parser_init(parser)) { return NULL; } kwtuple = parser->kwtuple; posonly = parser->pos; minposonly = Py_MIN(posonly, minpos); maxargs = posonly + (int)PyTuple_GET_SIZE(kwtuple); if (kwargs != NULL) { nkwargs = PyDict_GET_SIZE(kwargs); } else if (kwnames != NULL) { nkwargs = PyTuple_GET_SIZE(kwnames); kwstack = args + nargs; } else { nkwargs = 0; } if (nkwargs == 0 && minkw == 0 && minpos <= nargs && nargs <= maxpos) { /* Fast path. */ return args; } if (nargs + nkwargs > maxargs) { /* Adding "keyword" (when nargs == 0) prevents producing wrong error messages in some special cases (see bpo-31229). */ PyErr_Format(PyExc_TypeError, "%.200s%s takes at most %d %sargument%s (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", maxargs, (nargs == 0) ? "keyword " : "", (maxargs == 1) ? "" : "s", nargs + nkwargs); return NULL; } if (nargs > maxpos) { if (maxpos == 0) { PyErr_Format(PyExc_TypeError, "%.200s%s takes no positional arguments", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()"); } else { PyErr_Format(PyExc_TypeError, "%.200s%s takes %s %d positional argument%s (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", (minpos < maxpos) ? "at most" : "exactly", maxpos, (maxpos == 1) ? "" : "s", nargs); } return NULL; } if (nargs < minposonly) { PyErr_Format(PyExc_TypeError, "%.200s%s takes %s %d positional argument%s" " (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", minposonly < maxpos ? "at least" : "exactly", minposonly, minposonly == 1 ? "" : "s", nargs); return NULL; } /* copy tuple args */ for (i = 0; i < nargs; i++) { buf[i] = args[i]; } /* copy keyword args using kwtuple to drive process */ for (i = Py_MAX((int)nargs, posonly); i < maxargs; i++) { if (nkwargs) { keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); if (kwargs != NULL) { current_arg = PyDict_GetItemWithError(kwargs, keyword); if (!current_arg && PyErr_Occurred()) { return NULL; } } else { current_arg = find_keyword(kwnames, kwstack, keyword); } } else if (i >= reqlimit) { break; } else { current_arg = NULL; } buf[i] = current_arg; if (current_arg) { --nkwargs; } else if (i < minpos || (maxpos <= i && i < reqlimit)) { /* Less arguments than required */ keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); PyErr_Format(PyExc_TypeError, "%.200s%s missing required " "argument '%U' (pos %d)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", keyword, i+1); return NULL; } } if (nkwargs > 0) { /* make sure there are no arguments given by name and position */ for (i = posonly; i < nargs; i++) { keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); if (kwargs != NULL) { current_arg = PyDict_GetItemWithError(kwargs, keyword); if (!current_arg && PyErr_Occurred()) { return NULL; } } else { current_arg = find_keyword(kwnames, kwstack, keyword); } if (current_arg) { /* arg present in tuple and in dict */ PyErr_Format(PyExc_TypeError, "argument for %.200s%s given by name ('%U') " "and position (%d)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", keyword, i+1); return NULL; } } error_unexpected_keyword_arg(kwargs, kwnames, kwtuple, parser->fname); return NULL; } return buf; } PyObject * const * _PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs, PyObject *kwnames, struct _PyArg_Parser *parser, int minpos, int maxpos, int minkw, int vararg, PyObject **buf) { PyObject *kwtuple; PyObject *keyword; Py_ssize_t varargssize = 0; int i, posonly, minposonly, maxargs; int reqlimit = minkw ? maxpos + minkw : minpos; Py_ssize_t nkwargs; PyObject *current_arg; PyObject * const *kwstack = NULL; assert(kwargs == NULL || PyDict_Check(kwargs)); assert(kwargs == NULL || kwnames == NULL); if (parser == NULL) { PyErr_BadInternalCall(); return NULL; } if (kwnames != NULL && !PyTuple_Check(kwnames)) { PyErr_BadInternalCall(); return NULL; } if (args == NULL && nargs == 0) { args = buf; } if (!parser_init(parser)) { return NULL; } kwtuple = parser->kwtuple; posonly = parser->pos; minposonly = Py_MIN(posonly, minpos); maxargs = posonly + (int)PyTuple_GET_SIZE(kwtuple); if (kwargs != NULL) { nkwargs = PyDict_GET_SIZE(kwargs); } else if (kwnames != NULL) { nkwargs = PyTuple_GET_SIZE(kwnames); kwstack = args + nargs; } else { nkwargs = 0; } if (nargs < minposonly) { PyErr_Format(PyExc_TypeError, "%.200s%s takes %s %d positional argument%s" " (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", minposonly < maxpos ? "at least" : "exactly", minposonly, minposonly == 1 ? "" : "s", nargs); return NULL; } /* create varargs tuple */ varargssize = nargs - maxpos; if (varargssize < 0) { varargssize = 0; } buf[vararg] = PyTuple_New(varargssize); if (!buf[vararg]) { return NULL; } /* copy tuple args */ for (i = 0; i < nargs; i++) { if (i >= vararg) { PyTuple_SET_ITEM(buf[vararg], i - vararg, Py_NewRef(args[i])); continue; } else { buf[i] = args[i]; } } /* copy keyword args using kwtuple to drive process */ for (i = Py_MAX((int)nargs, posonly) - Py_SAFE_DOWNCAST(varargssize, Py_ssize_t, int); i < maxargs; i++) { if (nkwargs) { keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); if (kwargs != NULL) { current_arg = PyDict_GetItemWithError(kwargs, keyword); if (!current_arg && PyErr_Occurred()) { goto exit; } } else { current_arg = find_keyword(kwnames, kwstack, keyword); } } else { current_arg = NULL; } /* If an arguments is passed in as a keyword argument, * it should be placed before `buf[vararg]`. * * For example: * def f(a, /, b, *args): * pass * f(1, b=2) * * This `buf` array should be: [1, 2, NULL]. * In this case, nargs < vararg. * * Otherwise, we leave a place at `buf[vararg]` for vararg tuple * so the index is `i + 1`. */ if (nargs < vararg) { buf[i] = current_arg; } else { buf[i + 1] = current_arg; } if (current_arg) { --nkwargs; } else if (i < minpos || (maxpos <= i && i < reqlimit)) { /* Less arguments than required */ keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); PyErr_Format(PyExc_TypeError, "%.200s%s missing required " "argument '%U' (pos %d)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", keyword, i+1); goto exit; } } if (nkwargs > 0) { error_unexpected_keyword_arg(kwargs, kwnames, kwtuple, parser->fname); goto exit; } return buf; exit: Py_XDECREF(buf[vararg]); return NULL; } static const char * skipitem(const char **p_format, va_list *p_va, int flags) { const char *format = *p_format; char c = *format++; switch (c) { /* * codes that take a single data pointer as an argument * (the type of the pointer is irrelevant) */ case 'b': /* byte -- very short int */ case 'B': /* byte as bitfield */ case 'h': /* short int */ case 'H': /* short int as bitfield */ case 'i': /* int */ case 'I': /* int sized bitfield */ case 'l': /* long int */ case 'k': /* long int sized bitfield */ case 'L': /* long long */ case 'K': /* long long sized bitfield */ case 'n': /* Py_ssize_t */ case 'f': /* float */ case 'd': /* double */ case 'D': /* complex double */ case 'c': /* char */ case 'C': /* unicode char */ case 'p': /* boolean predicate */ case 'S': /* string object */ case 'Y': /* string object */ case 'U': /* unicode string object */ { if (p_va != NULL) { (void) va_arg(*p_va, void *); } break; } /* string codes */ case 'e': /* string with encoding */ { if (p_va != NULL) { (void) va_arg(*p_va, const char *); } if (!(*format == 's' || *format == 't')) /* after 'e', only 's' and 't' is allowed */ goto err; format++; } /* fall through */ case 's': /* string */ case 'z': /* string or None */ case 'y': /* bytes */ case 'w': /* buffer, read-write */ { if (p_va != NULL) { (void) va_arg(*p_va, char **); } if (*format == '#') { if (p_va != NULL) { (void) va_arg(*p_va, Py_ssize_t *); } format++; } else if ((c == 's' || c == 'z' || c == 'y' || c == 'w') && *format == '*') { format++; } break; } case 'O': /* object */ { if (*format == '!') { format++; if (p_va != NULL) { (void) va_arg(*p_va, PyTypeObject*); (void) va_arg(*p_va, PyObject **); } } else if (*format == '&') { typedef int (*converter)(PyObject *, void *); if (p_va != NULL) { (void) va_arg(*p_va, converter); (void) va_arg(*p_va, void *); } format++; } else { if (p_va != NULL) { (void) va_arg(*p_va, PyObject **); } } break; } case '(': /* bypass tuple, not handled at all previously */ { const char *msg; for (;;) { if (*format==')') break; if (IS_END_OF_FORMAT(*format)) return "Unmatched left paren in format " "string"; msg = skipitem(&format, p_va, flags); if (msg) return msg; } format++; break; } case ')': return "Unmatched right paren in format string"; default: err: return "impossible"; } *p_format = format; return NULL; } #undef _PyArg_CheckPositional int _PyArg_CheckPositional(const char *name, Py_ssize_t nargs, Py_ssize_t min, Py_ssize_t max) { assert(min >= 0); assert(min <= max); if (nargs < min) { if (name != NULL) PyErr_Format( PyExc_TypeError, "%.200s expected %s%zd argument%s, got %zd", name, (min == max ? "" : "at least "), min, min == 1 ? "" : "s", nargs); else PyErr_Format( PyExc_TypeError, "unpacked tuple should have %s%zd element%s," " but has %zd", (min == max ? "" : "at least "), min, min == 1 ? "" : "s", nargs); return 0; } if (nargs == 0) { return 1; } if (nargs > max) { if (name != NULL) PyErr_Format( PyExc_TypeError, "%.200s expected %s%zd argument%s, got %zd", name, (min == max ? "" : "at most "), max, max == 1 ? "" : "s", nargs); else PyErr_Format( PyExc_TypeError, "unpacked tuple should have %s%zd element%s," " but has %zd", (min == max ? "" : "at most "), max, max == 1 ? "" : "s", nargs); return 0; } return 1; } static int unpack_stack(PyObject *const *args, Py_ssize_t nargs, const char *name, Py_ssize_t min, Py_ssize_t max, va_list vargs) { Py_ssize_t i; PyObject **o; if (!_PyArg_CheckPositional(name, nargs, min, max)) { return 0; } for (i = 0; i < nargs; i++) { o = va_arg(vargs, PyObject **); *o = args[i]; } return 1; } int PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...) { PyObject **stack; Py_ssize_t nargs; int retval; va_list vargs; if (!PyTuple_Check(args)) { PyErr_SetString(PyExc_SystemError, "PyArg_UnpackTuple() argument list is not a tuple"); return 0; } stack = _PyTuple_ITEMS(args); nargs = PyTuple_GET_SIZE(args); va_start(vargs, max); retval = unpack_stack(stack, nargs, name, min, max, vargs); va_end(vargs); return retval; } int _PyArg_UnpackStack(PyObject *const *args, Py_ssize_t nargs, const char *name, Py_ssize_t min, Py_ssize_t max, ...) { int retval; va_list vargs; va_start(vargs, max); retval = unpack_stack(args, nargs, name, min, max, vargs); va_end(vargs); return retval; } #undef _PyArg_NoKeywords #undef _PyArg_NoKwnames #undef _PyArg_NoPositional /* For type constructors that don't take keyword args * * Sets a TypeError and returns 0 if the args/kwargs is * not empty, returns 1 otherwise */ int _PyArg_NoKeywords(const char *funcname, PyObject *kwargs) { if (kwargs == NULL) { return 1; } if (!PyDict_CheckExact(kwargs)) { PyErr_BadInternalCall(); return 0; } if (PyDict_GET_SIZE(kwargs) == 0) { return 1; } PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", funcname); return 0; } int _PyArg_NoPositional(const char *funcname, PyObject *args) { if (args == NULL) return 1; if (!PyTuple_CheckExact(args)) { PyErr_BadInternalCall(); return 0; } if (PyTuple_GET_SIZE(args) == 0) return 1; PyErr_Format(PyExc_TypeError, "%.200s() takes no positional arguments", funcname); return 0; } int _PyArg_NoKwnames(const char *funcname, PyObject *kwnames) { if (kwnames == NULL) { return 1; } assert(PyTuple_CheckExact(kwnames)); if (PyTuple_GET_SIZE(kwnames) == 0) { return 1; } PyErr_Format(PyExc_TypeError, "%s() takes no keyword arguments", funcname); return 0; } void _PyArg_Fini(void) { struct _PyArg_Parser *tmp, *s = _PyRuntime.getargs.static_parsers; while (s) { tmp = s->next; s->next = NULL; parser_clear(s); s = tmp; } _PyRuntime.getargs.static_parsers = NULL; } #ifdef __cplusplus }; #endif ================================================ FILE: Generated_Cases.c.h ================================================ // This file is generated by Tools/cases_generator/generate_cases.py // from: // Python/bytecodes.c // Do not edit! TARGET(NOP) { DISPATCH(); } TARGET(RESUME) { #line 138 "Python/bytecodes.c" assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); /* Possibly combine this with eval breaker */ if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) { int err = _Py_Instrument(frame->f_code, tstate->interp); if (err) goto error; next_instr--; } else if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker) && oparg < 2) { goto handle_eval_breaker; } #line 24 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_RESUME) { #line 152 "Python/bytecodes.c" /* Possible performance enhancement: * We need to check the eval breaker anyway, can we * combine the instrument verison check and the eval breaker test? */ if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) { if (_Py_Instrument(frame->f_code, tstate->interp)) { goto error; } next_instr--; } else { _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation( tstate, oparg > 0, frame, next_instr-1); stack_pointer = _PyFrame_GetStackPointer(frame); if (err) goto error; if (frame->prev_instr != next_instr-1) { /* Instrumentation has jumped */ next_instr = frame->prev_instr; DISPATCH(); } if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker) && oparg < 2) { goto handle_eval_breaker; } } #line 55 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_CLOSURE) { PyObject *value; #line 180 "Python/bytecodes.c" /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); #line 66 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_FAST_CHECK) { PyObject *value; #line 187 "Python/bytecodes.c" value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); #line 78 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_FAST) { PyObject *value; #line 193 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); #line 90 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_FAST_AND_CLEAR) { PyObject *value; #line 199 "Python/bytecodes.c" value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; #line 102 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_FAST_LOAD_FAST) { PyObject *value1; PyObject *value2; #line 205 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; value1 = GETLOCAL(oparg1); value2 = GETLOCAL(oparg2); Py_INCREF(value1); Py_INCREF(value2); #line 118 "Python/generated_cases.c.h" STACK_GROW(2); stack_pointer[-1] = value2; stack_pointer[-2] = value1; DISPATCH(); } TARGET(LOAD_CONST) { PyObject *value; #line 214 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); #line 130 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); } TARGET(STORE_FAST) { PyObject *value = stack_pointer[-1]; #line 219 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 140 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_FAST_LOAD_FAST) { PyObject *value1 = stack_pointer[-1]; PyObject *value2; #line 227 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); value2 = GETLOCAL(oparg2); Py_INCREF(value2); #line 154 "Python/generated_cases.c.h" stack_pointer[-1] = value2; DISPATCH(); } TARGET(STORE_FAST_STORE_FAST) { PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; #line 235 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); SETLOCAL(oparg2, value2); #line 167 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } TARGET(POP_TOP) { PyObject *value = stack_pointer[-1]; #line 242 "Python/bytecodes.c" #line 175 "Python/generated_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); DISPATCH(); } TARGET(PUSH_NULL) { PyObject *res; #line 246 "Python/bytecodes.c" res = NULL; #line 185 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(END_FOR) { PyObject *_tmp_1 = stack_pointer[-1]; PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; #line 242 "Python/bytecodes.c" #line 197 "Python/generated_cases.c.h" Py_DECREF(value); } { PyObject *value = _tmp_2; #line 242 "Python/bytecodes.c" #line 203 "Python/generated_cases.c.h" Py_DECREF(value); } STACK_SHRINK(2); DISPATCH(); } TARGET(INSTRUMENTED_END_FOR) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; #line 252 "Python/bytecodes.c" /* Need to create a fake StopIteration error here, * to conform to PEP 380 */ if (PyGen_Check(receiver)) { PyErr_SetObject(PyExc_StopIteration, value); if (monitor_stop_iteration(tstate, frame, next_instr-1)) { goto error; } PyErr_SetRaisedException(NULL); } #line 223 "Python/generated_cases.c.h" Py_DECREF(receiver); Py_DECREF(value); STACK_SHRINK(2); DISPATCH(); } TARGET(END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; #line 265 "Python/bytecodes.c" Py_DECREF(receiver); #line 235 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; DISPATCH(); } TARGET(INSTRUMENTED_END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; #line 269 "Python/bytecodes.c" if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) { PyErr_SetObject(PyExc_StopIteration, value); if (monitor_stop_iteration(tstate, frame, next_instr-1)) { goto error; } PyErr_SetRaisedException(NULL); } Py_DECREF(receiver); #line 253 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; DISPATCH(); } TARGET(UNARY_NEGATIVE) { PyObject *value = stack_pointer[-1]; PyObject *res; #line 280 "Python/bytecodes.c" res = PyNumber_Negative(value); #line 264 "Python/generated_cases.c.h" Py_DECREF(value); #line 282 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 268 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } TARGET(UNARY_NOT) { PyObject *value = stack_pointer[-1]; PyObject *res; #line 286 "Python/bytecodes.c" int err = PyObject_IsTrue(value); #line 278 "Python/generated_cases.c.h" Py_DECREF(value); #line 288 "Python/bytecodes.c" if (err < 0) goto pop_1_error; if (err == 0) { res = Py_True; } else { res = Py_False; } #line 288 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; #line 298 "Python/bytecodes.c" res = PyNumber_Invert(value); #line 298 "Python/generated_cases.c.h" Py_DECREF(value); #line 300 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 302 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } TARGET(BINARY_OP_MULTIPLY_INT) { PyObject *_tmp_1 = stack_pointer[-1]; PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *right = _tmp_1; PyObject *left = _tmp_2; #line 316 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 316 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } { PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; #line 321 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; #line 330 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; STACK_SHRINK(1); stack_pointer[-1] = _tmp_2; DISPATCH(); } TARGET(BINARY_OP_ADD_INT) { PyObject *_tmp_1 = stack_pointer[-1]; PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *right = _tmp_1; PyObject *left = _tmp_2; #line 316 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 348 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } { PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; #line 329 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; #line 362 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; STACK_SHRINK(1); stack_pointer[-1] = _tmp_2; DISPATCH(); } TARGET(BINARY_OP_SUBTRACT_INT) { PyObject *_tmp_1 = stack_pointer[-1]; PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *right = _tmp_1; PyObject *left = _tmp_2; #line 316 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 380 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } { PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; #line 337 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; #line 394 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; STACK_SHRINK(1); stack_pointer[-1] = _tmp_2; DISPATCH(); } TARGET(BINARY_OP_MULTIPLY_FLOAT) { PyObject *_tmp_1 = stack_pointer[-1]; PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *right = _tmp_1; PyObject *left = _tmp_2; #line 352 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 412 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } { PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; #line 357 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); #line 426 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; STACK_SHRINK(1); stack_pointer[-1] = _tmp_2; DISPATCH(); } TARGET(BINARY_OP_ADD_FLOAT) { PyObject *_tmp_1 = stack_pointer[-1]; PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *right = _tmp_1; PyObject *left = _tmp_2; #line 352 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 444 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } { PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; #line 365 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); #line 458 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; STACK_SHRINK(1); stack_pointer[-1] = _tmp_2; DISPATCH(); } TARGET(BINARY_OP_SUBTRACT_FLOAT) { PyObject *_tmp_1 = stack_pointer[-1]; PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *right = _tmp_1; PyObject *left = _tmp_2; #line 352 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 476 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } { PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; #line 373 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); #line 490 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; STACK_SHRINK(1); stack_pointer[-1] = _tmp_2; DISPATCH(); } TARGET(BINARY_OP_ADD_UNICODE) { PyObject *_tmp_1 = stack_pointer[-1]; PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *right = _tmp_1; PyObject *left = _tmp_2; #line 388 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); #line 508 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } { PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; #line 393 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; #line 522 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; STACK_SHRINK(1); stack_pointer[-1] = _tmp_2; DISPATCH(); } TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { PyObject *_tmp_1 = stack_pointer[-1]; PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *right = _tmp_1; PyObject *left = _tmp_2; #line 388 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); #line 540 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } { PyObject *right = _tmp_1; PyObject *left = _tmp_2; #line 410 "Python/bytecodes.c" _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; assert(true_next.op.code == STORE_FAST); PyObject **target_local = &GETLOCAL(true_next.op.arg); DEOPT_IF(*target_local != left, BINARY_OP); STAT_INC(BINARY_OP, hit); /* Handle `left = left + right` or `left += right` for str. * * When possible, extend `left` in place rather than * allocating a new PyUnicodeObject. This attempts to avoid * quadratic behavior when one neglects to use str.join(). * * If `left` has only two references remaining (one from * the stack, one in the locals), DECREFing `left` leaves * only the locals reference, so PyUnicode_Append knows * that the string is safe to mutate. */ assert(Py_REFCNT(left) >= 2); _Py_DECREF_NO_DEALLOC(left); PyUnicode_Append(target_local, right); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (*target_local == NULL) goto pop_2_error; // The STORE_FAST is already done. JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); #line 571 "Python/generated_cases.c.h" } STACK_SHRINK(2); DISPATCH(); } TARGET(BINARY_SUBSCR) { PREDICTED(BINARY_SUBSCR); static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; #line 447 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_BinarySubscr(container, sub, next_instr); DISPATCH_SAME_OPARG(); } STAT_INC(BINARY_SUBSCR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ res = PyObject_GetItem(container, sub); #line 595 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); #line 459 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 600 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; DISPATCH(); } TARGET(BINARY_SLICE) { PyObject *stop = stack_pointer[-1]; PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; #line 463 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. if (slice == NULL) { res = NULL; } else { res = PyObject_GetItem(container, slice); Py_DECREF(slice); } Py_DECREF(container); if (res == NULL) goto pop_3_error; #line 625 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = res; DISPATCH(); } TARGET(STORE_SLICE) { PyObject *stop = stack_pointer[-1]; PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; #line 478 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { err = 1; } else { err = PyObject_SetItem(container, slice, v); Py_DECREF(slice); } Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; #line 649 "Python/generated_cases.c.h" STACK_SHRINK(4); DISPATCH(); } TARGET(BINARY_SUBSCR_LIST_INT) { PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; #line 493 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyList_Size(list) DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyList_GET_ITEM(list, index); assert(res != NULL); Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); #line 672 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; DISPATCH(); } TARGET(BINARY_SUBSCR_TUPLE_INT) { PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; #line 509 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyTuple_Size(list) DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyTuple_GET_ITEM(tuple, index); assert(res != NULL); Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); #line 697 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; DISPATCH(); } TARGET(BINARY_SUBSCR_DICT) { PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; #line 525 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); if (res == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } #line 716 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); #line 533 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub #line 723 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; DISPATCH(); } TARGET(BINARY_SUBSCR_GETITEM) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; #line 540 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; PyObject *cached = ht->_spec_cache.getitem; DEOPT_IF(cached == NULL, BINARY_SUBSCR); assert(PyFunction_Check(cached)); PyFunctionObject *getitem = (PyFunctionObject *)cached; uint32_t cached_version = ht->_spec_cache.getitem_version; DEOPT_IF(getitem->func_version != cached_version, BINARY_SUBSCR); PyCodeObject *code = (PyCodeObject *)getitem->func_code; assert(code->co_argcount == 2); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); Py_INCREF(getitem); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, getitem, 2); STACK_SHRINK(2); new_frame->localsplus[0] = container; new_frame->localsplus[1] = sub; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); #line 758 "Python/generated_cases.c.h" } TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; #line 565 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; #line 766 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; #line 569 "Python/bytecodes.c" int err = PySet_Add(set, v); #line 776 "Python/generated_cases.c.h" Py_DECREF(v); #line 571 "Python/bytecodes.c" if (err) goto pop_1_error; #line 780 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_SUBSCR) { PREDICTED(STORE_SUBSCR); static_assert(INLINE_CACHE_ENTRIES_STORE_SUBSCR == 1, "incorrect cache size"); PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); #line 581 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; _Py_Specialize_StoreSubscr(container, sub, next_instr); DISPATCH_SAME_OPARG(); } STAT_INC(STORE_SUBSCR, deferred); _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); #else (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); #line 807 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); #line 596 "Python/bytecodes.c" if (err) goto pop_3_error; #line 813 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); } TARGET(STORE_SUBSCR_LIST_INT) { PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; #line 600 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); // Ensure nonnegative, zero-or-one-digit ints. DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), STORE_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; // Ensure index < len(list) DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); PyObject *old_value = PyList_GET_ITEM(list, index); PyList_SET_ITEM(list, index, value); assert(old_value != NULL); Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); #line 840 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); } TARGET(STORE_SUBSCR_DICT) { PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; #line 619 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; #line 856 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); } TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; #line 627 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); #line 868 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); #line 630 "Python/bytecodes.c" if (err) goto pop_2_error; #line 873 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; #line 634 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); #line 884 "Python/generated_cases.c.h" Py_DECREF(value); #line 637 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 888 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } TARGET(CALL_INTRINSIC_2) { PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; #line 641 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); #line 900 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); #line 644 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 905 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); #line 648 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: cause = args[1]; /* fall through */ case 1: exc = args[0]; /* fall through */ case 0: if (do_raise(tstate, exc, cause)) { STACK_SHRINK(oparg); goto exception_unwind; } break; default: _PyErr_SetString(tstate, PyExc_SystemError, "bad RAISE_VARARGS oparg"); break; } if (true) { STACK_SHRINK(oparg); goto error; } #line 931 "Python/generated_cases.c.h" } TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; #line 668 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() assert(EMPTY()); /* Restore previous cframe and return. */ tstate->cframe = cframe.previous; assert(tstate->cframe->current_frame == frame->previous); assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); return retval; #line 947 "Python/generated_cases.c.h" } TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; #line 681 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); _Py_LeaveRecursiveCallPy(tstate); assert(frame != &entry_frame); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; #line 965 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; #line 696 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); if (err) goto error; STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); _Py_LeaveRecursiveCallPy(tstate); assert(frame != &entry_frame); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; #line 987 "Python/generated_cases.c.h" } TARGET(RETURN_CONST) { #line 715 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); _Py_LeaveRecursiveCallPy(tstate); assert(frame != &entry_frame); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; #line 1005 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_CONST) { #line 731 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); if (err) goto error; Py_INCREF(retval); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); _Py_LeaveRecursiveCallPy(tstate); assert(frame != &entry_frame); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; frame = cframe.current_frame = dying->previous; _PyEvalFrameClearAndPop(tstate, dying); frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; #line 1027 "Python/generated_cases.c.h" } TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; #line 751 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); if (type->tp_as_async != NULL) { getter = type->tp_as_async->am_aiter; } if (getter == NULL) { _PyErr_Format(tstate, PyExc_TypeError, "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); #line 1046 "Python/generated_cases.c.h" Py_DECREF(obj); #line 764 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); #line 1053 "Python/generated_cases.c.h" Py_DECREF(obj); #line 769 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || Py_TYPE(iter)->tp_as_async->am_anext == NULL) { _PyErr_Format(tstate, PyExc_TypeError, "'async for' received an object from __aiter__ " "that does not implement __anext__: %.100s", Py_TYPE(iter)->tp_name); Py_DECREF(iter); if (true) goto pop_1_error; } #line 1068 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; #line 784 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); if (PyAsyncGen_CheckExact(aiter)) { awaitable = type->tp_as_async->am_anext(aiter); if (awaitable == NULL) { goto error; } } else { if (type->tp_as_async != NULL){ getter = type->tp_as_async->am_anext; } if (getter != NULL) { next_iter = (*getter)(aiter); if (next_iter == NULL) { goto error; } } else { _PyErr_Format(tstate, PyExc_TypeError, "'async for' requires an iterator with " "__anext__ method, got %.100s", type->tp_name); goto error; } awaitable = _PyCoro_GetAwaitableIter(next_iter); if (awaitable == NULL) { _PyErr_FormatFromCause( PyExc_TypeError, "'async for' received an invalid object " "from __anext__: %.100s", Py_TYPE(next_iter)->tp_name); Py_DECREF(next_iter); goto error; } else { Py_DECREF(next_iter); } } #line 1119 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; DISPATCH(); } TARGET(GET_AWAITABLE) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; #line 829 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } #line 1135 "Python/generated_cases.c.h" Py_DECREF(iterable); #line 836 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); if (yf != NULL) { /* `iter` is a coroutine object that is being awaited, `yf` is a pointer to the current awaitable being awaited on. */ Py_DECREF(yf); Py_CLEAR(iter); _PyErr_SetString(tstate, PyExc_RuntimeError, "coroutine is being awaited already"); /* The code below jumps to `error` if `iter` is NULL. */ } } if (iter == NULL) goto pop_1_error; #line 1154 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } TARGET(SEND) { PREDICTED(SEND); static_assert(INLINE_CACHE_ENTRIES_SEND == 1, "incorrect cache size"); PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; #line 860 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_Send(receiver, next_instr); DISPATCH_SAME_OPARG(); } STAT_INC(SEND, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ assert(frame != &entry_frame); if ((tstate->interp->eval_frame == NULL) && (Py_TYPE(receiver) == &PyGen_Type || Py_TYPE(receiver) == &PyCoro_Type) && ((PyGenObject *)receiver)->gi_frame_state < FRAME_EXECUTING) { PyGenObject *gen = (PyGenObject *)receiver; _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; frame->return_offset = oparg; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); } if (Py_IsNone(v) && PyIter_Check(receiver)) { retval = Py_TYPE(receiver)->tp_iternext(receiver); } else { retval = PyObject_CallMethodOneArg(receiver, &_Py_ID(send), v); } if (retval == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_StopIteration) ) { monitor_raise(tstate, frame, next_instr-1); } if (_PyGen_FetchStopIterationValue(&retval) == 0) { assert(retval != NULL); JUMPBY(oparg); } else { goto error; } } Py_DECREF(v); #line 1212 "Python/generated_cases.c.h" stack_pointer[-1] = retval; next_instr += 1; DISPATCH(); } TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; #line 909 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND); STAT_INC(SEND, hit); _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; frame->return_offset = oparg; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); #line 1237 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; #line 927 "Python/bytecodes.c" assert(frame != &entry_frame); PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; _PyFrame_SetStackPointer(frame, stack_pointer - 1); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_YIELD, frame, next_instr-1, retval); if (err) goto error; tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *gen_frame = frame; frame = cframe.current_frame = frame->previous; gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; #line 1259 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; #line 946 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. assert(frame != &entry_frame); PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; _PyFrame_SetStackPointer(frame, stack_pointer - 1); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; _Py_LeaveRecursiveCallPy(tstate); _PyInterpreterFrame *gen_frame = frame; frame = cframe.current_frame = frame->previous; gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; #line 1280 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; #line 964 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); #line 1288 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); #line 969 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; if (PyLong_Check(lasti)) { frame->prev_instr = _PyCode_CODE(frame->f_code) + PyLong_AsLong(lasti); assert(!_PyErr_Occurred(tstate)); } else { assert(PyLong_Check(lasti)); _PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int"); goto error; } } assert(exc && PyExceptionInstance_Check(exc)); Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; #line 1314 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; #line 989 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { #line 1323 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); #line 992 "Python/bytecodes.c" } else { Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } #line 1333 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } TARGET(CLEANUP_THROW) { PyObject *exc_value = stack_pointer[-1]; PyObject *last_sent_val = stack_pointer[-2]; PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; #line 1001 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); #line 1349 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); #line 1006 "Python/bytecodes.c" none = Py_None; } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } #line 1360 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; DISPATCH(); } TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; #line 1015 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); #line 1371 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_BUILD_CLASS) { PyObject *bc; #line 1019 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); if (bc == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_SetString(tstate, PyExc_NameError, "__build_class__ not found"); } if (true) goto error; } Py_INCREF(bc); } else { bc = PyObject_GetItem(BUILTINS(), &_Py_ID(__build_class__)); if (bc == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) _PyErr_SetString(tstate, PyExc_NameError, "__build_class__ not found"); if (true) goto error; } } #line 1401 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); } TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; #line 1044 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); #line 1416 "Python/generated_cases.c.h" Py_DECREF(v); #line 1051 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); #line 1425 "Python/generated_cases.c.h" Py_DECREF(v); #line 1058 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1429 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { #line 1062 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals when deleting %R", name); goto error; } err = PyObject_DelItem(ns, name); // Can't use ERROR_IF here. if (err != 0) { format_exc_check_arg(tstate, PyExc_NameError, NAME_ERROR_MSG, name); goto error; } #line 1452 "Python/generated_cases.c.h" DISPATCH(); } TARGET(UNPACK_SEQUENCE) { PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; #line 1088 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_UnpackSequence(seq, next_instr, oparg); DISPATCH_SAME_OPARG(); } STAT_INC(UNPACK_SEQUENCE, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); #line 1473 "Python/generated_cases.c.h" Py_DECREF(seq); #line 1101 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1477 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; DISPATCH(); } TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); #line 1105 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); #line 1494 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; DISPATCH(); } TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); #line 1115 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); PyObject **items = _PyTuple_ITEMS(seq); for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } #line 1513 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; DISPATCH(); } TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); #line 1126 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); PyObject **items = _PyList_ITEMS(seq); for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } #line 1532 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; DISPATCH(); } TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; #line 1137 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); #line 1546 "Python/generated_cases.c.h" Py_DECREF(seq); #line 1141 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1550 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } TARGET(STORE_ATTR) { PREDICTED(STORE_ATTR); static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); #line 1152 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); next_instr--; _Py_Specialize_StoreAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); } STAT_INC(STORE_ATTR, deferred); _PyAttrCache *cache = (_PyAttrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); #else (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); #line 1577 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); #line 1168 "Python/bytecodes.c" if (err) goto pop_2_error; #line 1582 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); } TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; #line 1172 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); #line 1593 "Python/generated_cases.c.h" Py_DECREF(owner); #line 1175 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1597 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; #line 1179 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); #line 1607 "Python/generated_cases.c.h" Py_DECREF(v); #line 1182 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1611 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { #line 1186 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); // Can't use ERROR_IF here. if (err != 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { format_exc_check_arg(tstate, PyExc_NameError, NAME_ERROR_MSG, name); } goto error; } #line 1629 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_LOCALS) { PyObject *_tmp_1; { PyObject *locals; #line 1200 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, "no locals found"); if (true) goto error; } Py_INCREF(locals); #line 1645 "Python/generated_cases.c.h" _tmp_1 = locals; } STACK_GROW(1); stack_pointer[-1] = _tmp_1; DISPATCH(); } TARGET(LOAD_NAME) { PyObject *_tmp_1; { PyObject *locals; #line 1200 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, "no locals found"); if (true) goto error; } Py_INCREF(locals); #line 1665 "Python/generated_cases.c.h" _tmp_1 = locals; } { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; #line 1212 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); if (v != NULL) { Py_INCREF(v); } else if (_PyErr_Occurred(tstate)) { Py_DECREF(mod_or_class_dict); goto error; } } else { v = PyObject_GetItem(mod_or_class_dict, name); if (v == NULL) { if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { Py_DECREF(mod_or_class_dict); goto error; } _PyErr_Clear(tstate); } } Py_DECREF(mod_or_class_dict); if (v == NULL) { v = PyDict_GetItemWithError(GLOBALS(), name); if (v != NULL) { Py_INCREF(v); } else if (_PyErr_Occurred(tstate)) { goto error; } else { if (PyDict_CheckExact(BUILTINS())) { v = PyDict_GetItemWithError(BUILTINS(), name); if (v == NULL) { if (!_PyErr_Occurred(tstate)) { format_exc_check_arg( tstate, PyExc_NameError, NAME_ERROR_MSG, name); } goto error; } Py_INCREF(v); } else { v = PyObject_GetItem(BUILTINS(), name); if (v == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { format_exc_check_arg( tstate, PyExc_NameError, NAME_ERROR_MSG, name); } goto error; } } } } #line 1728 "Python/generated_cases.c.h" _tmp_1 = v; } STACK_GROW(1); stack_pointer[-1] = _tmp_1; DISPATCH(); } TARGET(LOAD_FROM_DICT_OR_GLOBALS) { PyObject *_tmp_1 = stack_pointer[-1]; { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; #line 1212 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); if (v != NULL) { Py_INCREF(v); } else if (_PyErr_Occurred(tstate)) { Py_DECREF(mod_or_class_dict); goto error; } } else { v = PyObject_GetItem(mod_or_class_dict, name); if (v == NULL) { if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { Py_DECREF(mod_or_class_dict); goto error; } _PyErr_Clear(tstate); } } Py_DECREF(mod_or_class_dict); if (v == NULL) { v = PyDict_GetItemWithError(GLOBALS(), name); if (v != NULL) { Py_INCREF(v); } else if (_PyErr_Occurred(tstate)) { goto error; } else { if (PyDict_CheckExact(BUILTINS())) { v = PyDict_GetItemWithError(BUILTINS(), name); if (v == NULL) { if (!_PyErr_Occurred(tstate)) { format_exc_check_arg( tstate, PyExc_NameError, NAME_ERROR_MSG, name); } goto error; } Py_INCREF(v); } else { v = PyObject_GetItem(BUILTINS(), name); if (v == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { format_exc_check_arg( tstate, PyExc_NameError, NAME_ERROR_MSG, name); } goto error; } } } } #line 1798 "Python/generated_cases.c.h" _tmp_1 = v; } stack_pointer[-1] = _tmp_1; DISPATCH(); } TARGET(LOAD_GLOBAL) { PREDICTED(LOAD_GLOBAL); static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; #line 1281 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name); DISPATCH_SAME_OPARG(); } STAT_INC(LOAD_GLOBAL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); if (PyDict_CheckExact(GLOBALS()) && PyDict_CheckExact(BUILTINS())) { v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), (PyDictObject *)BUILTINS(), name); if (v == NULL) { if (!_PyErr_Occurred(tstate)) { /* _PyDict_LoadGlobal() returns NULL without raising * an exception if the key doesn't exist */ format_exc_check_arg(tstate, PyExc_NameError, NAME_ERROR_MSG, name); } if (true) goto error; } Py_INCREF(v); } else { /* Slow-path if globals or builtins is not a dict */ /* namespace 1: globals */ v = PyObject_GetItem(GLOBALS(), name); if (v == NULL) { if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) goto error; _PyErr_Clear(tstate); /* namespace 2: builtins */ v = PyObject_GetItem(BUILTINS(), name); if (v == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { format_exc_check_arg( tstate, PyExc_NameError, NAME_ERROR_MSG, name); } if (true) goto error; } } } null = NULL; #line 1862 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = null; } next_instr += 4; DISPATCH(); } TARGET(LOAD_GLOBAL_MODULE) { PyObject *null = NULL; PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); #line 1335 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); assert(DK_IS_UNICODE(dict->ma_keys)); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); res = entries[index].me_value; DEOPT_IF(res == NULL, LOAD_GLOBAL); Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; #line 1887 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = null; } next_instr += 4; DISPATCH(); } TARGET(LOAD_GLOBAL_BUILTIN) { PyObject *null = NULL; PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); #line 1348 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); PyDictObject *bdict = (PyDictObject *)BUILTINS(); assert(opcode == LOAD_GLOBAL_BUILTIN); DEOPT_IF(mdict->ma_keys->dk_version != mod_version, LOAD_GLOBAL); DEOPT_IF(bdict->ma_keys->dk_version != bltn_version, LOAD_GLOBAL); assert(DK_IS_UNICODE(bdict->ma_keys)); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); res = entries[index].me_value; DEOPT_IF(res == NULL, LOAD_GLOBAL); Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; #line 1917 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = null; } next_instr += 4; DISPATCH(); } TARGET(DELETE_FAST) { #line 1365 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); #line 1931 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { #line 1371 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); PyObject *cell = PyCell_New(initial); if (cell == NULL) { goto resume_with_error; } SETLOCAL(oparg, cell); #line 1945 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { #line 1382 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. // Fortunately we don't need its superpower. if (oldobj == NULL) { format_exc_unbound(tstate, frame->f_code, oparg); goto error; } PyCell_SET(cell, NULL); Py_DECREF(oldobj); #line 1961 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; #line 1395 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); name = PyTuple_GET_ITEM(frame->f_code->co_localsplusnames, oparg); if (PyDict_CheckExact(class_dict)) { value = PyDict_GetItemWithError(class_dict, name); if (value != NULL) { Py_INCREF(value); } else if (_PyErr_Occurred(tstate)) { Py_DECREF(class_dict); goto error; } } else { value = PyObject_GetItem(class_dict, name); if (value == NULL) { if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { Py_DECREF(class_dict); goto error; } _PyErr_Clear(tstate); } } Py_DECREF(class_dict); if (!value) { PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { format_exc_unbound(tstate, frame->f_code, oparg); goto error; } Py_INCREF(value); } #line 2003 "Python/generated_cases.c.h" stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_DEREF) { PyObject *value; #line 1432 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { format_exc_unbound(tstate, frame->f_code, oparg); if (true) goto error; } Py_INCREF(value); #line 2018 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); } TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; #line 1442 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); #line 2031 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { #line 1449 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure; assert(oparg == co->co_nfreevars); int offset = co->co_nlocalsplus - oparg; for (int i = 0; i < oparg; ++i) { PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } #line 2048 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; #line 1462 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); #line 2057 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } #line 1464 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } #line 2063 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; DISPATCH(); } TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; #line 1468 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } #line 2076 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; DISPATCH(); } TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; #line 1473 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } #line 2089 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; DISPATCH(); } TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; #line 1478 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && (Py_TYPE(iterable)->tp_iter == NULL && !PySequence_Check(iterable))) { _PyErr_Clear(tstate); _PyErr_Format(tstate, PyExc_TypeError, "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } #line 2110 "Python/generated_cases.c.h" Py_DECREF(iterable); #line 1489 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); #line 2116 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); } TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; #line 1496 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); #line 2127 "Python/generated_cases.c.h" Py_DECREF(iterable); #line 1498 "Python/bytecodes.c" if (err < 0) goto pop_1_error; #line 2131 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; #line 1502 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; int err = 0; for (int i = 0; i < oparg; i++) { PyObject *item = values[i]; if (err == 0) err = PySet_Add(set, item); Py_DECREF(item); } if (err != 0) { Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } #line 2154 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; DISPATCH(); } TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; #line 1519 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, oparg); if (map == NULL) goto error; #line 2172 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } #line 1527 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } #line 2178 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; DISPATCH(); } TARGET(SETUP_ANNOTATIONS) { #line 1531 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when setting up annotations"); if (true) goto error; } /* check if __annotations__ in locals()... */ if (PyDict_CheckExact(LOCALS())) { ann_dict = _PyDict_GetItemWithError(LOCALS(), &_Py_ID(__annotations__)); if (ann_dict == NULL) { if (_PyErr_Occurred(tstate)) goto error; /* ...if not, create a new one */ ann_dict = PyDict_New(); if (ann_dict == NULL) goto error; err = PyDict_SetItem(LOCALS(), &_Py_ID(__annotations__), ann_dict); Py_DECREF(ann_dict); if (err) goto error; } } else { /* do the same if locals() is not a dict */ ann_dict = PyObject_GetItem(LOCALS(), &_Py_ID(__annotations__)); if (ann_dict == NULL) { if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) goto error; _PyErr_Clear(tstate); ann_dict = PyDict_New(); if (ann_dict == NULL) goto error; err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__), ann_dict); Py_DECREF(ann_dict); if (err) goto error; } else { Py_DECREF(ann_dict); } } #line 2226 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_CONST_KEY_MAP) { PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; #line 1573 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, "bad BUILD_CONST_KEY_MAP keys argument"); goto error; // Pop the keys and values. } map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); #line 2244 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); #line 1583 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } #line 2251 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); } TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; #line 1587 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { _PyErr_Format(tstate, PyExc_TypeError, "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } #line 2267 "Python/generated_cases.c.h" Py_DECREF(update); #line 1595 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 2272 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); } TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; #line 1601 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); #line 2285 "Python/generated_cases.c.h" Py_DECREF(update); #line 1606 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 2290 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); } TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; #line 1612 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; #line 2305 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { #line 1620 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); #line 2317 "Python/generated_cases.c.h" } TARGET(LOAD_SUPER_ATTR) { PREDICTED(LOAD_SUPER_ATTR); static_assert(INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR == 1, "incorrect cache size"); PyObject *self = stack_pointer[-1]; PyObject *class = stack_pointer[-2]; PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; #line 1634 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_LoadSuperAttr(global_super, class, next_instr, load_method); DISPATCH_SAME_OPARG(); } STAT_INC(LOAD_SUPER_ATTR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, next_instr-1, global_super, arg); if (err) goto pop_3_error; } // we make no attempt to optimize here; specializations should // handle any case whose performance we care about PyObject *stack[] = {class, self}; PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL); if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; if (super == NULL) { _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, frame, next_instr-1, global_super, arg); } else { int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_C_RETURN, frame, next_instr-1, global_super, arg); if (err < 0) { Py_CLEAR(super); } } } #line 2370 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); #line 1676 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; #line 2379 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } next_instr += 1; DISPATCH(); } TARGET(LOAD_SUPER_ATTR_ATTR) { PyObject *self = stack_pointer[-1]; PyObject *class = stack_pointer[-2]; PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; #line 1695 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); #line 2401 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); #line 1702 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; #line 2407 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } next_instr += 1; DISPATCH(); } TARGET(LOAD_SUPER_ATTR_METHOD) { PyObject *self = stack_pointer[-1]; PyObject *class = stack_pointer[-2]; PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; #line 1706 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); PyTypeObject *cls = (PyTypeObject *)class; int method_found = 0; res2 = _PySuper_Lookup(cls, self, name, cls->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); Py_DECREF(global_super); Py_DECREF(class); if (res2 == NULL) { Py_DECREF(self); if (true) goto pop_3_error; } if (method_found) { res = self; // transfer ownership } else { Py_DECREF(self); res = res2; res2 = NULL; } #line 2445 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; next_instr += 1; DISPATCH(); } TARGET(LOAD_ATTR) { PREDICTED(LOAD_ATTR); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; #line 1745 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); } STAT_INC(LOAD_ATTR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); if (oparg & 1) { /* Designed to work in tandem with CALL, pushes two values. */ PyObject* meth = NULL; if (_PyObject_GetMethod(owner, name, &meth)) { /* We can bypass temporary bound method object. meth is unbound method and obj is self. meth | self | arg1 | ... | argN */ assert(meth != NULL); // No errors on this branch res2 = meth; res = owner; // Transfer ownership } else { /* meth is not an unbound method (but a regular attr, or something was returned by a descriptor protocol). Set the second element of the stack to NULL, to signal CALL that it's not a method call. NULL | meth | arg1 | ... | argN */ #line 2493 "Python/generated_cases.c.h" Py_DECREF(owner); #line 1779 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; } } else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); #line 2504 "Python/generated_cases.c.h" Py_DECREF(owner); #line 1788 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } #line 2509 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_INSTANCE_VALUE) { PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); #line 1797 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); assert(tp->tp_dictoffset < 0); assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); res = _PyDictOrValues_GetValues(dorv)->values[index]; DEOPT_IF(res == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; #line 2536 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_MODULE) { PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); #line 1813 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); DEOPT_IF(dict->ma_keys->dk_version != type_version, LOAD_ATTR); assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); assert(index < dict->ma_keys->dk_nentries); PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + index; res = ep->me_value; DEOPT_IF(res == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; #line 2564 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_WITH_HINT) { PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); #line 1829 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(_PyDictOrValues_IsValues(dorv), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, LOAD_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); uint16_t hint = index; DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, LOAD_ATTR); if (DK_IS_UNICODE(dict->ma_keys)) { PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; DEOPT_IF(ep->me_key != name, LOAD_ATTR); res = ep->me_value; } else { PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint; DEOPT_IF(ep->me_key != name, LOAD_ATTR); res = ep->me_value; } DEOPT_IF(res == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; #line 2606 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_SLOT) { PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); #line 1859 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); char *addr = (char *)owner + index; res = *(PyObject **)addr; DEOPT_IF(res == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; #line 2631 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_CLASS) { PyObject *cls = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); #line 1872 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, LOAD_ATTR); assert(type_version != 0); STAT_INC(LOAD_ATTR, hit); res2 = NULL; res = descr; assert(res != NULL); Py_INCREF(res); #line 2658 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_PROPERTY) { PyObject *owner = stack_pointer[-1]; uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); #line 1887 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); assert(type_version != 0); assert(Py_IS_TYPE(fget, &PyFunction_Type)); PyFunctionObject *f = (PyFunctionObject *)fget; assert(func_version != 0); DEOPT_IF(f->func_version != func_version, LOAD_ATTR); PyCodeObject *code = (PyCodeObject *)f->func_code; assert(code->co_argcount == 1); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); Py_INCREF(fget); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 1); // Manipulate stack directly because we exit with DISPATCH_INLINED(). SET_TOP(NULL); int shrink_stack = !(oparg & 1); STACK_SHRINK(shrink_stack); new_frame->localsplus[0] = owner; JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); #line 2696 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { PyObject *owner = stack_pointer[-1]; uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); #line 1913 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); assert(type_version != 0); assert(Py_IS_TYPE(getattribute, &PyFunction_Type)); PyFunctionObject *f = (PyFunctionObject *)getattribute; assert(func_version != 0); DEOPT_IF(f->func_version != func_version, LOAD_ATTR); PyCodeObject *code = (PyCodeObject *)f->func_code; assert(code->co_argcount == 2); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); Py_INCREF(f); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2); // Manipulate stack directly because we exit with DISPATCH_INLINED(). SET_TOP(NULL); int shrink_stack = !(oparg & 1); STACK_SHRINK(shrink_stack); new_frame->localsplus[0] = owner; new_frame->localsplus[1] = Py_NewRef(name); JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); #line 2730 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { PyObject *owner = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); #line 1941 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR); STAT_INC(STORE_ATTR, hit); PyDictValues *values = _PyDictOrValues_GetValues(dorv); PyObject *old_value = values->values[index]; values->values[index] = value; if (old_value == NULL) { _PyDictValues_AddToInsertionOrder(values, index); } else { Py_DECREF(old_value); } Py_DECREF(owner); #line 2756 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); } TARGET(STORE_ATTR_WITH_HINT) { PyObject *owner = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); #line 1961 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(_PyDictOrValues_IsValues(dorv), STORE_ATTR); PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, STORE_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); PyObject *name = GETITEM(frame->f_code->co_names, oparg); DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR); PyObject *old_value; uint64_t new_version; if (DK_IS_UNICODE(dict->ma_keys)) { PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; DEOPT_IF(ep->me_key != name, STORE_ATTR); old_value = ep->me_value; DEOPT_IF(old_value == NULL, STORE_ATTR); new_version = _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, value); ep->me_value = value; } else { PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint; DEOPT_IF(ep->me_key != name, STORE_ATTR); old_value = ep->me_value; DEOPT_IF(old_value == NULL, STORE_ATTR); new_version = _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, value); ep->me_value = value; } Py_DECREF(old_value); STAT_INC(STORE_ATTR, hit); /* Ensure dict is GC tracked if it needs to be */ if (!_PyObject_GC_IS_TRACKED(dict) && _PyObject_GC_MAY_BE_TRACKED(value)) { _PyObject_GC_TRACK(dict); } /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); #line 2806 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); } TARGET(STORE_ATTR_SLOT) { PyObject *owner = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); #line 2002 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); char *addr = (char *)owner + index; STAT_INC(STORE_ATTR, hit); PyObject *old_value = *(PyObject **)addr; *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); #line 2827 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); } TARGET(COMPARE_OP) { PREDICTED(COMPARE_OP); static_assert(INLINE_CACHE_ENTRIES_COMPARE_OP == 1, "incorrect cache size"); PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; #line 2021 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_CompareOp(left, right, next_instr, oparg); DISPATCH_SAME_OPARG(); } STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); #line 2852 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 2034 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 2857 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; DISPATCH(); } TARGET(COMPARE_OP_FLOAT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; #line 2038 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); double dleft = PyFloat_AS_DOUBLE(left); double dright = PyFloat_AS_DOUBLE(right); // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg int sign_ish = COMPARISON_BIT(dleft, dright); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; #line 2879 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; DISPATCH(); } TARGET(COMPARE_OP_INT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; #line 2052 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && _PyLong_DigitCount((PyLongObject *)right) <= 1); Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left); Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; #line 2905 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; DISPATCH(); } TARGET(COMPARE_OP_STR) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; #line 2070 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); int eq = _PyUnicode_Equal(left, right); assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); assert(eq == 0 || eq == 1); assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; #line 2928 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; DISPATCH(); } TARGET(IS_OP) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; #line 2084 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; #line 2941 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 2086 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 2946 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); } TARGET(CONTAINS_OP) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; #line 2090 "Python/bytecodes.c" int res = PySequence_Contains(right, left); #line 2958 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 2092 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; #line 2964 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); } TARGET(CHECK_EG_MATCH) { PyObject *match_type = stack_pointer[-1]; PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; #line 2097 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { #line 2977 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); #line 2099 "Python/bytecodes.c" if (true) goto pop_2_error; } match = NULL; rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); #line 2988 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); #line 2107 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); if (match == NULL) goto pop_2_error; if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } #line 3000 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); } TARGET(CHECK_EXC_MATCH) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; #line 2118 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { #line 3013 "Python/generated_cases.c.h" Py_DECREF(right); #line 2121 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); #line 3020 "Python/generated_cases.c.h" Py_DECREF(right); #line 2126 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 3024 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } TARGET(IMPORT_NAME) { PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; #line 2130 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); #line 3036 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); #line 2133 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 3041 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; #line 2137 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; #line 3054 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { #line 2143 "Python/bytecodes.c" JUMPBY(oparg); #line 3063 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { #line 2147 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); JUMPBY(1-oparg); #if ENABLE_SPECIALIZATION here[1].cache += (1 << OPTIMIZER_BITS_IN_COUNTER); if (here[1].cache > tstate->interp->optimizer_backedge_threshold) { OBJECT_STAT_INC(optimization_attempts); frame = _PyOptimizer_BackEdge(frame, here, next_instr, stack_pointer); if (frame == NULL) { frame = cframe.current_frame; goto error; } here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) -1); goto resume_frame; } #endif /* ENABLE_SPECIALIZATION */ #line 3085 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(ENTER_EXECUTOR) { #line 2177 "Python/bytecodes.c" _PyExecutorObject *executor = (_PyExecutorObject *)frame->f_code->co_executors->executors[oparg]; Py_INCREF(executor); frame = executor->execute(executor, frame, stack_pointer); if (frame == NULL) { frame = cframe.current_frame; goto error; } goto resume_frame; #line 3100 "Python/generated_cases.c.h" } TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; #line 2188 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); #line 3111 "Python/generated_cases.c.h" Py_DECREF(cond); #line 2194 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } else { if (err < 0) goto pop_1_error; } } #line 3121 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; #line 2204 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); #line 3134 "Python/generated_cases.c.h" Py_DECREF(cond); #line 2210 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } else { if (err < 0) goto pop_1_error; } } #line 3144 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; #line 2220 "Python/bytecodes.c" if (!Py_IsNone(value)) { #line 3153 "Python/generated_cases.c.h" Py_DECREF(value); #line 2222 "Python/bytecodes.c" JUMPBY(oparg); } #line 3158 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; #line 2227 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { #line 3170 "Python/generated_cases.c.h" Py_DECREF(value); #line 2232 "Python/bytecodes.c" } #line 3174 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { #line 2236 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); #line 3187 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; #line 2245 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; #line 3200 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); } TARGET(MATCH_CLASS) { PyObject *names = stack_pointer[-1]; PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; #line 2253 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); #line 3216 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); #line 2258 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } else { if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } #line 3228 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); } TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; #line 2268 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; #line 3240 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; #line 2273 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; #line 3252 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(MATCH_KEYS) { PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; #line 2278 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; #line 3266 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); } TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; #line 2284 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); #line 3278 "Python/generated_cases.c.h" Py_DECREF(iterable); #line 2287 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; #line 3282 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; #line 2291 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ if (!(frame->f_code->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) { /* and it is used in a 'yield from' expression of a regular generator. */ _PyErr_SetString(tstate, PyExc_TypeError, "cannot 'yield from' a coroutine object " "in a non-coroutine generator"); goto error; } iter = iterable; } else if (PyGen_CheckExact(iterable)) { iter = iterable; } else { /* `iterable` is not a generator. */ iter = PyObject_GetIter(iterable); if (iter == NULL) { goto error; } #line 3313 "Python/generated_cases.c.h" Py_DECREF(iterable); #line 2314 "Python/bytecodes.c" } #line 3317 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } TARGET(FOR_ITER) { PREDICTED(FOR_ITER); static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; #line 2332 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_ForIter(iter, next_instr, oparg); DISPATCH_SAME_OPARG(); } STAT_INC(FOR_ITER, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next == NULL) { if (_PyErr_Occurred(tstate)) { if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { goto error; } monitor_raise(tstate, frame, next_instr-1); _PyErr_Clear(tstate); } /* iterator ended normally */ assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR || next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == INSTRUMENTED_END_FOR); Py_DECREF(iter); STACK_SHRINK(1); /* Jump forward oparg, then skip following END_FOR instruction */ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); DISPATCH(); } // Common case: no jump, leave it to the code generator #line 3358 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; DISPATCH(); } TARGET(INSTRUMENTED_FOR_ITER) { #line 2365 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next != NULL) { PUSH(next); target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER; } else { if (_PyErr_Occurred(tstate)) { if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { goto error; } monitor_raise(tstate, frame, here); _PyErr_Clear(tstate); } /* iterator ended normally */ assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR || next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == INSTRUMENTED_END_FOR); STACK_SHRINK(1); Py_DECREF(iter); /* Skip END_FOR */ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); #line 3392 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; #line 2393 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); PyListObject *seq = it->it_seq; if (seq) { if (it->it_index < PyList_GET_SIZE(seq)) { next = Py_NewRef(PyList_GET_ITEM(seq, it->it_index++)); goto end_for_iter_list; // End of this instruction } it->it_seq = NULL; Py_DECREF(seq); } Py_DECREF(iter); STACK_SHRINK(1); /* Jump forward oparg, then skip following END_FOR instruction */ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator #line 3419 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; DISPATCH(); } TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; #line 2415 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); PyTupleObject *seq = it->it_seq; if (seq) { if (it->it_index < PyTuple_GET_SIZE(seq)) { next = Py_NewRef(PyTuple_GET_ITEM(seq, it->it_index++)); goto end_for_iter_tuple; // End of this instruction } it->it_seq = NULL; Py_DECREF(seq); } Py_DECREF(iter); STACK_SHRINK(1); /* Jump forward oparg, then skip following END_FOR instruction */ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator #line 3449 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; DISPATCH(); } TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; #line 2437 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); if (r->len <= 0) { STACK_SHRINK(1); Py_DECREF(r); // Jump over END_FOR instruction. JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); DISPATCH(); } long value = r->start; r->start = value + r->step; r->len--; next = PyLong_FromLong(value); if (next == NULL) { goto error; } #line 3477 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; DISPATCH(); } TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; #line 2457 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); STAT_INC(FOR_ITER, hit); _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; frame->return_offset = oparg; _PyFrame_StackPush(gen_frame, Py_None); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); #line 3502 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; #line 2475 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_Format(tstate, PyExc_TypeError, "'%.200s' object does not support the " "asynchronous context manager protocol", Py_TYPE(mgr)->tp_name); } goto error; } exit = _PyObject_LookupSpecial(mgr, &_Py_ID(__aexit__)); if (exit == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_Format(tstate, PyExc_TypeError, "'%.200s' object does not support the " "asynchronous context manager protocol " "(missed __aexit__ method)", Py_TYPE(mgr)->tp_name); } Py_DECREF(enter); goto error; } #line 3532 "Python/generated_cases.c.h" Py_DECREF(mgr); #line 2498 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } #line 3541 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; DISPATCH(); } TARGET(BEFORE_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; #line 2507 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__enter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_Format(tstate, PyExc_TypeError, "'%.200s' object does not support the " "context manager protocol", Py_TYPE(mgr)->tp_name); } goto error; } exit = _PyObject_LookupSpecial(mgr, &_Py_ID(__exit__)); if (exit == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_Format(tstate, PyExc_TypeError, "'%.200s' object does not support the " "context manager protocol " "(missed __exit__ method)", Py_TYPE(mgr)->tp_name); } Py_DECREF(enter); goto error; } #line 3578 "Python/generated_cases.c.h" Py_DECREF(mgr); #line 2533 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } #line 3587 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; DISPATCH(); } TARGET(WITH_EXCEPT_START) { PyObject *val = stack_pointer[-1]; PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; #line 2542 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception - lasti: THIRD = lasti of exception in exc_info() - exit_func: FOURTH = the context.__exit__ bound method We call FOURTH(type(TOP), TOP, GetTraceback(TOP)). Then we push the __exit__ return value. */ PyObject *exc, *tb; assert(val && PyExceptionInstance_Check(val)); exc = PyExceptionInstance_Class(val); tb = PyException_GetTraceback(val); Py_XDECREF(tb); assert(PyLong_Check(lasti)); (void)lasti; // Shut up compiler warning if asserts are off PyObject *stack[4] = {NULL, exc, val, tb}; res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; #line 3620 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; #line 2581 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; } else { prev_exc = Py_None; } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); #line 3639 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; DISPATCH(); } TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { PyObject *self = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); #line 2593 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self); DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); res2 = Py_NewRef(descr); assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); #line 3670 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_METHOD_NO_DICT) { PyObject *self = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); #line 2612 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; assert(oparg & 1); #line 3694 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_METHOD_LAZY_DICT) { PyObject *self = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); #line 2624 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; assert(dictoffset > 0); PyObject *dict = *(PyObject **)((char *)self + dictoffset); /* This object has a __dict__, just not yet created */ DEOPT_IF(dict != NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; assert(oparg & 1); #line 3722 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } next_instr += 9; DISPATCH(); } TARGET(KW_NAMES) { #line 2640 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); #line 3735 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { #line 2646 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING : PEEK(total_args); int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, next_instr-1, function, arg); if (err) goto error; _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); #line 3753 "Python/generated_cases.c.h" } TARGET(CALL) { PREDICTED(CALL); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; #line 2691 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { callable = method; args--; total_args++; } #if ENABLE_SPECIALIZATION _PyCallCache *cache = (_PyCallCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_Call(callable, next_instr, total_args, kwnames); DISPATCH_SAME_OPARG(); } STAT_INC(CALL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ if (!is_meth && Py_TYPE(callable) == &PyMethod_Type) { is_meth = 1; // For consistenct; it's dead, though args--; total_args++; PyObject *self = ((PyMethodObject *)callable)->im_self; args[0] = Py_NewRef(self); method = ((PyMethodObject *)callable)->im_func; args[-1] = Py_NewRef(method); Py_DECREF(callable); callable = method; } int positional_args = total_args - KWNAMES_LEN(); // Check if the call can be inlined or not if (Py_TYPE(callable) == &PyFunction_Type && tstate->interp->eval_frame == NULL && ((PyFunctionObject *)callable)->vectorcall == _PyFunction_Vectorcall) { int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable)); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( tstate, (PyFunctionObject *)callable, locals, args, positional_args, kwnames ); kwnames = NULL; // Manipulate stack directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); // The frame has stolen all the arguments from the stack, // so there is no need to clean them up. if (new_frame == NULL) { goto error; } JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); } /* Callable is not a normal Python function */ res = PyObject_Vectorcall( callable, args, positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames); if (opcode == INSTRUMENTED_CALL) { PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING : PEEK(total_args); if (res == NULL) { _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, frame, next_instr-1, callable, arg); } else { int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_C_RETURN, frame, next_instr-1, callable, arg); if (err < 0) { Py_CLEAR(res); } } } kwnames = NULL; assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(callable); for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } #line 3845 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; #line 2779 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); PyObject *self = ((PyMethodObject *)callable)->im_self; PEEK(oparg + 1) = Py_NewRef(self); // callable PyObject *meth = ((PyMethodObject *)callable)->im_func; PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); #line 3867 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { PREDICTED(CALL_PY_EXACT_ARGS); PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); #line 2791 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; int argcount = oparg; if (is_meth) { callable = method; args--; argcount++; } DEOPT_IF(!PyFunction_Check(callable), CALL); PyFunctionObject *func = (PyFunctionObject *)callable; DEOPT_IF(func->func_version != func_version, CALL); PyCodeObject *code = (PyCodeObject *)func->func_code; DEOPT_IF(code->co_argcount != argcount, CALL); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); STAT_INC(CALL, hit); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, func, argcount); for (int i = 0; i < argcount; i++) { new_frame->localsplus[i] = args[i]; } // Manipulate stack directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); #line 3902 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); #line 2819 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; int argcount = oparg; if (is_meth) { callable = method; args--; argcount++; } DEOPT_IF(!PyFunction_Check(callable), CALL); PyFunctionObject *func = (PyFunctionObject *)callable; DEOPT_IF(func->func_version != func_version, CALL); PyCodeObject *code = (PyCodeObject *)func->func_code; assert(func->func_defaults); assert(PyTuple_CheckExact(func->func_defaults)); int defcount = (int)PyTuple_GET_SIZE(func->func_defaults); assert(defcount <= code->co_argcount); int min_args = code->co_argcount - defcount; DEOPT_IF(argcount > code->co_argcount, CALL); DEOPT_IF(argcount < min_args, CALL); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); STAT_INC(CALL, hit); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, func, code->co_argcount); for (int i = 0; i < argcount; i++) { new_frame->localsplus[i] = args[i]; } for (int i = argcount; i < code->co_argcount; i++) { PyObject *def = PyTuple_GET_ITEM(func->func_defaults, i - min_args); new_frame->localsplus[i] = Py_NewRef(def); } // Manipulate stack and cache directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); #line 3946 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; #line 2857 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); PyObject *obj = args[0]; DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL); STAT_INC(CALL, hit); res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable #line 3964 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 3; DISPATCH(); } TARGET(CALL_NO_KW_STR_1) { PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; #line 2869 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL); STAT_INC(CALL, hit); PyObject *arg = args[0]; res = PyObject_Str(arg); Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } #line 3988 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(CALL_NO_KW_TUPLE_1) { PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; #line 2883 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyTuple_Type, CALL); STAT_INC(CALL, hit); PyObject *arg = args[0]; res = PySequence_Tuple(arg); Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } #line 4013 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(CALL_BUILTIN_CLASS) { PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; #line 2897 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { callable = method; args--; total_args++; } int kwnames_len = KWNAMES_LEN(); DEOPT_IF(!PyType_Check(callable), CALL); PyTypeObject *tp = (PyTypeObject *)callable; DEOPT_IF(tp->tp_vectorcall == NULL, CALL); STAT_INC(CALL, hit); res = tp->tp_vectorcall((PyObject *)tp, args, total_args - kwnames_len, kwnames); kwnames = NULL; /* Free the arguments. */ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } #line 4049 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(CALL_NO_KW_BUILTIN_O) { PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; #line 2922 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { callable = method; args--; total_args++; } DEOPT_IF(total_args != 1, CALL); DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, CALL); STAT_INC(CALL, hit); PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); // This is slower but CPython promises to check all non-vectorcall // function calls. if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) { goto error; } PyObject *arg = args[0]; res = _PyCFunction_TrampolineCall(cfunc, PyCFunction_GET_SELF(callable), arg); _Py_LeaveRecursiveCallTstate(tstate); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } #line 4091 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(CALL_NO_KW_BUILTIN_FAST) { PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; #line 2953 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { callable = method; args--; total_args++; } DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL, CALL); STAT_INC(CALL, hit); PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); /* res = func(self, args, nargs) */ res = ((_PyCFunctionFast)(void(*)(void))cfunc)( PyCFunction_GET_SELF(callable), args, total_args); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); /* Free the arguments. */ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } /* Not deopting because this doesn't mean our optimization was wrong. `res` can be NULL for valid reasons. Eg. getattr(x, 'invalid'). In those cases an exception is set, so we must handle it. */ #line 4137 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) { PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; #line 2988 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; if (is_meth) { callable = method; args--; total_args++; } DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); DEOPT_IF(PyCFunction_GET_FLAGS(callable) != (METH_FASTCALL | METH_KEYWORDS), CALL); STAT_INC(CALL, hit); /* res = func(self, args, nargs, kwnames) */ _PyCFunctionFastWithKeywords cfunc = (_PyCFunctionFastWithKeywords)(void(*)(void)) PyCFunction_GET_FUNCTION(callable); res = cfunc( PyCFunction_GET_SELF(callable), args, total_args - KWNAMES_LEN(), kwnames ); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); kwnames = NULL; /* Free the arguments. */ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } #line 4183 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(CALL_NO_KW_LEN) { PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; #line 3023 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; int total_args = oparg; if (is_meth) { callable = method; args--; total_args++; } DEOPT_IF(total_args != 1, CALL); PyInterpreterState *interp = _PyInterpreterState_GET(); DEOPT_IF(callable != interp->callable_cache.len, CALL); STAT_INC(CALL, hit); PyObject *arg = args[0]; Py_ssize_t len_i = PyObject_Length(arg); if (len_i < 0) { goto error; } res = PyLong_FromSsize_t(len_i); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } #line 4222 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 3; DISPATCH(); } TARGET(CALL_NO_KW_ISINSTANCE) { PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; #line 3050 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; int total_args = oparg; if (is_meth) { callable = method; args--; total_args++; } DEOPT_IF(total_args != 2, CALL); PyInterpreterState *interp = _PyInterpreterState_GET(); DEOPT_IF(callable != interp->callable_cache.isinstance, CALL); STAT_INC(CALL, hit); PyObject *cls = args[1]; PyObject *inst = args[0]; int retval = PyObject_IsInstance(inst, cls); if (retval < 0) { goto error; } res = PyBool_FromLong(retval); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(inst); Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } #line 4262 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 3; DISPATCH(); } TARGET(CALL_NO_KW_LIST_APPEND) { PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; #line 3080 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); PyInterpreterState *interp = _PyInterpreterState_GET(); DEOPT_IF(method != interp->callable_cache.list_append, CALL); DEOPT_IF(!PyList_Check(self), CALL); STAT_INC(CALL, hit); if (_PyList_AppendTakeRef((PyListObject *)self, args[0]) < 0) { goto pop_1_error; // Since arg is DECREF'ed already } Py_DECREF(self); Py_DECREF(method); STACK_SHRINK(3); // CALL + POP_TOP JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); #line 4292 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; #line 3100 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { args--; total_args++; } PyMethodDescrObject *callable = (PyMethodDescrObject *)PEEK(total_args + 1); DEOPT_IF(total_args != 2, CALL); DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); PyMethodDef *meth = callable->d_method; DEOPT_IF(meth->ml_flags != METH_O, CALL); PyObject *arg = args[1]; PyObject *self = args[0]; DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); STAT_INC(CALL, hit); PyCFunction cfunc = meth->ml_meth; // This is slower but CPython promises to check all non-vectorcall // function calls. if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) { goto error; } res = _PyCFunction_TrampolineCall(cfunc, self, arg); _Py_LeaveRecursiveCallTstate(tstate); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(self); Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } #line 4330 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; #line 3134 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { args--; total_args++; } PyMethodDescrObject *callable = (PyMethodDescrObject *)PEEK(total_args + 1); DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); PyMethodDef *meth = callable->d_method; DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), CALL); PyTypeObject *d_type = callable->d_common.d_type; PyObject *self = args[0]; DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL); STAT_INC(CALL, hit); int nargs = total_args - 1; _PyCFunctionFastWithKeywords cfunc = (_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; res = cfunc(self, args + 1, nargs - KWNAMES_LEN(), kwnames); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); kwnames = NULL; /* Free the arguments. */ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } #line 4372 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; #line 3166 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { args--; total_args++; } DEOPT_IF(total_args != 1, CALL); PyMethodDescrObject *callable = (PyMethodDescrObject *)SECOND(); DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); PyMethodDef *meth = callable->d_method; PyObject *self = args[0]; DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL); STAT_INC(CALL, hit); PyCFunction cfunc = meth->ml_meth; // This is slower but CPython promises to check all non-vectorcall // function calls. if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) { goto error; } res = _PyCFunction_TrampolineCall(cfunc, self, NULL); _Py_LeaveRecursiveCallTstate(tstate); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } #line 4414 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; #line 3198 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { args--; total_args++; } PyMethodDescrObject *callable = (PyMethodDescrObject *)PEEK(total_args + 1); /* Builtin METH_FASTCALL methods, without keywords */ DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); PyMethodDef *meth = callable->d_method; DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL); PyObject *self = args[0]; DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); STAT_INC(CALL, hit); _PyCFunctionFast cfunc = (_PyCFunctionFast)(void(*)(void))meth->ml_meth; int nargs = total_args - 1; res = cfunc(self, args + 1, nargs); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); /* Clear the stack of the arguments. */ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } #line 4455 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 3; CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { #line 3229 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); #line 4467 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { PREDICTED(CALL_FUNCTION_EX); PyObject *kwargs = (oparg & 1) ? stack_pointer[-(((oparg & 1) ? 1 : 0))] : NULL; PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; #line 3233 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); if (!PyTuple_CheckExact(callargs)) { if (check_args_iterable(tstate, func, callargs) < 0) { goto error; } PyObject *tuple = PySequence_Tuple(callargs); if (tuple == NULL) { goto error; } Py_SETREF(callargs, tuple); } assert(PyTuple_CheckExact(callargs)); EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); if (opcode == INSTRUMENTED_CALL_FUNCTION_EX && !PyFunction_Check(func) && !PyMethod_Check(func) ) { PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? PyTuple_GET_ITEM(callargs, 0) : Py_None; int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, next_instr-1, func, arg); if (err) goto error; result = PyObject_Call(func, callargs, kwargs); if (result == NULL) { _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, frame, next_instr-1, func, arg); } else { int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_C_RETURN, frame, next_instr-1, func, arg); if (err < 0) { Py_CLEAR(result); } } } else { if (Py_TYPE(func) == &PyFunction_Type && tstate->interp->eval_frame == NULL && ((PyFunctionObject *)func)->vectorcall == _PyFunction_Vectorcall) { assert(PyTuple_CheckExact(callargs)); Py_ssize_t nargs = PyTuple_GET_SIZE(callargs); int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func)); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex(tstate, (PyFunctionObject *)func, locals, nargs, callargs, kwargs); // Need to manually shrink the stack since we exit with DISPATCH_INLINED. STACK_SHRINK(oparg + 3); if (new_frame == NULL) { goto error; } frame->return_offset = 0; DISPATCH_INLINED(new_frame); } result = PyObject_Call(func, callargs, kwargs); } #line 4538 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); #line 3295 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } #line 4545 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *closure = (oparg & MAKE_FUNCTION_CLOSURE) ? stack_pointer[-(1 + ((oparg & MAKE_FUNCTION_CLOSURE) ? 1 : 0))] : NULL; PyObject *annotations = (oparg & MAKE_FUNCTION_ANNOTATIONS) ? stack_pointer[-(1 + ((oparg & MAKE_FUNCTION_CLOSURE) ? 1 : 0) + ((oparg & MAKE_FUNCTION_ANNOTATIONS) ? 1 : 0))] : NULL; PyObject *kwdefaults = (oparg & MAKE_FUNCTION_KWDEFAULTS) ? stack_pointer[-(1 + ((oparg & MAKE_FUNCTION_CLOSURE) ? 1 : 0) + ((oparg & MAKE_FUNCTION_ANNOTATIONS) ? 1 : 0) + ((oparg & MAKE_FUNCTION_KWDEFAULTS) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & MAKE_FUNCTION_DEFAULTS) ? stack_pointer[-(1 + ((oparg & MAKE_FUNCTION_CLOSURE) ? 1 : 0) + ((oparg & MAKE_FUNCTION_ANNOTATIONS) ? 1 : 0) + ((oparg & MAKE_FUNCTION_KWDEFAULTS) ? 1 : 0) + ((oparg & MAKE_FUNCTION_DEFAULTS) ? 1 : 0))] : NULL; PyObject *func; #line 3305 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); Py_DECREF(codeobj); if (func_obj == NULL) { goto error; } if (oparg & MAKE_FUNCTION_CLOSURE) { assert(PyTuple_CheckExact(closure)); func_obj->func_closure = closure; } if (oparg & MAKE_FUNCTION_ANNOTATIONS) { assert(PyTuple_CheckExact(annotations)); func_obj->func_annotations = annotations; } if (oparg & MAKE_FUNCTION_KWDEFAULTS) { assert(PyDict_CheckExact(kwdefaults)); func_obj->func_kwdefaults = kwdefaults; } if (oparg & MAKE_FUNCTION_DEFAULTS) { assert(PyTuple_CheckExact(defaults)); func_obj->func_defaults = defaults; } func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; #line 4589 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & MAKE_FUNCTION_DEFAULTS) ? 1 : 0) + ((oparg & MAKE_FUNCTION_KWDEFAULTS) ? 1 : 0) + ((oparg & MAKE_FUNCTION_ANNOTATIONS) ? 1 : 0) + ((oparg & MAKE_FUNCTION_CLOSURE) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { #line 3336 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); if (gen == NULL) { goto error; } assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; _PyFrame_Copy(frame, gen_frame); assert(frame->frame_obj == NULL); gen->gi_frame_state = FRAME_CREATED; gen_frame->owner = FRAME_OWNED_BY_GENERATOR; _Py_LeaveRecursiveCallPy(tstate); assert(frame != &entry_frame); _PyInterpreterFrame *prev = frame->previous; _PyThreadState_PopFrame(tstate, frame); frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; #line 4617 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { PyObject *step = (oparg == 3) ? stack_pointer[-(((oparg == 3) ? 1 : 0))] : NULL; PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; #line 3359 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); #line 4627 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); #line 3361 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } #line 4633 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; DISPATCH(); } TARGET(FORMAT_VALUE) { PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; #line 3365 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; /* See if any conversion is specified. */ switch (which_conversion) { case FVC_NONE: conv_fn = NULL; break; case FVC_STR: conv_fn = PyObject_Str; break; case FVC_REPR: conv_fn = PyObject_Repr; break; case FVC_ASCII: conv_fn = PyObject_ASCII; break; default: _PyErr_Format(tstate, PyExc_SystemError, "unexpected conversion flag %d", which_conversion); goto error; } /* If there's a conversion function, call it and replace value with that result. Otherwise, just use value, without conversion. */ if (conv_fn != NULL) { result = conv_fn(value); Py_DECREF(value); if (result == NULL) { Py_XDECREF(fmt_spec); if (true) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } } value = result; } result = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } #line 4679 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); } TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; #line 3402 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); #line 4691 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); } TARGET(BINARY_OP) { PREDICTED(BINARY_OP); static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; #line 3407 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, &GETLOCAL(0)); DISPATCH_SAME_OPARG(); } STAT_INC(BINARY_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ assert(0 <= oparg); assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); #line 4718 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); #line 3422 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 4723 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; DISPATCH(); } TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; #line 3427 "Python/bytecodes.c" assert(oparg >= 2); #line 4735 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { #line 3431 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; next_instr--; if (_PyOpcode_Caches[next_opcode]) { _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1); INCREMENT_ADAPTIVE_COUNTER(cache->counter); } assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); #line 4754 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { #line 3445 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); #line 4760 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { #line 3449 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); #line 4767 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { #line 3454 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); if (err < 0) goto error; _Py_CODEUNIT *here = next_instr-1; assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); #line 4782 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { #line 3465 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); if (err < 0) goto error; _Py_CODEUNIT *here = next_instr-1; assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); #line 4796 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { #line 3476 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; if (Py_IsNone(value)) { offset = oparg; } else { Py_DECREF(value); offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); #line 4813 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { #line 3490 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; if (Py_IsNone(value)) { offset = 0; } else { Py_DECREF(value); offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); #line 4830 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { #line 3504 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); #line 4841 "Python/generated_cases.c.h" } TARGET(CACHE) { #line 3512 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); #line 4848 "Python/generated_cases.c.h" } TARGET(RESERVED) { #line 3517 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); #line 4855 "Python/generated_cases.c.h" } ================================================ FILE: GetArgs.c ================================================ /* New getargs implementation */ #include "Python.h" #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "pycore_pylifecycle.h" // _PyArg_Fini #include #include #ifdef __cplusplus extern "C" { #endif /* Export Stable ABIs (abi only) */ PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, const char *, ...); PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, const char *, ...); PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywords_SizeT(PyObject *, PyObject *, const char *, char **, ...); PyAPI_FUNC(int) _PyArg_VaParse_SizeT(PyObject *, const char *, va_list); PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *, PyObject *, const char *, char **, va_list); #define FLAG_COMPAT 1 typedef int (*destr_t)(PyObject *, void *); /* Keep track of "objects" that have been allocated or initialized and which will need to be deallocated or cleaned up somehow if overall parsing fails. */ typedef struct { void *item; destr_t destructor; } freelistentry_t; typedef struct { freelistentry_t *entries; int first_available; int entries_malloced; } freelist_t; #define STATIC_FREELIST_ENTRIES 8 /* Forward */ static int vgetargs1_impl(PyObject *args, PyObject *const *stack, Py_ssize_t nargs, const char *format, va_list *p_va, int flags); static int vgetargs1(PyObject *, const char *, va_list *, int); static void seterror(Py_ssize_t, const char *, int *, const char *, const char *); static const char *convertitem(PyObject *, const char **, va_list *, int, int *, char *, size_t, freelist_t *); static const char *converttuple(PyObject *, const char **, va_list *, int, int *, char *, size_t, int, freelist_t *); static const char *convertsimple(PyObject *, const char **, va_list *, int, char *, size_t, freelist_t *); static Py_ssize_t convertbuffer(PyObject *, const void **p, const char **); static int getbuffer(PyObject *, Py_buffer *, const char**); static int vgetargskeywords(PyObject *, PyObject *, const char *, char **, va_list *, int); static int vgetargskeywordsfast(PyObject *, PyObject *, struct _PyArg_Parser *, va_list *, int); static int vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, PyObject *keywords, PyObject *kwnames, struct _PyArg_Parser *parser, va_list *p_va, int flags); static const char *skipitem(const char **, va_list *, int); int PyArg_Parse(PyObject *args, const char *format, ...) { int retval; va_list va; va_start(va, format); retval = vgetargs1(args, format, &va, FLAG_COMPAT); va_end(va); return retval; } PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *args, const char *format, ...) { int retval; va_list va; va_start(va, format); retval = vgetargs1(args, format, &va, FLAG_COMPAT); va_end(va); return retval; } int PyArg_ParseTuple(PyObject *args, const char *format, ...) { int retval; va_list va; va_start(va, format); retval = vgetargs1(args, format, &va, 0); va_end(va); return retval; } int _PyArg_ParseTuple_SizeT(PyObject *args, const char *format, ...) { int retval; va_list va; va_start(va, format); retval = vgetargs1(args, format, &va, 0); va_end(va); return retval; } int _PyArg_ParseStack(PyObject *const *args, Py_ssize_t nargs, const char *format, ...) { int retval; va_list va; va_start(va, format); retval = vgetargs1_impl(NULL, args, nargs, format, &va, 0); va_end(va); return retval; } int PyArg_VaParse(PyObject *args, const char *format, va_list va) { va_list lva; int retval; va_copy(lva, va); retval = vgetargs1(args, format, &lva, 0); va_end(lva); return retval; } int _PyArg_VaParse_SizeT(PyObject *args, const char *format, va_list va) { va_list lva; int retval; va_copy(lva, va); retval = vgetargs1(args, format, &lva, 0); va_end(lva); return retval; } /* Handle cleanup of allocated memory in case of exception */ static int cleanup_ptr(PyObject *self, void *ptr) { void **pptr = (void **)ptr; PyMem_Free(*pptr); *pptr = NULL; return 0; } static int cleanup_buffer(PyObject *self, void *ptr) { Py_buffer *buf = (Py_buffer *)ptr; if (buf) { PyBuffer_Release(buf); } return 0; } static int addcleanup(void *ptr, freelist_t *freelist, destr_t destructor) { int index; index = freelist->first_available; freelist->first_available += 1; freelist->entries[index].item = ptr; freelist->entries[index].destructor = destructor; return 0; } static int cleanreturn(int retval, freelist_t *freelist) { int index; if (retval == 0) { /* A failure occurred, therefore execute all of the cleanup functions. */ for (index = 0; index < freelist->first_available; ++index) { freelist->entries[index].destructor(NULL, freelist->entries[index].item); } } if (freelist->entries_malloced) PyMem_Free(freelist->entries); return retval; } static int vgetargs1_impl(PyObject *compat_args, PyObject *const *stack, Py_ssize_t nargs, const char *format, va_list *p_va, int flags) { char msgbuf[256]; int levels[32]; const char *fname = NULL; const char *message = NULL; int min = -1; int max = 0; int level = 0; int endfmt = 0; const char *formatsave = format; Py_ssize_t i; const char *msg; int compat = flags & FLAG_COMPAT; freelistentry_t static_entries[STATIC_FREELIST_ENTRIES]; freelist_t freelist; assert(nargs == 0 || stack != NULL); freelist.entries = static_entries; freelist.first_available = 0; freelist.entries_malloced = 0; flags = flags & ~FLAG_COMPAT; while (endfmt == 0) { int c = *format++; switch (c) { case '(': if (level == 0) max++; level++; if (level >= 30) Py_FatalError("too many tuple nesting levels " "in argument format string"); break; case ')': if (level == 0) Py_FatalError("excess ')' in getargs format"); else level--; break; case '\0': endfmt = 1; break; case ':': fname = format; endfmt = 1; break; case ';': message = format; endfmt = 1; break; case '|': if (level == 0) min = max; break; default: if (level == 0) { if (Py_ISALPHA(c)) if (c != 'e') /* skip encoded */ max++; } break; } } if (level != 0) Py_FatalError(/* '(' */ "missing ')' in getargs format"); if (min < 0) min = max; format = formatsave; if (max > STATIC_FREELIST_ENTRIES) { freelist.entries = PyMem_NEW(freelistentry_t, max); if (freelist.entries == NULL) { PyErr_NoMemory(); return 0; } freelist.entries_malloced = 1; } if (compat) { if (max == 0) { if (compat_args == NULL) return 1; PyErr_Format(PyExc_TypeError, "%.200s%s takes no arguments", fname==NULL ? "function" : fname, fname==NULL ? "" : "()"); return cleanreturn(0, &freelist); } else if (min == 1 && max == 1) { if (compat_args == NULL) { PyErr_Format(PyExc_TypeError, "%.200s%s takes at least one argument", fname==NULL ? "function" : fname, fname==NULL ? "" : "()"); return cleanreturn(0, &freelist); } msg = convertitem(compat_args, &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg == NULL) return cleanreturn(1, &freelist); seterror(levels[0], msg, levels+1, fname, message); return cleanreturn(0, &freelist); } else { PyErr_SetString(PyExc_SystemError, "old style getargs format uses new features"); return cleanreturn(0, &freelist); } } if (nargs < min || max < nargs) { if (message == NULL) PyErr_Format(PyExc_TypeError, "%.150s%s takes %s %d argument%s (%zd given)", fname==NULL ? "function" : fname, fname==NULL ? "" : "()", min==max ? "exactly" : nargs < min ? "at least" : "at most", nargs < min ? min : max, (nargs < min ? min : max) == 1 ? "" : "s", nargs); else PyErr_SetString(PyExc_TypeError, message); return cleanreturn(0, &freelist); } for (i = 0; i < nargs; i++) { if (*format == '|') format++; msg = convertitem(stack[i], &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { seterror(i+1, msg, levels, fname, message); return cleanreturn(0, &freelist); } } if (*format != '\0' && !Py_ISALPHA(*format) && *format != '(' && *format != '|' && *format != ':' && *format != ';') { PyErr_Format(PyExc_SystemError, "bad format string: %.200s", formatsave); return cleanreturn(0, &freelist); } return cleanreturn(1, &freelist); } static int vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) { PyObject **stack; Py_ssize_t nargs; if (!(flags & FLAG_COMPAT)) { assert(args != NULL); if (!PyTuple_Check(args)) { PyErr_SetString(PyExc_SystemError, "new style getargs format but argument is not a tuple"); return 0; } stack = _PyTuple_ITEMS(args); nargs = PyTuple_GET_SIZE(args); } else { stack = NULL; nargs = 0; } return vgetargs1_impl(args, stack, nargs, format, p_va, flags); } static void seterror(Py_ssize_t iarg, const char *msg, int *levels, const char *fname, const char *message) { char buf[512]; int i; char *p = buf; if (PyErr_Occurred()) return; else if (message == NULL) { if (fname != NULL) { PyOS_snprintf(p, sizeof(buf), "%.200s() ", fname); p += strlen(p); } if (iarg != 0) { PyOS_snprintf(p, sizeof(buf) - (p - buf), "argument %zd", iarg); i = 0; p += strlen(p); while (i < 32 && levels[i] > 0 && (int)(p-buf) < 220) { PyOS_snprintf(p, sizeof(buf) - (p - buf), ", item %d", levels[i]-1); p += strlen(p); i++; } } else { PyOS_snprintf(p, sizeof(buf) - (p - buf), "argument"); p += strlen(p); } PyOS_snprintf(p, sizeof(buf) - (p - buf), " %.256s", msg); message = buf; } if (msg[0] == '(') { PyErr_SetString(PyExc_SystemError, message); } else { PyErr_SetString(PyExc_TypeError, message); } } /* Convert a tuple argument. On entry, *p_format points to the character _after_ the opening '('. On successful exit, *p_format points to the closing ')'. If successful: *p_format and *p_va are updated, *levels and *msgbuf are untouched, and NULL is returned. If the argument is invalid: *p_format is unchanged, *p_va is undefined, *levels is a 0-terminated list of item numbers, *msgbuf contains an error message, whose format is: "must be , not ", where: is the name of the expected type, and is the name of the actual type, and msgbuf is returned. */ static const char * converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, int *levels, char *msgbuf, size_t bufsize, int toplevel, freelist_t *freelist) { int level = 0; int n = 0; const char *format = *p_format; int i; Py_ssize_t len; for (;;) { int c = *format++; if (c == '(') { if (level == 0) n++; level++; } else if (c == ')') { if (level == 0) break; level--; } else if (c == ':' || c == ';' || c == '\0') break; else if (level == 0 && Py_ISALPHA(c)) n++; } if (!PySequence_Check(arg) || PyBytes_Check(arg)) { levels[0] = 0; PyOS_snprintf(msgbuf, bufsize, toplevel ? "expected %d arguments, not %.50s" : "must be %d-item sequence, not %.50s", n, arg == Py_None ? "None" : Py_TYPE(arg)->tp_name); return msgbuf; } len = PySequence_Size(arg); if (len != n) { levels[0] = 0; if (toplevel) { PyOS_snprintf(msgbuf, bufsize, "expected %d argument%s, not %zd", n, n == 1 ? "" : "s", len); } else { PyOS_snprintf(msgbuf, bufsize, "must be sequence of length %d, not %zd", n, len); } return msgbuf; } format = *p_format; for (i = 0; i < n; i++) { const char *msg; PyObject *item; item = PySequence_GetItem(arg, i); if (item == NULL) { PyErr_Clear(); levels[0] = i+1; levels[1] = 0; strncpy(msgbuf, "is not retrievable", bufsize); return msgbuf; } msg = convertitem(item, &format, p_va, flags, levels+1, msgbuf, bufsize, freelist); /* PySequence_GetItem calls tp->sq_item, which INCREFs */ Py_XDECREF(item); if (msg != NULL) { levels[0] = i+1; return msg; } } *p_format = format; return NULL; } /* Convert a single item. */ static const char * convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags, int *levels, char *msgbuf, size_t bufsize, freelist_t *freelist) { const char *msg; const char *format = *p_format; if (*format == '(' /* ')' */) { format++; msg = converttuple(arg, &format, p_va, flags, levels, msgbuf, bufsize, 0, freelist); if (msg == NULL) format++; } else { msg = convertsimple(arg, &format, p_va, flags, msgbuf, bufsize, freelist); if (msg != NULL) levels[0] = 0; } if (msg == NULL) *p_format = format; return msg; } /* Format an error message generated by convertsimple(). displayname must be UTF-8 encoded. */ void _PyArg_BadArgument(const char *fname, const char *displayname, const char *expected, PyObject *arg) { PyErr_Format(PyExc_TypeError, "%.200s() %.200s must be %.50s, not %.50s", fname, displayname, expected, arg == Py_None ? "None" : Py_TYPE(arg)->tp_name); } static const char * converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize) { assert(expected != NULL); assert(arg != NULL); if (expected[0] == '(') { PyOS_snprintf(msgbuf, bufsize, "%.100s", expected); } else { PyOS_snprintf(msgbuf, bufsize, "must be %.50s, not %.50s", expected, arg == Py_None ? "None" : Py_TYPE(arg)->tp_name); } return msgbuf; } #define CONV_UNICODE "(unicode conversion error)" /* Convert a non-tuple argument. Return NULL if conversion went OK, or a string with a message describing the failure. The message is formatted as "must be , not ". When failing, an exception may or may not have been raised. Don't call if a tuple is expected. When you add new format codes, please don't forget poor skipitem() below. */ static const char * convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, char *msgbuf, size_t bufsize, freelist_t *freelist) { #define RETURN_ERR_OCCURRED return msgbuf const char *format = *p_format; char c = *format++; const char *sarg; switch (c) { case 'b': { /* unsigned byte -- very short int */ char *p = va_arg(*p_va, char *); long ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else if (ival < 0) { PyErr_SetString(PyExc_OverflowError, "unsigned byte integer is less than minimum"); RETURN_ERR_OCCURRED; } else if (ival > UCHAR_MAX) { PyErr_SetString(PyExc_OverflowError, "unsigned byte integer is greater than maximum"); RETURN_ERR_OCCURRED; } else *p = (unsigned char) ival; break; } case 'B': {/* byte sized bitfield - both signed and unsigned values allowed */ char *p = va_arg(*p_va, char *); unsigned long ival = PyLong_AsUnsignedLongMask(arg); if (ival == (unsigned long)-1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = (unsigned char) ival; break; } case 'h': {/* signed short int */ short *p = va_arg(*p_va, short *); long ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else if (ival < SHRT_MIN) { PyErr_SetString(PyExc_OverflowError, "signed short integer is less than minimum"); RETURN_ERR_OCCURRED; } else if (ival > SHRT_MAX) { PyErr_SetString(PyExc_OverflowError, "signed short integer is greater than maximum"); RETURN_ERR_OCCURRED; } else *p = (short) ival; break; } case 'H': { /* short int sized bitfield, both signed and unsigned allowed */ unsigned short *p = va_arg(*p_va, unsigned short *); unsigned long ival = PyLong_AsUnsignedLongMask(arg); if (ival == (unsigned long)-1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = (unsigned short) ival; break; } case 'i': {/* signed int */ int *p = va_arg(*p_va, int *); long ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else if (ival > INT_MAX) { PyErr_SetString(PyExc_OverflowError, "signed integer is greater than maximum"); RETURN_ERR_OCCURRED; } else if (ival < INT_MIN) { PyErr_SetString(PyExc_OverflowError, "signed integer is less than minimum"); RETURN_ERR_OCCURRED; } else *p = ival; break; } case 'I': { /* int sized bitfield, both signed and unsigned allowed */ unsigned int *p = va_arg(*p_va, unsigned int *); unsigned long ival = PyLong_AsUnsignedLongMask(arg); if (ival == (unsigned long)-1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = (unsigned int) ival; break; } case 'n': /* Py_ssize_t */ { PyObject *iobj; Py_ssize_t *p = va_arg(*p_va, Py_ssize_t *); Py_ssize_t ival = -1; iobj = _PyNumber_Index(arg); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); } if (ival == -1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; *p = ival; break; } case 'l': {/* long int */ long *p = va_arg(*p_va, long *); long ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = ival; break; } case 'k': { /* long sized bitfield */ unsigned long *p = va_arg(*p_va, unsigned long *); unsigned long ival; if (PyLong_Check(arg)) ival = PyLong_AsUnsignedLongMask(arg); else return converterr("int", arg, msgbuf, bufsize); *p = ival; break; } case 'L': {/* long long */ long long *p = va_arg( *p_va, long long * ); long long ival = PyLong_AsLongLong(arg); if (ival == (long long)-1 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = ival; break; } case 'K': { /* long long sized bitfield */ unsigned long long *p = va_arg(*p_va, unsigned long long *); unsigned long long ival; if (PyLong_Check(arg)) ival = PyLong_AsUnsignedLongLongMask(arg); else return converterr("int", arg, msgbuf, bufsize); *p = ival; break; } case 'f': {/* float */ float *p = va_arg(*p_va, float *); double dval = PyFloat_AsDouble(arg); if (dval == -1.0 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = (float) dval; break; } case 'd': {/* double */ double *p = va_arg(*p_va, double *); double dval = PyFloat_AsDouble(arg); if (dval == -1.0 && PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = dval; break; } case 'D': {/* complex double */ Py_complex *p = va_arg(*p_va, Py_complex *); Py_complex cval; cval = PyComplex_AsCComplex(arg); if (PyErr_Occurred()) RETURN_ERR_OCCURRED; else *p = cval; break; } case 'c': {/* char */ char *p = va_arg(*p_va, char *); if (PyBytes_Check(arg) && PyBytes_Size(arg) == 1) *p = PyBytes_AS_STRING(arg)[0]; else if (PyByteArray_Check(arg) && PyByteArray_Size(arg) == 1) *p = PyByteArray_AS_STRING(arg)[0]; else return converterr("a byte string of length 1", arg, msgbuf, bufsize); break; } case 'C': {/* unicode char */ int *p = va_arg(*p_va, int *); int kind; const void *data; if (!PyUnicode_Check(arg)) return converterr("a unicode character", arg, msgbuf, bufsize); if (PyUnicode_GET_LENGTH(arg) != 1) return converterr("a unicode character", arg, msgbuf, bufsize); kind = PyUnicode_KIND(arg); data = PyUnicode_DATA(arg); *p = PyUnicode_READ(kind, data, 0); break; } case 'p': {/* boolean *p*redicate */ int *p = va_arg(*p_va, int *); int val = PyObject_IsTrue(arg); if (val > 0) *p = 1; else if (val == 0) *p = 0; else RETURN_ERR_OCCURRED; break; } /* XXX WAAAAH! 's', 'y', 'z', 'u', 'Z', 'e', 'w' codes all need to be cleaned up! */ case 'y': {/* any bytes-like object */ void **p = (void **)va_arg(*p_va, char **); const char *buf; Py_ssize_t count; if (*format == '*') { if (getbuffer(arg, (Py_buffer*)p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); format++; if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); } break; } count = convertbuffer(arg, (const void **)p, &buf); if (count < 0) return converterr(buf, arg, msgbuf, bufsize); if (*format == '#') { Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*); *psize = count; format++; } else { if (strlen(*p) != (size_t)count) { PyErr_SetString(PyExc_ValueError, "embedded null byte"); RETURN_ERR_OCCURRED; } } break; } case 's': /* text string or bytes-like object */ case 'z': /* text string, bytes-like object or None */ { if (*format == '*') { /* "s*" or "z*" */ Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *); if (c == 'z' && arg == Py_None) PyBuffer_FillInfo(p, NULL, NULL, 0, 1, 0); else if (PyUnicode_Check(arg)) { Py_ssize_t len; sarg = PyUnicode_AsUTF8AndSize(arg, &len); if (sarg == NULL) return converterr(CONV_UNICODE, arg, msgbuf, bufsize); PyBuffer_FillInfo(p, arg, (void *)sarg, len, 1, 0); } else { /* any bytes-like object */ const char *buf; if (getbuffer(arg, p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); } if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); } format++; } else if (*format == '#') { /* a string or read-only bytes-like object */ /* "s#" or "z#" */ const void **p = (const void **)va_arg(*p_va, const char **); Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*); if (c == 'z' && arg == Py_None) { *p = NULL; *psize = 0; } else if (PyUnicode_Check(arg)) { Py_ssize_t len; sarg = PyUnicode_AsUTF8AndSize(arg, &len); if (sarg == NULL) return converterr(CONV_UNICODE, arg, msgbuf, bufsize); *p = sarg; *psize = len; } else { /* read-only bytes-like object */ /* XXX Really? */ const char *buf; Py_ssize_t count = convertbuffer(arg, p, &buf); if (count < 0) return converterr(buf, arg, msgbuf, bufsize); *psize = count; } format++; } else { /* "s" or "z" */ const char **p = va_arg(*p_va, const char **); Py_ssize_t len; sarg = NULL; if (c == 'z' && arg == Py_None) *p = NULL; else if (PyUnicode_Check(arg)) { sarg = PyUnicode_AsUTF8AndSize(arg, &len); if (sarg == NULL) return converterr(CONV_UNICODE, arg, msgbuf, bufsize); if (strlen(sarg) != (size_t)len) { PyErr_SetString(PyExc_ValueError, "embedded null character"); RETURN_ERR_OCCURRED; } *p = sarg; } else return converterr(c == 'z' ? "str or None" : "str", arg, msgbuf, bufsize); } break; } case 'e': {/* encoded string */ char **buffer; const char *encoding; PyObject *s; int recode_strings; Py_ssize_t size; const char *ptr; /* Get 'e' parameter: the encoding name */ encoding = (const char *)va_arg(*p_va, const char *); if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); /* Get output buffer parameter: 's' (recode all objects via Unicode) or 't' (only recode non-string objects) */ if (*format == 's') recode_strings = 1; else if (*format == 't') recode_strings = 0; else return converterr( "(unknown parser marker combination)", arg, msgbuf, bufsize); buffer = (char **)va_arg(*p_va, char **); format++; if (buffer == NULL) return converterr("(buffer is NULL)", arg, msgbuf, bufsize); /* Encode object */ if (!recode_strings && (PyBytes_Check(arg) || PyByteArray_Check(arg))) { s = Py_NewRef(arg); if (PyBytes_Check(arg)) { size = PyBytes_GET_SIZE(s); ptr = PyBytes_AS_STRING(s); } else { size = PyByteArray_GET_SIZE(s); ptr = PyByteArray_AS_STRING(s); } } else if (PyUnicode_Check(arg)) { /* Encode object; use default error handling */ s = PyUnicode_AsEncodedString(arg, encoding, NULL); if (s == NULL) return converterr("(encoding failed)", arg, msgbuf, bufsize); assert(PyBytes_Check(s)); size = PyBytes_GET_SIZE(s); ptr = PyBytes_AS_STRING(s); if (ptr == NULL) ptr = ""; } else { return converterr( recode_strings ? "str" : "str, bytes or bytearray", arg, msgbuf, bufsize); } /* Write output; output is guaranteed to be 0-terminated */ if (*format == '#') { /* Using buffer length parameter '#': - if *buffer is NULL, a new buffer of the needed size is allocated and the data copied into it; *buffer is updated to point to the new buffer; the caller is responsible for PyMem_Free()ing it after usage - if *buffer is not NULL, the data is copied to *buffer; *buffer_len has to be set to the size of the buffer on input; buffer overflow is signalled with an error; buffer has to provide enough room for the encoded string plus the trailing 0-byte - in both cases, *buffer_len is updated to the size of the buffer /excluding/ the trailing 0-byte */ Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*); format++; if (psize == NULL) { Py_DECREF(s); return converterr( "(buffer_len is NULL)", arg, msgbuf, bufsize); } if (*buffer == NULL) { *buffer = PyMem_NEW(char, size + 1); if (*buffer == NULL) { Py_DECREF(s); PyErr_NoMemory(); RETURN_ERR_OCCURRED; } if (addcleanup(buffer, freelist, cleanup_ptr)) { Py_DECREF(s); return converterr( "(cleanup problem)", arg, msgbuf, bufsize); } } else { if (size + 1 > *psize) { Py_DECREF(s); PyErr_Format(PyExc_ValueError, "encoded string too long " "(%zd, maximum length %zd)", (Py_ssize_t)size, (Py_ssize_t)(*psize - 1)); RETURN_ERR_OCCURRED; } } memcpy(*buffer, ptr, size+1); *psize = size; } else { /* Using a 0-terminated buffer: - the encoded string has to be 0-terminated for this variant to work; if it is not, an error raised - a new buffer of the needed size is allocated and the data copied into it; *buffer is updated to point to the new buffer; the caller is responsible for PyMem_Free()ing it after usage */ if ((Py_ssize_t)strlen(ptr) != size) { Py_DECREF(s); return converterr( "encoded string without null bytes", arg, msgbuf, bufsize); } *buffer = PyMem_NEW(char, size + 1); if (*buffer == NULL) { Py_DECREF(s); PyErr_NoMemory(); RETURN_ERR_OCCURRED; } if (addcleanup(buffer, freelist, cleanup_ptr)) { Py_DECREF(s); return converterr("(cleanup problem)", arg, msgbuf, bufsize); } memcpy(*buffer, ptr, size+1); } Py_DECREF(s); break; } case 'S': { /* PyBytes object */ PyObject **p = va_arg(*p_va, PyObject **); if (PyBytes_Check(arg)) *p = arg; else return converterr("bytes", arg, msgbuf, bufsize); break; } case 'Y': { /* PyByteArray object */ PyObject **p = va_arg(*p_va, PyObject **); if (PyByteArray_Check(arg)) *p = arg; else return converterr("bytearray", arg, msgbuf, bufsize); break; } case 'U': { /* PyUnicode object */ PyObject **p = va_arg(*p_va, PyObject **); if (PyUnicode_Check(arg)) { *p = arg; } else return converterr("str", arg, msgbuf, bufsize); break; } case 'O': { /* object */ PyTypeObject *type; PyObject **p; if (*format == '!') { type = va_arg(*p_va, PyTypeObject*); p = va_arg(*p_va, PyObject **); format++; if (PyType_IsSubtype(Py_TYPE(arg), type)) *p = arg; else return converterr(type->tp_name, arg, msgbuf, bufsize); } else if (*format == '&') { typedef int (*converter)(PyObject *, void *); converter convert = va_arg(*p_va, converter); void *addr = va_arg(*p_va, void *); int res; format++; if (! (res = (*convert)(arg, addr))) return converterr("(unspecified)", arg, msgbuf, bufsize); if (res == Py_CLEANUP_SUPPORTED && addcleanup(addr, freelist, convert) == -1) return converterr("(cleanup problem)", arg, msgbuf, bufsize); } else { p = va_arg(*p_va, PyObject **); *p = arg; } break; } case 'w': { /* "w*": memory buffer, read-write access */ void **p = va_arg(*p_va, void **); if (*format != '*') return converterr( "(invalid use of 'w' format character)", arg, msgbuf, bufsize); format++; /* Caller is interested in Py_buffer, and the object supports it directly. */ if (PyObject_GetBuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) { PyErr_Clear(); return converterr("read-write bytes-like object", arg, msgbuf, bufsize); } if (!PyBuffer_IsContiguous((Py_buffer*)p, 'C')) { PyBuffer_Release((Py_buffer*)p); return converterr("contiguous buffer", arg, msgbuf, bufsize); } if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); } break; } default: return converterr("(impossible)", arg, msgbuf, bufsize); } *p_format = format; return NULL; #undef RETURN_ERR_OCCURRED } static Py_ssize_t convertbuffer(PyObject *arg, const void **p, const char **errmsg) { PyBufferProcs *pb = Py_TYPE(arg)->tp_as_buffer; Py_ssize_t count; Py_buffer view; *errmsg = NULL; *p = NULL; if (pb != NULL && pb->bf_releasebuffer != NULL) { *errmsg = "read-only bytes-like object"; return -1; } if (getbuffer(arg, &view, errmsg) < 0) return -1; count = view.len; *p = view.buf; PyBuffer_Release(&view); return count; } static int getbuffer(PyObject *arg, Py_buffer *view, const char **errmsg) { if (PyObject_GetBuffer(arg, view, PyBUF_SIMPLE) != 0) { *errmsg = "bytes-like object"; return -1; } if (!PyBuffer_IsContiguous(view, 'C')) { PyBuffer_Release(view); *errmsg = "contiguous buffer"; return -1; } return 0; } /* Support for keyword arguments donated by Geoff Philbrick */ /* Return false (0) for error, else true. */ int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *keywords, const char *format, char **kwlist, ...) { int retval; va_list va; if ((args == NULL || !PyTuple_Check(args)) || (keywords != NULL && !PyDict_Check(keywords)) || format == NULL || kwlist == NULL) { PyErr_BadInternalCall(); return 0; } va_start(va, kwlist); retval = vgetargskeywords(args, keywords, format, kwlist, &va, 0); va_end(va); return retval; } int _PyArg_ParseTupleAndKeywords_SizeT(PyObject *args, PyObject *keywords, const char *format, char **kwlist, ...) { int retval; va_list va; if ((args == NULL || !PyTuple_Check(args)) || (keywords != NULL && !PyDict_Check(keywords)) || format == NULL || kwlist == NULL) { PyErr_BadInternalCall(); return 0; } va_start(va, kwlist); retval = vgetargskeywords(args, keywords, format, kwlist, &va, 0); va_end(va); return retval; } int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *keywords, const char *format, char **kwlist, va_list va) { int retval; va_list lva; if ((args == NULL || !PyTuple_Check(args)) || (keywords != NULL && !PyDict_Check(keywords)) || format == NULL || kwlist == NULL) { PyErr_BadInternalCall(); return 0; } va_copy(lva, va); retval = vgetargskeywords(args, keywords, format, kwlist, &lva, 0); va_end(lva); return retval; } int _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args, PyObject *keywords, const char *format, char **kwlist, va_list va) { int retval; va_list lva; if ((args == NULL || !PyTuple_Check(args)) || (keywords != NULL && !PyDict_Check(keywords)) || format == NULL || kwlist == NULL) { PyErr_BadInternalCall(); return 0; } va_copy(lva, va); retval = vgetargskeywords(args, keywords, format, kwlist, &lva, 0); va_end(lva); return retval; } PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywordsFast(PyObject *args, PyObject *keywords, struct _PyArg_Parser *parser, ...) { int retval; va_list va; va_start(va, parser); retval = vgetargskeywordsfast(args, keywords, parser, &va, 0); va_end(va); return retval; } int _PyArg_ParseTupleAndKeywordsFast_SizeT(PyObject *args, PyObject *keywords, struct _PyArg_Parser *parser, ...) { int retval; va_list va; va_start(va, parser); retval = vgetargskeywordsfast(args, keywords, parser, &va, 0); va_end(va); return retval; } int _PyArg_ParseStackAndKeywords(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames, struct _PyArg_Parser *parser, ...) { int retval; va_list va; va_start(va, parser); retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va, 0); va_end(va); return retval; } int _PyArg_ParseStackAndKeywords_SizeT(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames, struct _PyArg_Parser *parser, ...) { int retval; va_list va; va_start(va, parser); retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va, 0); va_end(va); return retval; } PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywordsFast(PyObject *args, PyObject *keywords, struct _PyArg_Parser *parser, va_list va) { int retval; va_list lva; va_copy(lva, va); retval = vgetargskeywordsfast(args, keywords, parser, &lva, 0); va_end(lva); return retval; } static void error_unexpected_keyword_arg(PyObject *kwargs, PyObject *kwnames, PyObject *kwtuple, const char *fname) { /* make sure there are no extraneous keyword arguments */ Py_ssize_t j = 0; while (1) { PyObject *keyword; if (kwargs != NULL) { if (!PyDict_Next(kwargs, &j, &keyword, NULL)) break; } else { if (j >= PyTuple_GET_SIZE(kwnames)) break; keyword = PyTuple_GET_ITEM(kwnames, j); j++; } if (!PyUnicode_Check(keyword)) { PyErr_SetString(PyExc_TypeError, "keywords must be strings"); return; } int match = PySequence_Contains(kwtuple, keyword); if (match <= 0) { if (!match) { PyErr_Format(PyExc_TypeError, "'%S' is an invalid keyword " "argument for %.200s%s", keyword, (fname == NULL) ? "this function" : fname, (fname == NULL) ? "" : "()"); } return; } } /* Something wrong happened. There are extraneous keyword arguments, * but we don't know what. And we don't bother. */ PyErr_Format(PyExc_TypeError, "invalid keyword argument for %.200s%s", (fname == NULL) ? "this function" : fname, (fname == NULL) ? "" : "()"); } int PyArg_ValidateKeywordArguments(PyObject *kwargs) { if (!PyDict_Check(kwargs)) { PyErr_BadInternalCall(); return 0; } if (!_PyDict_HasOnlyStringKeys(kwargs)) { PyErr_SetString(PyExc_TypeError, "keywords must be strings"); return 0; } return 1; } #define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':') static int vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, char **kwlist, va_list *p_va, int flags) { char msgbuf[512]; int levels[32]; const char *fname, *msg, *custom_msg; int min = INT_MAX; int max = INT_MAX; int i, pos, len; int skip = 0; Py_ssize_t nargs, nkwargs; PyObject *current_arg; freelistentry_t static_entries[STATIC_FREELIST_ENTRIES]; freelist_t freelist; freelist.entries = static_entries; freelist.first_available = 0; freelist.entries_malloced = 0; assert(args != NULL && PyTuple_Check(args)); assert(kwargs == NULL || PyDict_Check(kwargs)); assert(format != NULL); assert(kwlist != NULL); assert(p_va != NULL); /* grab the function name or custom error msg first (mutually exclusive) */ fname = strchr(format, ':'); if (fname) { fname++; custom_msg = NULL; } else { custom_msg = strchr(format,';'); if (custom_msg) custom_msg++; } /* scan kwlist and count the number of positional-only parameters */ for (pos = 0; kwlist[pos] && !*kwlist[pos]; pos++) { } /* scan kwlist and get greatest possible nbr of args */ for (len = pos; kwlist[len]; len++) { if (!*kwlist[len]) { PyErr_SetString(PyExc_SystemError, "Empty keyword parameter name"); return cleanreturn(0, &freelist); } } if (len > STATIC_FREELIST_ENTRIES) { freelist.entries = PyMem_NEW(freelistentry_t, len); if (freelist.entries == NULL) { PyErr_NoMemory(); return 0; } freelist.entries_malloced = 1; } nargs = PyTuple_GET_SIZE(args); nkwargs = (kwargs == NULL) ? 0 : PyDict_GET_SIZE(kwargs); if (nargs + nkwargs > len) { /* Adding "keyword" (when nargs == 0) prevents producing wrong error messages in some special cases (see bpo-31229). */ PyErr_Format(PyExc_TypeError, "%.200s%s takes at most %d %sargument%s (%zd given)", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()", len, (nargs == 0) ? "keyword " : "", (len == 1) ? "" : "s", nargs + nkwargs); return cleanreturn(0, &freelist); } /* convert tuple args and keyword args in same loop, using kwlist to drive process */ for (i = 0; i < len; i++) { if (*format == '|') { if (min != INT_MAX) { PyErr_SetString(PyExc_SystemError, "Invalid format string (| specified twice)"); return cleanreturn(0, &freelist); } min = i; format++; if (max != INT_MAX) { PyErr_SetString(PyExc_SystemError, "Invalid format string ($ before |)"); return cleanreturn(0, &freelist); } } if (*format == '$') { if (max != INT_MAX) { PyErr_SetString(PyExc_SystemError, "Invalid format string ($ specified twice)"); return cleanreturn(0, &freelist); } max = i; format++; if (max < pos) { PyErr_SetString(PyExc_SystemError, "Empty parameter name after $"); return cleanreturn(0, &freelist); } if (skip) { /* Now we know the minimal and the maximal numbers of * positional arguments and can raise an exception with * informative message (see below). */ break; } if (max < nargs) { if (max == 0) { PyErr_Format(PyExc_TypeError, "%.200s%s takes no positional arguments", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()"); } else { PyErr_Format(PyExc_TypeError, "%.200s%s takes %s %d positional argument%s" " (%zd given)", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()", (min != INT_MAX) ? "at most" : "exactly", max, max == 1 ? "" : "s", nargs); } return cleanreturn(0, &freelist); } } if (IS_END_OF_FORMAT(*format)) { PyErr_Format(PyExc_SystemError, "More keyword list entries (%d) than " "format specifiers (%d)", len, i); return cleanreturn(0, &freelist); } if (!skip) { if (i < nargs) { current_arg = PyTuple_GET_ITEM(args, i); } else if (nkwargs && i >= pos) { current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]); if (current_arg) { --nkwargs; } else if (PyErr_Occurred()) { return cleanreturn(0, &freelist); } } else { current_arg = NULL; } if (current_arg) { msg = convertitem(current_arg, &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { seterror(i+1, msg, levels, fname, custom_msg); return cleanreturn(0, &freelist); } continue; } if (i < min) { if (i < pos) { assert (min == INT_MAX); assert (max == INT_MAX); skip = 1; /* At that moment we still don't know the minimal and * the maximal numbers of positional arguments. Raising * an exception is deferred until we encounter | and $ * or the end of the format. */ } else { PyErr_Format(PyExc_TypeError, "%.200s%s missing required " "argument '%s' (pos %d)", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()", kwlist[i], i+1); return cleanreturn(0, &freelist); } } /* current code reports success when all required args * fulfilled and no keyword args left, with no further * validation. XXX Maybe skip this in debug build ? */ if (!nkwargs && !skip) { return cleanreturn(1, &freelist); } } /* We are into optional args, skip through to any remaining * keyword args */ msg = skipitem(&format, p_va, flags); if (msg) { PyErr_Format(PyExc_SystemError, "%s: '%s'", msg, format); return cleanreturn(0, &freelist); } } if (skip) { PyErr_Format(PyExc_TypeError, "%.200s%s takes %s %d positional argument%s" " (%zd given)", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()", (Py_MIN(pos, min) < i) ? "at least" : "exactly", Py_MIN(pos, min), Py_MIN(pos, min) == 1 ? "" : "s", nargs); return cleanreturn(0, &freelist); } if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) { PyErr_Format(PyExc_SystemError, "more argument specifiers than keyword list entries " "(remaining format:'%s')", format); return cleanreturn(0, &freelist); } if (nkwargs > 0) { PyObject *key; Py_ssize_t j; /* make sure there are no arguments given by name and position */ for (i = pos; i < nargs; i++) { current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]); if (current_arg) { /* arg present in tuple and in dict */ PyErr_Format(PyExc_TypeError, "argument for %.200s%s given by name ('%s') " "and position (%d)", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()", kwlist[i], i+1); return cleanreturn(0, &freelist); } else if (PyErr_Occurred()) { return cleanreturn(0, &freelist); } } /* make sure there are no extraneous keyword arguments */ j = 0; while (PyDict_Next(kwargs, &j, &key, NULL)) { int match = 0; if (!PyUnicode_Check(key)) { PyErr_SetString(PyExc_TypeError, "keywords must be strings"); return cleanreturn(0, &freelist); } for (i = pos; i < len; i++) { if (_PyUnicode_EqualToASCIIString(key, kwlist[i])) { match = 1; break; } } if (!match) { PyErr_Format(PyExc_TypeError, "'%U' is an invalid keyword " "argument for %.200s%s", key, (fname == NULL) ? "this function" : fname, (fname == NULL) ? "" : "()"); return cleanreturn(0, &freelist); } } /* Something wrong happened. There are extraneous keyword arguments, * but we don't know what. And we don't bother. */ PyErr_Format(PyExc_TypeError, "invalid keyword argument for %.200s%s", (fname == NULL) ? "this function" : fname, (fname == NULL) ? "" : "()"); return cleanreturn(0, &freelist); } return cleanreturn(1, &freelist); } static int scan_keywords(const char * const *keywords, int *ptotal, int *pposonly) { /* scan keywords and count the number of positional-only parameters */ int i; for (i = 0; keywords[i] && !*keywords[i]; i++) { } *pposonly = i; /* scan keywords and get greatest possible nbr of args */ for (; keywords[i]; i++) { if (!*keywords[i]) { PyErr_SetString(PyExc_SystemError, "Empty keyword parameter name"); return -1; } } *ptotal = i; return 0; } static int parse_format(const char *format, int total, int npos, const char **pfname, const char **pcustommsg, int *pmin, int *pmax) { /* grab the function name or custom error msg first (mutually exclusive) */ const char *custommsg; const char *fname = strchr(format, ':'); if (fname) { fname++; custommsg = NULL; } else { custommsg = strchr(format,';'); if (custommsg) { custommsg++; } } int min = INT_MAX; int max = INT_MAX; for (int i = 0; i < total; i++) { if (*format == '|') { if (min != INT_MAX) { PyErr_SetString(PyExc_SystemError, "Invalid format string (| specified twice)"); return -1; } if (max != INT_MAX) { PyErr_SetString(PyExc_SystemError, "Invalid format string ($ before |)"); return -1; } min = i; format++; } if (*format == '$') { if (max != INT_MAX) { PyErr_SetString(PyExc_SystemError, "Invalid format string ($ specified twice)"); return -1; } if (i < npos) { PyErr_SetString(PyExc_SystemError, "Empty parameter name after $"); return -1; } max = i; format++; } if (IS_END_OF_FORMAT(*format)) { PyErr_Format(PyExc_SystemError, "More keyword list entries (%d) than " "format specifiers (%d)", total, i); return -1; } const char *msg = skipitem(&format, NULL, 0); if (msg) { PyErr_Format(PyExc_SystemError, "%s: '%s'", msg, format); return -1; } } min = Py_MIN(min, total); max = Py_MIN(max, total); if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) { PyErr_Format(PyExc_SystemError, "more argument specifiers than keyword list entries " "(remaining format:'%s')", format); return -1; } *pfname = fname; *pcustommsg = custommsg; *pmin = min; *pmax = max; return 0; } static PyObject * new_kwtuple(const char * const *keywords, int total, int pos) { int nkw = total - pos; PyObject *kwtuple = PyTuple_New(nkw); if (kwtuple == NULL) { return NULL; } keywords += pos; for (int i = 0; i < nkw; i++) { PyObject *str = PyUnicode_FromString(keywords[i]); if (str == NULL) { Py_DECREF(kwtuple); return NULL; } PyUnicode_InternInPlace(&str); PyTuple_SET_ITEM(kwtuple, i, str); } return kwtuple; } static int _parser_init(struct _PyArg_Parser *parser) { const char * const *keywords = parser->keywords; assert(keywords != NULL); assert(parser->pos == 0 && (parser->format == NULL || parser->fname == NULL) && parser->custom_msg == NULL && parser->min == 0 && parser->max == 0); int len, pos; if (scan_keywords(keywords, &len, &pos) < 0) { return 0; } const char *fname, *custommsg = NULL; int min = 0, max = 0; if (parser->format) { assert(parser->fname == NULL); if (parse_format(parser->format, len, pos, &fname, &custommsg, &min, &max) < 0) { return 0; } } else { assert(parser->fname != NULL); fname = parser->fname; } int owned; PyObject *kwtuple = parser->kwtuple; if (kwtuple == NULL) { kwtuple = new_kwtuple(keywords, len, pos); if (kwtuple == NULL) { return 0; } owned = 1; } else { owned = 0; } parser->pos = pos; parser->fname = fname; parser->custom_msg = custommsg; parser->min = min; parser->max = max; parser->kwtuple = kwtuple; parser->initialized = owned ? 1 : -1; assert(parser->next == NULL); parser->next = _PyRuntime.getargs.static_parsers; _PyRuntime.getargs.static_parsers = parser; return 1; } static int parser_init(struct _PyArg_Parser *parser) { // volatile as it can be modified by other threads // and should not be optimized or reordered by compiler if (*((volatile int *)&parser->initialized)) { assert(parser->kwtuple != NULL); return 1; } PyThread_acquire_lock(_PyRuntime.getargs.mutex, WAIT_LOCK); // Check again if another thread initialized the parser // while we were waiting for the lock. if (*((volatile int *)&parser->initialized)) { assert(parser->kwtuple != NULL); PyThread_release_lock(_PyRuntime.getargs.mutex); return 1; } int ret = _parser_init(parser); PyThread_release_lock(_PyRuntime.getargs.mutex); return ret; } static void parser_clear(struct _PyArg_Parser *parser) { if (parser->initialized == 1) { Py_CLEAR(parser->kwtuple); } } static PyObject* find_keyword(PyObject *kwnames, PyObject *const *kwstack, PyObject *key) { Py_ssize_t i, nkwargs; nkwargs = PyTuple_GET_SIZE(kwnames); for (i = 0; i < nkwargs; i++) { PyObject *kwname = PyTuple_GET_ITEM(kwnames, i); /* kwname == key will normally find a match in since keyword keys should be interned strings; if not retry below in a new loop. */ if (kwname == key) { return kwstack[i]; } } for (i = 0; i < nkwargs; i++) { PyObject *kwname = PyTuple_GET_ITEM(kwnames, i); assert(PyUnicode_Check(kwname)); if (_PyUnicode_EQ(kwname, key)) { return kwstack[i]; } } return NULL; } static int vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs, PyObject *kwnames, struct _PyArg_Parser *parser, va_list *p_va, int flags) { PyObject *kwtuple; char msgbuf[512]; int levels[32]; const char *format; const char *msg; PyObject *keyword; int i, pos, len; Py_ssize_t nkwargs; PyObject *current_arg; freelistentry_t static_entries[STATIC_FREELIST_ENTRIES]; freelist_t freelist; PyObject *const *kwstack = NULL; freelist.entries = static_entries; freelist.first_available = 0; freelist.entries_malloced = 0; assert(kwargs == NULL || PyDict_Check(kwargs)); assert(kwargs == NULL || kwnames == NULL); assert(p_va != NULL); if (parser == NULL) { PyErr_BadInternalCall(); return 0; } if (kwnames != NULL && !PyTuple_Check(kwnames)) { PyErr_BadInternalCall(); return 0; } if (!parser_init(parser)) { return 0; } kwtuple = parser->kwtuple; pos = parser->pos; len = pos + (int)PyTuple_GET_SIZE(kwtuple); if (len > STATIC_FREELIST_ENTRIES) { freelist.entries = PyMem_NEW(freelistentry_t, len); if (freelist.entries == NULL) { PyErr_NoMemory(); return 0; } freelist.entries_malloced = 1; } if (kwargs != NULL) { nkwargs = PyDict_GET_SIZE(kwargs); } else if (kwnames != NULL) { nkwargs = PyTuple_GET_SIZE(kwnames); kwstack = args + nargs; } else { nkwargs = 0; } if (nargs + nkwargs > len) { /* Adding "keyword" (when nargs == 0) prevents producing wrong error messages in some special cases (see bpo-31229). */ PyErr_Format(PyExc_TypeError, "%.200s%s takes at most %d %sargument%s (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", len, (nargs == 0) ? "keyword " : "", (len == 1) ? "" : "s", nargs + nkwargs); return cleanreturn(0, &freelist); } if (parser->max < nargs) { if (parser->max == 0) { PyErr_Format(PyExc_TypeError, "%.200s%s takes no positional arguments", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()"); } else { PyErr_Format(PyExc_TypeError, "%.200s%s takes %s %d positional argument%s (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", (parser->min < parser->max) ? "at most" : "exactly", parser->max, parser->max == 1 ? "" : "s", nargs); } return cleanreturn(0, &freelist); } format = parser->format; assert(format != NULL || len == 0); /* convert tuple args and keyword args in same loop, using kwtuple to drive process */ for (i = 0; i < len; i++) { if (*format == '|') { format++; } if (*format == '$') { format++; } assert(!IS_END_OF_FORMAT(*format)); if (i < nargs) { current_arg = args[i]; } else if (nkwargs && i >= pos) { keyword = PyTuple_GET_ITEM(kwtuple, i - pos); if (kwargs != NULL) { current_arg = PyDict_GetItemWithError(kwargs, keyword); if (!current_arg && PyErr_Occurred()) { return cleanreturn(0, &freelist); } } else { current_arg = find_keyword(kwnames, kwstack, keyword); } if (current_arg) { --nkwargs; } } else { current_arg = NULL; } if (current_arg) { msg = convertitem(current_arg, &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { seterror(i+1, msg, levels, parser->fname, parser->custom_msg); return cleanreturn(0, &freelist); } continue; } if (i < parser->min) { /* Less arguments than required */ if (i < pos) { Py_ssize_t min = Py_MIN(pos, parser->min); PyErr_Format(PyExc_TypeError, "%.200s%s takes %s %d positional argument%s" " (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", min < parser->max ? "at least" : "exactly", min, min == 1 ? "" : "s", nargs); } else { keyword = PyTuple_GET_ITEM(kwtuple, i - pos); PyErr_Format(PyExc_TypeError, "%.200s%s missing required " "argument '%U' (pos %d)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", keyword, i+1); } return cleanreturn(0, &freelist); } /* current code reports success when all required args * fulfilled and no keyword args left, with no further * validation. XXX Maybe skip this in debug build ? */ if (!nkwargs) { return cleanreturn(1, &freelist); } /* We are into optional args, skip through to any remaining * keyword args */ msg = skipitem(&format, p_va, flags); assert(msg == NULL); } assert(IS_END_OF_FORMAT(*format) || (*format == '|') || (*format == '$')); if (nkwargs > 0) { /* make sure there are no arguments given by name and position */ for (i = pos; i < nargs; i++) { keyword = PyTuple_GET_ITEM(kwtuple, i - pos); if (kwargs != NULL) { current_arg = PyDict_GetItemWithError(kwargs, keyword); if (!current_arg && PyErr_Occurred()) { return cleanreturn(0, &freelist); } } else { current_arg = find_keyword(kwnames, kwstack, keyword); } if (current_arg) { /* arg present in tuple and in dict */ PyErr_Format(PyExc_TypeError, "argument for %.200s%s given by name ('%U') " "and position (%d)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", keyword, i+1); return cleanreturn(0, &freelist); } } error_unexpected_keyword_arg(kwargs, kwnames, kwtuple, parser->fname); return cleanreturn(0, &freelist); } return cleanreturn(1, &freelist); } static int vgetargskeywordsfast(PyObject *args, PyObject *keywords, struct _PyArg_Parser *parser, va_list *p_va, int flags) { PyObject **stack; Py_ssize_t nargs; if (args == NULL || !PyTuple_Check(args) || (keywords != NULL && !PyDict_Check(keywords))) { PyErr_BadInternalCall(); return 0; } stack = _PyTuple_ITEMS(args); nargs = PyTuple_GET_SIZE(args); return vgetargskeywordsfast_impl(stack, nargs, keywords, NULL, parser, p_va, flags); } #undef _PyArg_UnpackKeywords PyObject * const * _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs, PyObject *kwnames, struct _PyArg_Parser *parser, int minpos, int maxpos, int minkw, PyObject **buf) { PyObject *kwtuple; PyObject *keyword; int i, posonly, minposonly, maxargs; int reqlimit = minkw ? maxpos + minkw : minpos; Py_ssize_t nkwargs; PyObject *current_arg; PyObject * const *kwstack = NULL; assert(kwargs == NULL || PyDict_Check(kwargs)); assert(kwargs == NULL || kwnames == NULL); if (parser == NULL) { PyErr_BadInternalCall(); return NULL; } if (kwnames != NULL && !PyTuple_Check(kwnames)) { PyErr_BadInternalCall(); return NULL; } if (args == NULL && nargs == 0) { args = buf; } if (!parser_init(parser)) { return NULL; } kwtuple = parser->kwtuple; posonly = parser->pos; minposonly = Py_MIN(posonly, minpos); maxargs = posonly + (int)PyTuple_GET_SIZE(kwtuple); if (kwargs != NULL) { nkwargs = PyDict_GET_SIZE(kwargs); } else if (kwnames != NULL) { nkwargs = PyTuple_GET_SIZE(kwnames); kwstack = args + nargs; } else { nkwargs = 0; } if (nkwargs == 0 && minkw == 0 && minpos <= nargs && nargs <= maxpos) { /* Fast path. */ return args; } if (nargs + nkwargs > maxargs) { /* Adding "keyword" (when nargs == 0) prevents producing wrong error messages in some special cases (see bpo-31229). */ PyErr_Format(PyExc_TypeError, "%.200s%s takes at most %d %sargument%s (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", maxargs, (nargs == 0) ? "keyword " : "", (maxargs == 1) ? "" : "s", nargs + nkwargs); return NULL; } if (nargs > maxpos) { if (maxpos == 0) { PyErr_Format(PyExc_TypeError, "%.200s%s takes no positional arguments", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()"); } else { PyErr_Format(PyExc_TypeError, "%.200s%s takes %s %d positional argument%s (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", (minpos < maxpos) ? "at most" : "exactly", maxpos, (maxpos == 1) ? "" : "s", nargs); } return NULL; } if (nargs < minposonly) { PyErr_Format(PyExc_TypeError, "%.200s%s takes %s %d positional argument%s" " (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", minposonly < maxpos ? "at least" : "exactly", minposonly, minposonly == 1 ? "" : "s", nargs); return NULL; } /* copy tuple args */ for (i = 0; i < nargs; i++) { buf[i] = args[i]; } /* copy keyword args using kwtuple to drive process */ for (i = Py_MAX((int)nargs, posonly); i < maxargs; i++) { if (nkwargs) { keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); if (kwargs != NULL) { current_arg = PyDict_GetItemWithError(kwargs, keyword); if (!current_arg && PyErr_Occurred()) { return NULL; } } else { current_arg = find_keyword(kwnames, kwstack, keyword); } } else if (i >= reqlimit) { break; } else { current_arg = NULL; } buf[i] = current_arg; if (current_arg) { --nkwargs; } else if (i < minpos || (maxpos <= i && i < reqlimit)) { /* Less arguments than required */ keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); PyErr_Format(PyExc_TypeError, "%.200s%s missing required " "argument '%U' (pos %d)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", keyword, i+1); return NULL; } } if (nkwargs > 0) { /* make sure there are no arguments given by name and position */ for (i = posonly; i < nargs; i++) { keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); if (kwargs != NULL) { current_arg = PyDict_GetItemWithError(kwargs, keyword); if (!current_arg && PyErr_Occurred()) { return NULL; } } else { current_arg = find_keyword(kwnames, kwstack, keyword); } if (current_arg) { /* arg present in tuple and in dict */ PyErr_Format(PyExc_TypeError, "argument for %.200s%s given by name ('%U') " "and position (%d)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", keyword, i+1); return NULL; } } error_unexpected_keyword_arg(kwargs, kwnames, kwtuple, parser->fname); return NULL; } return buf; } PyObject * const * _PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs, PyObject *kwnames, struct _PyArg_Parser *parser, int minpos, int maxpos, int minkw, int vararg, PyObject **buf) { PyObject *kwtuple; PyObject *keyword; Py_ssize_t varargssize = 0; int i, posonly, minposonly, maxargs; int reqlimit = minkw ? maxpos + minkw : minpos; Py_ssize_t nkwargs; PyObject *current_arg; PyObject * const *kwstack = NULL; assert(kwargs == NULL || PyDict_Check(kwargs)); assert(kwargs == NULL || kwnames == NULL); if (parser == NULL) { PyErr_BadInternalCall(); return NULL; } if (kwnames != NULL && !PyTuple_Check(kwnames)) { PyErr_BadInternalCall(); return NULL; } if (args == NULL && nargs == 0) { args = buf; } if (!parser_init(parser)) { return NULL; } kwtuple = parser->kwtuple; posonly = parser->pos; minposonly = Py_MIN(posonly, minpos); maxargs = posonly + (int)PyTuple_GET_SIZE(kwtuple); if (kwargs != NULL) { nkwargs = PyDict_GET_SIZE(kwargs); } else if (kwnames != NULL) { nkwargs = PyTuple_GET_SIZE(kwnames); kwstack = args + nargs; } else { nkwargs = 0; } if (nargs < minposonly) { PyErr_Format(PyExc_TypeError, "%.200s%s takes %s %d positional argument%s" " (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", minposonly < maxpos ? "at least" : "exactly", minposonly, minposonly == 1 ? "" : "s", nargs); return NULL; } /* create varargs tuple */ varargssize = nargs - maxpos; if (varargssize < 0) { varargssize = 0; } buf[vararg] = PyTuple_New(varargssize); if (!buf[vararg]) { return NULL; } /* copy tuple args */ for (i = 0; i < nargs; i++) { if (i >= vararg) { PyTuple_SET_ITEM(buf[vararg], i - vararg, Py_NewRef(args[i])); continue; } else { buf[i] = args[i]; } } /* copy keyword args using kwtuple to drive process */ for (i = Py_MAX((int)nargs, posonly) - Py_SAFE_DOWNCAST(varargssize, Py_ssize_t, int); i < maxargs; i++) { if (nkwargs) { keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); if (kwargs != NULL) { current_arg = PyDict_GetItemWithError(kwargs, keyword); if (!current_arg && PyErr_Occurred()) { goto exit; } } else { current_arg = find_keyword(kwnames, kwstack, keyword); } } else { current_arg = NULL; } /* If an arguments is passed in as a keyword argument, * it should be placed before `buf[vararg]`. * * For example: * def f(a, /, b, *args): * pass * f(1, b=2) * * This `buf` array should be: [1, 2, NULL]. * In this case, nargs < vararg. * * Otherwise, we leave a place at `buf[vararg]` for vararg tuple * so the index is `i + 1`. */ if (nargs < vararg) { buf[i] = current_arg; } else { buf[i + 1] = current_arg; } if (current_arg) { --nkwargs; } else if (i < minpos || (maxpos <= i && i < reqlimit)) { /* Less arguments than required */ keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); PyErr_Format(PyExc_TypeError, "%.200s%s missing required " "argument '%U' (pos %d)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", keyword, i+1); goto exit; } } if (nkwargs > 0) { error_unexpected_keyword_arg(kwargs, kwnames, kwtuple, parser->fname); goto exit; } return buf; exit: Py_XDECREF(buf[vararg]); return NULL; } static const char * skipitem(const char **p_format, va_list *p_va, int flags) { const char *format = *p_format; char c = *format++; switch (c) { /* * codes that take a single data pointer as an argument * (the type of the pointer is irrelevant) */ case 'b': /* byte -- very short int */ case 'B': /* byte as bitfield */ case 'h': /* short int */ case 'H': /* short int as bitfield */ case 'i': /* int */ case 'I': /* int sized bitfield */ case 'l': /* long int */ case 'k': /* long int sized bitfield */ case 'L': /* long long */ case 'K': /* long long sized bitfield */ case 'n': /* Py_ssize_t */ case 'f': /* float */ case 'd': /* double */ case 'D': /* complex double */ case 'c': /* char */ case 'C': /* unicode char */ case 'p': /* boolean predicate */ case 'S': /* string object */ case 'Y': /* string object */ case 'U': /* unicode string object */ { if (p_va != NULL) { (void) va_arg(*p_va, void *); } break; } /* string codes */ case 'e': /* string with encoding */ { if (p_va != NULL) { (void) va_arg(*p_va, const char *); } if (!(*format == 's' || *format == 't')) /* after 'e', only 's' and 't' is allowed */ goto err; format++; } /* fall through */ case 's': /* string */ case 'z': /* string or None */ case 'y': /* bytes */ case 'w': /* buffer, read-write */ { if (p_va != NULL) { (void) va_arg(*p_va, char **); } if (*format == '#') { if (p_va != NULL) { (void) va_arg(*p_va, Py_ssize_t *); } format++; } else if ((c == 's' || c == 'z' || c == 'y' || c == 'w') && *format == '*') { format++; } break; } case 'O': /* object */ { if (*format == '!') { format++; if (p_va != NULL) { (void) va_arg(*p_va, PyTypeObject*); (void) va_arg(*p_va, PyObject **); } } else if (*format == '&') { typedef int (*converter)(PyObject *, void *); if (p_va != NULL) { (void) va_arg(*p_va, converter); (void) va_arg(*p_va, void *); } format++; } else { if (p_va != NULL) { (void) va_arg(*p_va, PyObject **); } } break; } case '(': /* bypass tuple, not handled at all previously */ { const char *msg; for (;;) { if (*format==')') break; if (IS_END_OF_FORMAT(*format)) return "Unmatched left paren in format " "string"; msg = skipitem(&format, p_va, flags); if (msg) return msg; } format++; break; } case ')': return "Unmatched right paren in format string"; default: err: return "impossible"; } *p_format = format; return NULL; } #undef _PyArg_CheckPositional int _PyArg_CheckPositional(const char *name, Py_ssize_t nargs, Py_ssize_t min, Py_ssize_t max) { assert(min >= 0); assert(min <= max); if (nargs < min) { if (name != NULL) PyErr_Format( PyExc_TypeError, "%.200s expected %s%zd argument%s, got %zd", name, (min == max ? "" : "at least "), min, min == 1 ? "" : "s", nargs); else PyErr_Format( PyExc_TypeError, "unpacked tuple should have %s%zd element%s," " but has %zd", (min == max ? "" : "at least "), min, min == 1 ? "" : "s", nargs); return 0; } if (nargs == 0) { return 1; } if (nargs > max) { if (name != NULL) PyErr_Format( PyExc_TypeError, "%.200s expected %s%zd argument%s, got %zd", name, (min == max ? "" : "at most "), max, max == 1 ? "" : "s", nargs); else PyErr_Format( PyExc_TypeError, "unpacked tuple should have %s%zd element%s," " but has %zd", (min == max ? "" : "at most "), max, max == 1 ? "" : "s", nargs); return 0; } return 1; } static int unpack_stack(PyObject *const *args, Py_ssize_t nargs, const char *name, Py_ssize_t min, Py_ssize_t max, va_list vargs) { Py_ssize_t i; PyObject **o; if (!_PyArg_CheckPositional(name, nargs, min, max)) { return 0; } for (i = 0; i < nargs; i++) { o = va_arg(vargs, PyObject **); *o = args[i]; } return 1; } int PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...) { PyObject **stack; Py_ssize_t nargs; int retval; va_list vargs; if (!PyTuple_Check(args)) { PyErr_SetString(PyExc_SystemError, "PyArg_UnpackTuple() argument list is not a tuple"); return 0; } stack = _PyTuple_ITEMS(args); nargs = PyTuple_GET_SIZE(args); va_start(vargs, max); retval = unpack_stack(stack, nargs, name, min, max, vargs); va_end(vargs); return retval; } int _PyArg_UnpackStack(PyObject *const *args, Py_ssize_t nargs, const char *name, Py_ssize_t min, Py_ssize_t max, ...) { int retval; va_list vargs; va_start(vargs, max); retval = unpack_stack(args, nargs, name, min, max, vargs); va_end(vargs); return retval; } #undef _PyArg_NoKeywords #undef _PyArg_NoKwnames #undef _PyArg_NoPositional /* For type constructors that don't take keyword args * * Sets a TypeError and returns 0 if the args/kwargs is * not empty, returns 1 otherwise */ int _PyArg_NoKeywords(const char *funcname, PyObject *kwargs) { if (kwargs == NULL) { return 1; } if (!PyDict_CheckExact(kwargs)) { PyErr_BadInternalCall(); return 0; } if (PyDict_GET_SIZE(kwargs) == 0) { return 1; } PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", funcname); return 0; } int _PyArg_NoPositional(const char *funcname, PyObject *args) { if (args == NULL) return 1; if (!PyTuple_CheckExact(args)) { PyErr_BadInternalCall(); return 0; } if (PyTuple_GET_SIZE(args) == 0) return 1; PyErr_Format(PyExc_TypeError, "%.200s() takes no positional arguments", funcname); return 0; } int _PyArg_NoKwnames(const char *funcname, PyObject *kwnames) { if (kwnames == NULL) { return 1; } assert(PyTuple_CheckExact(kwnames)); if (PyTuple_GET_SIZE(kwnames) == 0) { return 1; } PyErr_Format(PyExc_TypeError, "%s() takes no keyword arguments", funcname); return 0; } void _PyArg_Fini(void) { struct _PyArg_Parser *tmp, *s = _PyRuntime.getargs.static_parsers; while (s) { tmp = s->next; s->next = NULL; parser_clear(s); s = tmp; } _PyRuntime.getargs.static_parsers = NULL; } #ifdef __cplusplus }; #endif ================================================ FILE: GetCompiler.c ================================================ /* Return the compiler identification, if possible. */ #include "Python.h" #ifndef COMPILER // Note the __clang__ conditional has to come before the __GNUC__ one because // clang pretends to be GCC. #if defined(__clang__) #define COMPILER "[Clang " __clang_version__ "]" #elif defined(__GNUC__) #define COMPILER "[GCC " __VERSION__ "]" // Generic fallbacks. #elif defined(__cplusplus) #define COMPILER "[C++]" #else #define COMPILER "[C]" #endif #endif /* !COMPILER */ const char * Py_GetCompiler(void) { return COMPILER; } ================================================ FILE: GetCopyRight.c ================================================ /* Return the copyright string. This is updated manually. */ #include "Python.h" static const char cprt[] = "\ Copyright (c) 2001-2023 Python Software Foundation.\n\ All Rights Reserved.\n\ \n\ Copyright (c) 2000 BeOpen.com.\n\ All Rights Reserved.\n\ \n\ Copyright (c) 1995-2001 Corporation for National Research Initiatives.\n\ All Rights Reserved.\n\ \n\ Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.\n\ All Rights Reserved."; const char * Py_GetCopyright(void) { return cprt; } ================================================ FILE: GetCopyright.c ================================================ /* Return the copyright string. This is updated manually. */ #include "Python.h" static const char cprt[] = "\ Copyright (c) 2001-2023 Python Software Foundation.\n\ All Rights Reserved.\n\ \n\ Copyright (c) 2000 BeOpen.com.\n\ All Rights Reserved.\n\ \n\ Copyright (c) 1995-2001 Corporation for National Research Initiatives.\n\ All Rights Reserved.\n\ \n\ Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.\n\ All Rights Reserved."; const char * Py_GetCopyright(void) { return cprt; } ================================================ FILE: GetOpt.c ================================================ /*---------------------------------------------------------------------------* * * * C++ Library * * Copyright 1992-1994, David Gottner * * All Rights Reserved * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice, this permission notice and * the following disclaimer notice appear unmodified in all copies. * * I DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL I * BE LIABLE FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *---------------------------------------------------------------------------*/ /* Modified to support --help and --version, as well as /? on Windows * by Georg Brandl. */ #include #include #include #include #include "pycore_getopt.h" #ifdef __cplusplus extern "C" { #endif int _PyOS_opterr = 1; /* generate error messages */ Py_ssize_t _PyOS_optind = 1; /* index into argv array */ const wchar_t *_PyOS_optarg = NULL; /* optional argument */ static const wchar_t *opt_ptr = L""; /* Python command line short and long options */ #define SHORT_OPTS L"bBc:dEhiIJm:OPqRsStuvVW:xX:?" static const _PyOS_LongOption longopts[] = { /* name, has_arg, val (used in switch in initconfig.c) */ {L"check-hash-based-pycs", 1, 0}, {L"help-all", 0, 1}, {L"help-env", 0, 2}, {L"help-xoptions", 0, 3}, {NULL, 0, -1}, /* sentinel */ }; void _PyOS_ResetGetOpt(void) { _PyOS_opterr = 1; _PyOS_optind = 1; _PyOS_optarg = NULL; opt_ptr = L""; } int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex) { wchar_t *ptr; wchar_t option; if (*opt_ptr == '\0') { if (_PyOS_optind >= argc) return -1; #ifdef MS_WINDOWS else if (wcscmp(argv[_PyOS_optind], L"/?") == 0) { ++_PyOS_optind; return 'h'; } #endif else if (argv[_PyOS_optind][0] != L'-' || argv[_PyOS_optind][1] == L'\0' /* lone dash */ ) return -1; else if (wcscmp(argv[_PyOS_optind], L"--") == 0) { ++_PyOS_optind; return -1; } else if (wcscmp(argv[_PyOS_optind], L"--help") == 0) { ++_PyOS_optind; return 'h'; } else if (wcscmp(argv[_PyOS_optind], L"--version") == 0) { ++_PyOS_optind; return 'V'; } opt_ptr = &argv[_PyOS_optind++][1]; } if ((option = *opt_ptr++) == L'\0') return -1; if (option == L'-') { // Parse long option. if (*opt_ptr == L'\0') { if (_PyOS_opterr) { fprintf(stderr, "expected long option\n"); } return -1; } *longindex = 0; const _PyOS_LongOption *opt; for (opt = &longopts[*longindex]; opt->name; opt = &longopts[++(*longindex)]) { if (!wcscmp(opt->name, opt_ptr)) break; } if (!opt->name) { if (_PyOS_opterr) { fprintf(stderr, "unknown option %ls\n", argv[_PyOS_optind - 1]); } return '_'; } opt_ptr = L""; if (!opt->has_arg) { return opt->val; } if (_PyOS_optind >= argc) { if (_PyOS_opterr) { fprintf(stderr, "Argument expected for the %ls options\n", argv[_PyOS_optind - 1]); } return '_'; } _PyOS_optarg = argv[_PyOS_optind++]; return opt->val; } if (option == 'J') { if (_PyOS_opterr) { fprintf(stderr, "-J is reserved for Jython\n"); } return '_'; } if ((ptr = wcschr(SHORT_OPTS, option)) == NULL) { if (_PyOS_opterr) { fprintf(stderr, "Unknown option: -%c\n", (char)option); } return '_'; } if (*(ptr + 1) == L':') { if (*opt_ptr != L'\0') { _PyOS_optarg = opt_ptr; opt_ptr = L""; } else { if (_PyOS_optind >= argc) { if (_PyOS_opterr) { fprintf(stderr, "Argument expected for the -%c option\n", (char)option); } return '_'; } _PyOS_optarg = argv[_PyOS_optind++]; } } return option; } #ifdef __cplusplus } #endif ================================================ FILE: GetPlatForm.c ================================================ #include "Python.h" #ifndef PLATFORM #define PLATFORM "unknown" #endif const char * Py_GetPlatform(void) { return PLATFORM; } ================================================ FILE: GetVersion.c ================================================ /* Return the full version string. */ #include "Python.h" #include "patchlevel.h" static int initialized = 0; static char version[250]; void _Py_InitVersion(void) { if (initialized) { return; } initialized = 1; PyOS_snprintf(version, sizeof(version), "%.80s (%.80s) %.80s", PY_VERSION, Py_GetBuildInfo(), Py_GetCompiler()); } const char * Py_GetVersion(void) { _Py_InitVersion(); return version; } // Export the Python hex version as a constant. const unsigned long Py_Version = PY_VERSION_HEX; ================================================ FILE: Get_Compiler.c ================================================ /* Return the compiler identification, if possible. */ #include "Python.h" #ifndef COMPILER // Note the __clang__ conditional has to come before the __GNUC__ one because // clang pretends to be GCC. #if defined(__clang__) #define COMPILER "[Clang " __clang_version__ "]" #elif defined(__GNUC__) #define COMPILER "[GCC " __VERSION__ "]" // Generic fallbacks. #elif defined(__cplusplus) #define COMPILER "[C++]" #else #define COMPILER "[C]" #endif #endif /* !COMPILER */ const char * Py_GetCompiler(void) { return COMPILER; } ================================================ FILE: Get_Opt.c ================================================ /*---------------------------------------------------------------------------* * * * C++ Library * * Copyright 1992-1994, David Gottner * * All Rights Reserved * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice, this permission notice and * the following disclaimer notice appear unmodified in all copies. * * I DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL I * BE LIABLE FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *---------------------------------------------------------------------------*/ /* Modified to support --help and --version, as well as /? on Windows * by Georg Brandl. */ #include #include #include #include #include "pycore_getopt.h" #ifdef __cplusplus extern "C" { #endif int _PyOS_opterr = 1; /* generate error messages */ Py_ssize_t _PyOS_optind = 1; /* index into argv array */ const wchar_t *_PyOS_optarg = NULL; /* optional argument */ static const wchar_t *opt_ptr = L""; /* Python command line short and long options */ #define SHORT_OPTS L"bBc:dEhiIJm:OPqRsStuvVW:xX:?" static const _PyOS_LongOption longopts[] = { /* name, has_arg, val (used in switch in initconfig.c) */ {L"check-hash-based-pycs", 1, 0}, {L"help-all", 0, 1}, {L"help-env", 0, 2}, {L"help-xoptions", 0, 3}, {NULL, 0, -1}, /* sentinel */ }; void _PyOS_ResetGetOpt(void) { _PyOS_opterr = 1; _PyOS_optind = 1; _PyOS_optarg = NULL; opt_ptr = L""; } int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex) { wchar_t *ptr; wchar_t option; if (*opt_ptr == '\0') { if (_PyOS_optind >= argc) return -1; #ifdef MS_WINDOWS else if (wcscmp(argv[_PyOS_optind], L"/?") == 0) { ++_PyOS_optind; return 'h'; } #endif else if (argv[_PyOS_optind][0] != L'-' || argv[_PyOS_optind][1] == L'\0' /* lone dash */ ) return -1; else if (wcscmp(argv[_PyOS_optind], L"--") == 0) { ++_PyOS_optind; return -1; } else if (wcscmp(argv[_PyOS_optind], L"--help") == 0) { ++_PyOS_optind; return 'h'; } else if (wcscmp(argv[_PyOS_optind], L"--version") == 0) { ++_PyOS_optind; return 'V'; } opt_ptr = &argv[_PyOS_optind++][1]; } if ((option = *opt_ptr++) == L'\0') return -1; if (option == L'-') { // Parse long option. if (*opt_ptr == L'\0') { if (_PyOS_opterr) { fprintf(stderr, "expected long option\n"); } return -1; } *longindex = 0; const _PyOS_LongOption *opt; for (opt = &longopts[*longindex]; opt->name; opt = &longopts[++(*longindex)]) { if (!wcscmp(opt->name, opt_ptr)) break; } if (!opt->name) { if (_PyOS_opterr) { fprintf(stderr, "unknown option %ls\n", argv[_PyOS_optind - 1]); } return '_'; } opt_ptr = L""; if (!opt->has_arg) { return opt->val; } if (_PyOS_optind >= argc) { if (_PyOS_opterr) { fprintf(stderr, "Argument expected for the %ls options\n", argv[_PyOS_optind - 1]); } return '_'; } _PyOS_optarg = argv[_PyOS_optind++]; return opt->val; } if (option == 'J') { if (_PyOS_opterr) { fprintf(stderr, "-J is reserved for Jython\n"); } return '_'; } if ((ptr = wcschr(SHORT_OPTS, option)) == NULL) { if (_PyOS_opterr) { fprintf(stderr, "Unknown option: -%c\n", (char)option); } return '_'; } if (*(ptr + 1) == L':') { if (*opt_ptr != L'\0') { _PyOS_optarg = opt_ptr; opt_ptr = L""; } else { if (_PyOS_optind >= argc) { if (_PyOS_opterr) { fprintf(stderr, "Argument expected for the -%c option\n", (char)option); } return '_'; } _PyOS_optarg = argv[_PyOS_optind++]; } } return option; } #ifdef __cplusplus } #endif ================================================ FILE: Get_Plat_Form.c ================================================ #include "Python.h" #ifndef PLATFORM #define PLATFORM "unknown" #endif const char * Py_GetPlatform(void) { return PLATFORM; } ================================================ FILE: Getversion.c ================================================ /* Return the full version string. */ #include "Python.h" #include "patchlevel.h" static int initialized = 0; static char version[250]; void _Py_InitVersion(void) { if (initialized) { return; } initialized = 1; PyOS_snprintf(version, sizeof(version), "%.80s (%.80s) %.80s", PY_VERSION, Py_GetBuildInfo(), Py_GetCompiler()); } const char * Py_GetVersion(void) { _Py_InitVersion(); return version; } // Export the Python hex version as a constant. const unsigned long Py_Version = PY_VERSION_HEX; ================================================ FILE: Hamt.c ================================================ #include "Python.h" #include "pycore_bitutils.h" // _Py_popcount32 #include "pycore_hamt.h" #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_object.h" // _PyObject_GC_TRACK() #include // offsetof() /* This file provides an implementation of an immutable mapping using the Hash Array Mapped Trie (or HAMT) datastructure. This design allows to have: 1. Efficient copy: immutable mappings can be copied by reference, making it an O(1) operation. 2. Efficient mutations: due to structural sharing, only a portion of the trie needs to be copied when the collection is mutated. The cost of set/delete operations is O(log N). 3. Efficient lookups: O(log N). (where N is number of key/value items in the immutable mapping.) HAMT ==== The core idea of HAMT is that the shape of the trie is encoded into the hashes of keys. Say we want to store a K/V pair in our mapping. First, we calculate the hash of K, let's say it's 19830128, or in binary: 0b1001011101001010101110000 = 19830128 Now let's partition this bit representation of the hash into blocks of 5 bits each: 0b00_00000_10010_11101_00101_01011_10000 = 19830128 (6) (5) (4) (3) (2) (1) Each block of 5 bits represents a number between 0 and 31. So if we have a tree that consists of nodes, each of which is an array of 32 pointers, those 5-bit blocks will encode a position on a single tree level. For example, storing the key K with hash 19830128, results in the following tree structure: (array of 32 pointers) +---+ -- +----+----+----+ -- +----+ root node | 0 | .. | 15 | 16 | 17 | .. | 31 | 0b10000 = 16 (1) (level 1) +---+ -- +----+----+----+ -- +----+ | +---+ -- +----+----+----+ -- +----+ a 2nd level node | 0 | .. | 10 | 11 | 12 | .. | 31 | 0b01011 = 11 (2) +---+ -- +----+----+----+ -- +----+ | +---+ -- +----+----+----+ -- +----+ a 3rd level node | 0 | .. | 04 | 05 | 06 | .. | 31 | 0b00101 = 5 (3) +---+ -- +----+----+----+ -- +----+ | +---+ -- +----+----+----+----+ a 4th level node | 0 | .. | 04 | 29 | 30 | 31 | 0b11101 = 29 (4) +---+ -- +----+----+----+----+ | +---+ -- +----+----+----+ -- +----+ a 5th level node | 0 | .. | 17 | 18 | 19 | .. | 31 | 0b10010 = 18 (5) +---+ -- +----+----+----+ -- +----+ | +--------------+ | +---+ -- +----+----+----+ -- +----+ a 6th level node | 0 | .. | 15 | 16 | 17 | .. | 31 | 0b00000 = 0 (6) +---+ -- +----+----+----+ -- +----+ | V -- our value (or collision) To rehash: for a K/V pair, the hash of K encodes where in the tree V will be stored. To optimize memory footprint and handle hash collisions, our implementation uses three different types of nodes: * A Bitmap node; * An Array node; * A Collision node. Because we implement an immutable dictionary, our nodes are also immutable. Therefore, when we need to modify a node, we copy it, and do that modification to the copy. Array Nodes ----------- These nodes are very simple. Essentially they are arrays of 32 pointers we used to illustrate the high-level idea in the previous section. We use Array nodes only when we need to store more than 16 pointers in a single node. Array nodes do not store key objects or value objects. They are used only as an indirection level - their pointers point to other nodes in the tree. Bitmap Node ----------- Allocating a new 32-pointers array for every node of our tree would be very expensive. Unless we store millions of keys, most of tree nodes would be very sparse. When we have less than 16 elements in a node, we don't want to use the Array node, that would mean that we waste a lot of memory. Instead, we can use bitmap compression and can have just as many pointers as we need! Bitmap nodes consist of two fields: 1. An array of pointers. If a Bitmap node holds N elements, the array will be of N pointers. 2. A 32bit integer -- a bitmap field. If an N-th bit is set in the bitmap, it means that the node has an N-th element. For example, say we need to store a 3 elements sparse array: +---+ -- +---+ -- +----+ -- +----+ | 0 | .. | 4 | .. | 11 | .. | 17 | +---+ -- +---+ -- +----+ -- +----+ | | | o1 o2 o3 We allocate a three-pointer Bitmap node. Its bitmap field will be then set to: 0b_00100_00010_00000_10000 == (1 << 17) | (1 << 11) | (1 << 4) To check if our Bitmap node has an I-th element we can do: bitmap & (1 << I) And here's a formula to calculate a position in our pointer array which would correspond to an I-th element: popcount(bitmap & ((1 << I) - 1)) Let's break it down: * `popcount` is a function that returns a number of bits set to 1; * `((1 << I) - 1)` is a mask to filter the bitmask to contain bits set to the *right* of our bit. So for our 17, 11, and 4 indexes: * bitmap & ((1 << 17) - 1) == 0b100000010000 => 2 bits are set => index is 2. * bitmap & ((1 << 11) - 1) == 0b10000 => 1 bit is set => index is 1. * bitmap & ((1 << 4) - 1) == 0b0 => 0 bits are set => index is 0. To conclude: Bitmap nodes are just like Array nodes -- they can store a number of pointers, but use bitmap compression to eliminate unused pointers. Bitmap nodes have two pointers for each item: +----+----+----+----+ -- +----+----+ | k1 | v1 | k2 | v2 | .. | kN | vN | +----+----+----+----+ -- +----+----+ When kI == NULL, vI points to another tree level. When kI != NULL, the actual key object is stored in kI, and its value is stored in vI. Collision Nodes --------------- Collision nodes are simple arrays of pointers -- two pointers per key/value. When there's a hash collision, say for k1/v1 and k2/v2 we have `hash(k1)==hash(k2)`. Then our collision node will be: +----+----+----+----+ | k1 | v1 | k2 | v2 | +----+----+----+----+ Tree Structure -------------- All nodes are PyObjects. The `PyHamtObject` object has a pointer to the root node (h_root), and has a length field (h_count). High-level functions accept a PyHamtObject object and dispatch to lower-level functions depending on what kind of node h_root points to. Operations ========== There are three fundamental operations on an immutable dictionary: 1. "o.assoc(k, v)" will return a new immutable dictionary, that will be a copy of "o", but with the "k/v" item set. Functions in this file: hamt_node_assoc, hamt_node_bitmap_assoc, hamt_node_array_assoc, hamt_node_collision_assoc `hamt_node_assoc` function accepts a node object, and calls other functions depending on its actual type. 2. "o.find(k)" will lookup key "k" in "o". Functions: hamt_node_find, hamt_node_bitmap_find, hamt_node_array_find, hamt_node_collision_find 3. "o.without(k)" will return a new immutable dictionary, that will be a copy of "o", buth without the "k" key. Functions: hamt_node_without, hamt_node_bitmap_without, hamt_node_array_without, hamt_node_collision_without Further Reading =============== 1. http://blog.higher-order.net/2009/09/08/understanding-clojures-persistenthashmap-deftwice.html 2. http://blog.higher-order.net/2010/08/16/assoc-and-clojures-persistenthashmap-part-ii.html 3. Clojure's PersistentHashMap implementation: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentHashMap.java Debug ===== The HAMT datatype is accessible for testing purposes under the `_testcapi` module: >>> from _testcapi import hamt >>> h = hamt() >>> h2 = h.set('a', 2) >>> h3 = h2.set('b', 3) >>> list(h3) ['a', 'b'] When CPython is built in debug mode, a '__dump__()' method is available to introspect the tree: >>> print(h3.__dump__()) HAMT(len=2): BitmapNode(size=4 count=2 bitmap=0b110 id=0x10eb9d9e8): 'a': 2 'b': 3 */ #define IS_ARRAY_NODE(node) Py_IS_TYPE(node, &_PyHamt_ArrayNode_Type) #define IS_BITMAP_NODE(node) Py_IS_TYPE(node, &_PyHamt_BitmapNode_Type) #define IS_COLLISION_NODE(node) Py_IS_TYPE(node, &_PyHamt_CollisionNode_Type) /* Return type for 'find' (lookup a key) functions. * F_ERROR - an error occurred; * F_NOT_FOUND - the key was not found; * F_FOUND - the key was found. */ typedef enum {F_ERROR, F_NOT_FOUND, F_FOUND} hamt_find_t; /* Return type for 'without' (delete a key) functions. * W_ERROR - an error occurred; * W_NOT_FOUND - the key was not found: there's nothing to delete; * W_EMPTY - the key was found: the node/tree would be empty if the key is deleted; * W_NEWNODE - the key was found: a new node/tree is returned without that key. */ typedef enum {W_ERROR, W_NOT_FOUND, W_EMPTY, W_NEWNODE} hamt_without_t; /* Low-level iterator protocol type. * I_ITEM - a new item has been yielded; * I_END - the whole tree was visited (similar to StopIteration). */ typedef enum {I_ITEM, I_END} hamt_iter_t; #define HAMT_ARRAY_NODE_SIZE 32 typedef struct { PyObject_HEAD PyHamtNode *a_array[HAMT_ARRAY_NODE_SIZE]; Py_ssize_t a_count; } PyHamtNode_Array; typedef struct { PyObject_VAR_HEAD int32_t c_hash; PyObject *c_array[1]; } PyHamtNode_Collision; static PyHamtObject * hamt_alloc(void); static PyHamtNode * hamt_node_assoc(PyHamtNode *node, uint32_t shift, int32_t hash, PyObject *key, PyObject *val, int* added_leaf); static hamt_without_t hamt_node_without(PyHamtNode *node, uint32_t shift, int32_t hash, PyObject *key, PyHamtNode **new_node); static hamt_find_t hamt_node_find(PyHamtNode *node, uint32_t shift, int32_t hash, PyObject *key, PyObject **val); #ifdef Py_DEBUG static int hamt_node_dump(PyHamtNode *node, _PyUnicodeWriter *writer, int level); #endif static PyHamtNode * hamt_node_array_new(Py_ssize_t); static PyHamtNode * hamt_node_collision_new(int32_t hash, Py_ssize_t size); static inline Py_ssize_t hamt_node_collision_count(PyHamtNode_Collision *node); #ifdef Py_DEBUG static void _hamt_node_array_validate(void *obj_raw) { PyObject *obj = _PyObject_CAST(obj_raw); assert(IS_ARRAY_NODE(obj)); PyHamtNode_Array *node = (PyHamtNode_Array*)obj; Py_ssize_t i = 0, count = 0; for (; i < HAMT_ARRAY_NODE_SIZE; i++) { if (node->a_array[i] != NULL) { count++; } } assert(count == node->a_count); } #define VALIDATE_ARRAY_NODE(NODE) \ do { _hamt_node_array_validate(NODE); } while (0); #else #define VALIDATE_ARRAY_NODE(NODE) #endif /* Returns -1 on error */ static inline int32_t hamt_hash(PyObject *o) { Py_hash_t hash = PyObject_Hash(o); #if SIZEOF_PY_HASH_T <= 4 return hash; #else if (hash == -1) { /* exception */ return -1; } /* While it's somewhat suboptimal to reduce Python's 64 bit hash to 32 bits via XOR, it seems that the resulting hash function is good enough (this is also how Long type is hashed in Java.) Storing 10, 100, 1000 Python strings results in a relatively shallow and uniform tree structure. Also it's worth noting that it would be possible to adapt the tree structure to 64 bit hashes, but that would increase memory pressure and provide little to no performance benefits for collections with fewer than billions of key/value pairs. Important: do not change this hash reducing function. There are many tests that need an exact tree shape to cover all code paths and we do that by specifying concrete values for test data's `__hash__`. If this function is changed most of the regression tests would become useless. */ int32_t xored = (int32_t)(hash & 0xffffffffl) ^ (int32_t)(hash >> 32); return xored == -1 ? -2 : xored; #endif } static inline uint32_t hamt_mask(int32_t hash, uint32_t shift) { return (((uint32_t)hash >> shift) & 0x01f); } static inline uint32_t hamt_bitpos(int32_t hash, uint32_t shift) { return (uint32_t)1 << hamt_mask(hash, shift); } static inline uint32_t hamt_bitindex(uint32_t bitmap, uint32_t bit) { return (uint32_t)_Py_popcount32(bitmap & (bit - 1)); } /////////////////////////////////// Dump Helpers #ifdef Py_DEBUG static int _hamt_dump_ident(_PyUnicodeWriter *writer, int level) { /* Write `' ' * level` to the `writer` */ PyObject *str = NULL; PyObject *num = NULL; PyObject *res = NULL; int ret = -1; str = PyUnicode_FromString(" "); if (str == NULL) { goto error; } num = PyLong_FromLong((long)level); if (num == NULL) { goto error; } res = PyNumber_Multiply(str, num); if (res == NULL) { goto error; } ret = _PyUnicodeWriter_WriteStr(writer, res); error: Py_XDECREF(res); Py_XDECREF(str); Py_XDECREF(num); return ret; } static int _hamt_dump_format(_PyUnicodeWriter *writer, const char *format, ...) { /* A convenient helper combining _PyUnicodeWriter_WriteStr and PyUnicode_FromFormatV. */ PyObject* msg; int ret; va_list vargs; va_start(vargs, format); msg = PyUnicode_FromFormatV(format, vargs); va_end(vargs); if (msg == NULL) { return -1; } ret = _PyUnicodeWriter_WriteStr(writer, msg); Py_DECREF(msg); return ret; } #endif /* Py_DEBUG */ /////////////////////////////////// Bitmap Node static PyHamtNode * hamt_node_bitmap_new(Py_ssize_t size) { /* Create a new bitmap node of size 'size' */ PyHamtNode_Bitmap *node; Py_ssize_t i; if (size == 0) { /* Since bitmap nodes are immutable, we can cache the instance for size=0 and reuse it whenever we need an empty bitmap node. */ return (PyHamtNode *)Py_NewRef(&_Py_SINGLETON(hamt_bitmap_node_empty)); } assert(size >= 0); assert(size % 2 == 0); /* No freelist; allocate a new bitmap node */ node = PyObject_GC_NewVar( PyHamtNode_Bitmap, &_PyHamt_BitmapNode_Type, size); if (node == NULL) { return NULL; } Py_SET_SIZE(node, size); for (i = 0; i < size; i++) { node->b_array[i] = NULL; } node->b_bitmap = 0; _PyObject_GC_TRACK(node); return (PyHamtNode *)node; } static inline Py_ssize_t hamt_node_bitmap_count(PyHamtNode_Bitmap *node) { return Py_SIZE(node) / 2; } static PyHamtNode_Bitmap * hamt_node_bitmap_clone(PyHamtNode_Bitmap *node) { /* Clone a bitmap node; return a new one with the same child notes. */ PyHamtNode_Bitmap *clone; Py_ssize_t i; clone = (PyHamtNode_Bitmap *)hamt_node_bitmap_new(Py_SIZE(node)); if (clone == NULL) { return NULL; } for (i = 0; i < Py_SIZE(node); i++) { clone->b_array[i] = Py_XNewRef(node->b_array[i]); } clone->b_bitmap = node->b_bitmap; return clone; } static PyHamtNode_Bitmap * hamt_node_bitmap_clone_without(PyHamtNode_Bitmap *o, uint32_t bit) { assert(bit & o->b_bitmap); assert(hamt_node_bitmap_count(o) > 1); PyHamtNode_Bitmap *new = (PyHamtNode_Bitmap *)hamt_node_bitmap_new( Py_SIZE(o) - 2); if (new == NULL) { return NULL; } uint32_t idx = hamt_bitindex(o->b_bitmap, bit); uint32_t key_idx = 2 * idx; uint32_t val_idx = key_idx + 1; uint32_t i; for (i = 0; i < key_idx; i++) { new->b_array[i] = Py_XNewRef(o->b_array[i]); } assert(Py_SIZE(o) >= 0 && Py_SIZE(o) <= 32); for (i = val_idx + 1; i < (uint32_t)Py_SIZE(o); i++) { new->b_array[i - 2] = Py_XNewRef(o->b_array[i]); } new->b_bitmap = o->b_bitmap & ~bit; return new; } static PyHamtNode * hamt_node_new_bitmap_or_collision(uint32_t shift, PyObject *key1, PyObject *val1, int32_t key2_hash, PyObject *key2, PyObject *val2) { /* Helper method. Creates a new node for key1/val and key2/val2 pairs. If key1 hash is equal to the hash of key2, a Collision node will be created. If they are not equal, a Bitmap node is created. */ int32_t key1_hash = hamt_hash(key1); if (key1_hash == -1) { return NULL; } if (key1_hash == key2_hash) { PyHamtNode_Collision *n; n = (PyHamtNode_Collision *)hamt_node_collision_new(key1_hash, 4); if (n == NULL) { return NULL; } n->c_array[0] = Py_NewRef(key1); n->c_array[1] = Py_NewRef(val1); n->c_array[2] = Py_NewRef(key2); n->c_array[3] = Py_NewRef(val2); return (PyHamtNode *)n; } else { int added_leaf = 0; PyHamtNode *n = hamt_node_bitmap_new(0); if (n == NULL) { return NULL; } PyHamtNode *n2 = hamt_node_assoc( n, shift, key1_hash, key1, val1, &added_leaf); Py_DECREF(n); if (n2 == NULL) { return NULL; } n = hamt_node_assoc(n2, shift, key2_hash, key2, val2, &added_leaf); Py_DECREF(n2); if (n == NULL) { return NULL; } return n; } } static PyHamtNode * hamt_node_bitmap_assoc(PyHamtNode_Bitmap *self, uint32_t shift, int32_t hash, PyObject *key, PyObject *val, int* added_leaf) { /* assoc operation for bitmap nodes. Return: a new node, or self if key/val already is in the collection. 'added_leaf' is later used in '_PyHamt_Assoc' to determine if `hamt.set(key, val)` increased the size of the collection. */ uint32_t bit = hamt_bitpos(hash, shift); uint32_t idx = hamt_bitindex(self->b_bitmap, bit); /* Bitmap node layout: +------+------+------+------+ --- +------+------+ | key1 | val1 | key2 | val2 | ... | keyN | valN | +------+------+------+------+ --- +------+------+ where `N < Py_SIZE(node)`. The `node->b_bitmap` field is a bitmap. For a given `(shift, hash)` pair we can determine: - If this node has the corresponding key/val slots. - The index of key/val slots. */ if (self->b_bitmap & bit) { /* The key is set in this node */ uint32_t key_idx = 2 * idx; uint32_t val_idx = key_idx + 1; assert(val_idx < (size_t)Py_SIZE(self)); PyObject *key_or_null = self->b_array[key_idx]; PyObject *val_or_node = self->b_array[val_idx]; if (key_or_null == NULL) { /* key is NULL. This means that we have a few keys that have the same (hash, shift) pair. */ assert(val_or_node != NULL); PyHamtNode *sub_node = hamt_node_assoc( (PyHamtNode *)val_or_node, shift + 5, hash, key, val, added_leaf); if (sub_node == NULL) { return NULL; } if (val_or_node == (PyObject *)sub_node) { Py_DECREF(sub_node); return (PyHamtNode *)Py_NewRef(self); } PyHamtNode_Bitmap *ret = hamt_node_bitmap_clone(self); if (ret == NULL) { return NULL; } Py_SETREF(ret->b_array[val_idx], (PyObject*)sub_node); return (PyHamtNode *)ret; } assert(key != NULL); /* key is not NULL. This means that we have only one other key in this collection that matches our hash for this shift. */ int comp_err = PyObject_RichCompareBool(key, key_or_null, Py_EQ); if (comp_err < 0) { /* exception in __eq__ */ return NULL; } if (comp_err == 1) { /* key == key_or_null */ if (val == val_or_node) { /* we already have the same key/val pair; return self. */ return (PyHamtNode *)Py_NewRef(self); } /* We're setting a new value for the key we had before. Make a new bitmap node with a replaced value, and return it. */ PyHamtNode_Bitmap *ret = hamt_node_bitmap_clone(self); if (ret == NULL) { return NULL; } Py_SETREF(ret->b_array[val_idx], Py_NewRef(val)); return (PyHamtNode *)ret; } /* It's a new key, and it has the same index as *one* another key. We have a collision. We need to create a new node which will combine the existing key and the key we're adding. `hamt_node_new_bitmap_or_collision` will either create a new Collision node if the keys have identical hashes, or a new Bitmap node. */ PyHamtNode *sub_node = hamt_node_new_bitmap_or_collision( shift + 5, key_or_null, val_or_node, /* existing key/val */ hash, key, val /* new key/val */ ); if (sub_node == NULL) { return NULL; } PyHamtNode_Bitmap *ret = hamt_node_bitmap_clone(self); if (ret == NULL) { Py_DECREF(sub_node); return NULL; } Py_SETREF(ret->b_array[key_idx], NULL); Py_SETREF(ret->b_array[val_idx], (PyObject *)sub_node); *added_leaf = 1; return (PyHamtNode *)ret; } else { /* There was no key before with the same (shift,hash). */ uint32_t n = (uint32_t)_Py_popcount32(self->b_bitmap); if (n >= 16) { /* When we have a situation where we want to store more than 16 nodes at one level of the tree, we no longer want to use the Bitmap node with bitmap encoding. Instead we start using an Array node, which has simpler (faster) implementation at the expense of having preallocated 32 pointers for its keys/values pairs. Small hamt objects (<30 keys) usually don't have any Array nodes at all. Between ~30 and ~400 keys hamt objects usually have one Array node, and usually it's a root node. */ uint32_t jdx = hamt_mask(hash, shift); /* 'jdx' is the index of where the new key should be added in the new Array node we're about to create. */ PyHamtNode *empty = NULL; PyHamtNode_Array *new_node = NULL; PyHamtNode *res = NULL; /* Create a new Array node. */ new_node = (PyHamtNode_Array *)hamt_node_array_new(n + 1); if (new_node == NULL) { goto fin; } /* Create an empty bitmap node for the next hamt_node_assoc call. */ empty = hamt_node_bitmap_new(0); if (empty == NULL) { goto fin; } /* Make a new bitmap node for the key/val we're adding. Set that bitmap node to new-array-node[jdx]. */ new_node->a_array[jdx] = hamt_node_assoc( empty, shift + 5, hash, key, val, added_leaf); if (new_node->a_array[jdx] == NULL) { goto fin; } /* Copy existing key/value pairs from the current Bitmap node to the new Array node we've just created. */ Py_ssize_t i, j; for (i = 0, j = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { if (((self->b_bitmap >> i) & 1) != 0) { /* Ensure we don't accidentally override `jdx` element we set few lines above. */ assert(new_node->a_array[i] == NULL); if (self->b_array[j] == NULL) { new_node->a_array[i] = (PyHamtNode *)Py_NewRef(self->b_array[j + 1]); } else { int32_t rehash = hamt_hash(self->b_array[j]); if (rehash == -1) { goto fin; } new_node->a_array[i] = hamt_node_assoc( empty, shift + 5, rehash, self->b_array[j], self->b_array[j + 1], added_leaf); if (new_node->a_array[i] == NULL) { goto fin; } } j += 2; } } VALIDATE_ARRAY_NODE(new_node) /* That's it! */ res = (PyHamtNode *)new_node; fin: Py_XDECREF(empty); if (res == NULL) { Py_XDECREF(new_node); } return res; } else { /* We have less than 16 keys at this level; let's just create a new bitmap node out of this node with the new key/val pair added. */ uint32_t key_idx = 2 * idx; uint32_t val_idx = key_idx + 1; uint32_t i; *added_leaf = 1; /* Allocate new Bitmap node which can have one more key/val pair in addition to what we have already. */ PyHamtNode_Bitmap *new_node = (PyHamtNode_Bitmap *)hamt_node_bitmap_new(2 * (n + 1)); if (new_node == NULL) { return NULL; } /* Copy all keys/values that will be before the new key/value we are adding. */ for (i = 0; i < key_idx; i++) { new_node->b_array[i] = Py_XNewRef(self->b_array[i]); } /* Set the new key/value to the new Bitmap node. */ new_node->b_array[key_idx] = Py_NewRef(key); new_node->b_array[val_idx] = Py_NewRef(val); /* Copy all keys/values that will be after the new key/value we are adding. */ assert(Py_SIZE(self) >= 0 && Py_SIZE(self) <= 32); for (i = key_idx; i < (uint32_t)Py_SIZE(self); i++) { new_node->b_array[i + 2] = Py_XNewRef(self->b_array[i]); } new_node->b_bitmap = self->b_bitmap | bit; return (PyHamtNode *)new_node; } } } static hamt_without_t hamt_node_bitmap_without(PyHamtNode_Bitmap *self, uint32_t shift, int32_t hash, PyObject *key, PyHamtNode **new_node) { uint32_t bit = hamt_bitpos(hash, shift); if ((self->b_bitmap & bit) == 0) { return W_NOT_FOUND; } uint32_t idx = hamt_bitindex(self->b_bitmap, bit); uint32_t key_idx = 2 * idx; uint32_t val_idx = key_idx + 1; PyObject *key_or_null = self->b_array[key_idx]; PyObject *val_or_node = self->b_array[val_idx]; if (key_or_null == NULL) { /* key == NULL means that 'value' is another tree node. */ PyHamtNode *sub_node = NULL; hamt_without_t res = hamt_node_without( (PyHamtNode *)val_or_node, shift + 5, hash, key, &sub_node); switch (res) { case W_EMPTY: /* It's impossible for us to receive a W_EMPTY here: - Array nodes are converted to Bitmap nodes when we delete 16th item from them; - Collision nodes are converted to Bitmap when there is one item in them; - Bitmap node's without() inlines single-item sub-nodes. So in no situation we can have a single-item Bitmap child of another Bitmap node. */ Py_UNREACHABLE(); case W_NEWNODE: { assert(sub_node != NULL); if (IS_BITMAP_NODE(sub_node)) { PyHamtNode_Bitmap *sub_tree = (PyHamtNode_Bitmap *)sub_node; if (hamt_node_bitmap_count(sub_tree) == 1 && sub_tree->b_array[0] != NULL) { /* A bitmap node with one key/value pair. Just merge it into this node. Note that we don't inline Bitmap nodes that have a NULL key -- those nodes point to another tree level, and we cannot simply move tree levels up or down. */ PyHamtNode_Bitmap *clone = hamt_node_bitmap_clone(self); if (clone == NULL) { Py_DECREF(sub_node); return W_ERROR; } PyObject *key = sub_tree->b_array[0]; PyObject *val = sub_tree->b_array[1]; Py_XSETREF(clone->b_array[key_idx], Py_NewRef(key)); Py_SETREF(clone->b_array[val_idx], Py_NewRef(val)); Py_DECREF(sub_tree); *new_node = (PyHamtNode *)clone; return W_NEWNODE; } } #ifdef Py_DEBUG /* Ensure that Collision.without implementation converts to Bitmap nodes itself. */ if (IS_COLLISION_NODE(sub_node)) { assert(hamt_node_collision_count( (PyHamtNode_Collision*)sub_node) > 1); } #endif PyHamtNode_Bitmap *clone = hamt_node_bitmap_clone(self); if (clone == NULL) { return W_ERROR; } Py_SETREF(clone->b_array[val_idx], (PyObject *)sub_node); /* borrow */ *new_node = (PyHamtNode *)clone; return W_NEWNODE; } case W_ERROR: case W_NOT_FOUND: assert(sub_node == NULL); return res; default: Py_UNREACHABLE(); } } else { /* We have a regular key/value pair */ int cmp = PyObject_RichCompareBool(key_or_null, key, Py_EQ); if (cmp < 0) { return W_ERROR; } if (cmp == 0) { return W_NOT_FOUND; } if (hamt_node_bitmap_count(self) == 1) { return W_EMPTY; } *new_node = (PyHamtNode *) hamt_node_bitmap_clone_without(self, bit); if (*new_node == NULL) { return W_ERROR; } return W_NEWNODE; } } static hamt_find_t hamt_node_bitmap_find(PyHamtNode_Bitmap *self, uint32_t shift, int32_t hash, PyObject *key, PyObject **val) { /* Lookup a key in a Bitmap node. */ uint32_t bit = hamt_bitpos(hash, shift); uint32_t idx; uint32_t key_idx; uint32_t val_idx; PyObject *key_or_null; PyObject *val_or_node; int comp_err; if ((self->b_bitmap & bit) == 0) { return F_NOT_FOUND; } idx = hamt_bitindex(self->b_bitmap, bit); key_idx = idx * 2; val_idx = key_idx + 1; assert(val_idx < (size_t)Py_SIZE(self)); key_or_null = self->b_array[key_idx]; val_or_node = self->b_array[val_idx]; if (key_or_null == NULL) { /* There are a few keys that have the same hash at the current shift that match our key. Dispatch the lookup further down the tree. */ assert(val_or_node != NULL); return hamt_node_find((PyHamtNode *)val_or_node, shift + 5, hash, key, val); } /* We have only one key -- a potential match. Let's compare if the key we are looking at is equal to the key we are looking for. */ assert(key != NULL); comp_err = PyObject_RichCompareBool(key, key_or_null, Py_EQ); if (comp_err < 0) { /* exception in __eq__ */ return F_ERROR; } if (comp_err == 1) { /* key == key_or_null */ *val = val_or_node; return F_FOUND; } return F_NOT_FOUND; } static int hamt_node_bitmap_traverse(PyHamtNode_Bitmap *self, visitproc visit, void *arg) { /* Bitmap's tp_traverse */ Py_ssize_t i; for (i = Py_SIZE(self); --i >= 0; ) { Py_VISIT(self->b_array[i]); } return 0; } static void hamt_node_bitmap_dealloc(PyHamtNode_Bitmap *self) { /* Bitmap's tp_dealloc */ Py_ssize_t len = Py_SIZE(self); Py_ssize_t i; if (Py_SIZE(self) == 0) { /* The empty node is statically allocated. */ assert(self == &_Py_SINGLETON(hamt_bitmap_node_empty)); #ifdef Py_DEBUG _Py_FatalRefcountError("deallocating the empty hamt node bitmap singleton"); #else return; #endif } PyObject_GC_UnTrack(self); Py_TRASHCAN_BEGIN(self, hamt_node_bitmap_dealloc) if (len > 0) { i = len; while (--i >= 0) { Py_XDECREF(self->b_array[i]); } } Py_TYPE(self)->tp_free((PyObject *)self); Py_TRASHCAN_END } #ifdef Py_DEBUG static int hamt_node_bitmap_dump(PyHamtNode_Bitmap *node, _PyUnicodeWriter *writer, int level) { /* Debug build: __dump__() method implementation for Bitmap nodes. */ Py_ssize_t i; PyObject *tmp1; PyObject *tmp2; if (_hamt_dump_ident(writer, level + 1)) { goto error; } if (_hamt_dump_format(writer, "BitmapNode(size=%zd count=%zd ", Py_SIZE(node), Py_SIZE(node) / 2)) { goto error; } tmp1 = PyLong_FromUnsignedLong(node->b_bitmap); if (tmp1 == NULL) { goto error; } tmp2 = _PyLong_Format(tmp1, 2); Py_DECREF(tmp1); if (tmp2 == NULL) { goto error; } if (_hamt_dump_format(writer, "bitmap=%S id=%p):\n", tmp2, node)) { Py_DECREF(tmp2); goto error; } Py_DECREF(tmp2); for (i = 0; i < Py_SIZE(node); i += 2) { PyObject *key_or_null = node->b_array[i]; PyObject *val_or_node = node->b_array[i + 1]; if (_hamt_dump_ident(writer, level + 2)) { goto error; } if (key_or_null == NULL) { if (_hamt_dump_format(writer, "NULL:\n")) { goto error; } if (hamt_node_dump((PyHamtNode *)val_or_node, writer, level + 2)) { goto error; } } else { if (_hamt_dump_format(writer, "%R: %R", key_or_null, val_or_node)) { goto error; } } if (_hamt_dump_format(writer, "\n")) { goto error; } } return 0; error: return -1; } #endif /* Py_DEBUG */ /////////////////////////////////// Collision Node static PyHamtNode * hamt_node_collision_new(int32_t hash, Py_ssize_t size) { /* Create a new Collision node. */ PyHamtNode_Collision *node; Py_ssize_t i; assert(size >= 4); assert(size % 2 == 0); node = PyObject_GC_NewVar( PyHamtNode_Collision, &_PyHamt_CollisionNode_Type, size); if (node == NULL) { return NULL; } for (i = 0; i < size; i++) { node->c_array[i] = NULL; } Py_SET_SIZE(node, size); node->c_hash = hash; _PyObject_GC_TRACK(node); return (PyHamtNode *)node; } static hamt_find_t hamt_node_collision_find_index(PyHamtNode_Collision *self, PyObject *key, Py_ssize_t *idx) { /* Lookup `key` in the Collision node `self`. Set the index of the found key to 'idx'. */ Py_ssize_t i; PyObject *el; for (i = 0; i < Py_SIZE(self); i += 2) { el = self->c_array[i]; assert(el != NULL); int cmp = PyObject_RichCompareBool(key, el, Py_EQ); if (cmp < 0) { return F_ERROR; } if (cmp == 1) { *idx = i; return F_FOUND; } } return F_NOT_FOUND; } static PyHamtNode * hamt_node_collision_assoc(PyHamtNode_Collision *self, uint32_t shift, int32_t hash, PyObject *key, PyObject *val, int* added_leaf) { /* Set a new key to this level (currently a Collision node) of the tree. */ if (hash == self->c_hash) { /* The hash of the 'key' we are adding matches the hash of other keys in this Collision node. */ Py_ssize_t key_idx = -1; hamt_find_t found; PyHamtNode_Collision *new_node; Py_ssize_t i; /* Let's try to lookup the new 'key', maybe we already have it. */ found = hamt_node_collision_find_index(self, key, &key_idx); switch (found) { case F_ERROR: /* Exception. */ return NULL; case F_NOT_FOUND: /* This is a totally new key. Clone the current node, add a new key/value to the cloned node. */ new_node = (PyHamtNode_Collision *)hamt_node_collision_new( self->c_hash, Py_SIZE(self) + 2); if (new_node == NULL) { return NULL; } for (i = 0; i < Py_SIZE(self); i++) { new_node->c_array[i] = Py_NewRef(self->c_array[i]); } new_node->c_array[i] = Py_NewRef(key); new_node->c_array[i + 1] = Py_NewRef(val); *added_leaf = 1; return (PyHamtNode *)new_node; case F_FOUND: /* There's a key which is equal to the key we are adding. */ assert(key_idx >= 0); assert(key_idx < Py_SIZE(self)); Py_ssize_t val_idx = key_idx + 1; if (self->c_array[val_idx] == val) { /* We're setting a key/value pair that's already set. */ return (PyHamtNode *)Py_NewRef(self); } /* We need to replace old value for the key with a new value. Create a new Collision node.*/ new_node = (PyHamtNode_Collision *)hamt_node_collision_new( self->c_hash, Py_SIZE(self)); if (new_node == NULL) { return NULL; } /* Copy all elements of the old node to the new one. */ for (i = 0; i < Py_SIZE(self); i++) { new_node->c_array[i] = Py_NewRef(self->c_array[i]); } /* Replace the old value with the new value for the our key. */ Py_SETREF(new_node->c_array[val_idx], Py_NewRef(val)); return (PyHamtNode *)new_node; default: Py_UNREACHABLE(); } } else { /* The hash of the new key is different from the hash that all keys of this Collision node have. Create a Bitmap node inplace with two children: key/value pair that we're adding, and the Collision node we're replacing on this tree level. */ PyHamtNode_Bitmap *new_node; PyHamtNode *assoc_res; new_node = (PyHamtNode_Bitmap *)hamt_node_bitmap_new(2); if (new_node == NULL) { return NULL; } new_node->b_bitmap = hamt_bitpos(self->c_hash, shift); new_node->b_array[1] = Py_NewRef(self); assoc_res = hamt_node_bitmap_assoc( new_node, shift, hash, key, val, added_leaf); Py_DECREF(new_node); return assoc_res; } } static inline Py_ssize_t hamt_node_collision_count(PyHamtNode_Collision *node) { return Py_SIZE(node) / 2; } static hamt_without_t hamt_node_collision_without(PyHamtNode_Collision *self, uint32_t shift, int32_t hash, PyObject *key, PyHamtNode **new_node) { if (hash != self->c_hash) { return W_NOT_FOUND; } Py_ssize_t key_idx = -1; hamt_find_t found = hamt_node_collision_find_index(self, key, &key_idx); switch (found) { case F_ERROR: return W_ERROR; case F_NOT_FOUND: return W_NOT_FOUND; case F_FOUND: assert(key_idx >= 0); assert(key_idx < Py_SIZE(self)); Py_ssize_t new_count = hamt_node_collision_count(self) - 1; if (new_count == 0) { /* The node has only one key/value pair and it's for the key we're trying to delete. So a new node will be empty after the removal. */ return W_EMPTY; } if (new_count == 1) { /* The node has two keys, and after deletion the new Collision node would have one. Collision nodes with one key shouldn't exist, so convert it to a Bitmap node. */ PyHamtNode_Bitmap *node = (PyHamtNode_Bitmap *) hamt_node_bitmap_new(2); if (node == NULL) { return W_ERROR; } if (key_idx == 0) { node->b_array[0] = Py_NewRef(self->c_array[2]); node->b_array[1] = Py_NewRef(self->c_array[3]); } else { assert(key_idx == 2); node->b_array[0] = Py_NewRef(self->c_array[0]); node->b_array[1] = Py_NewRef(self->c_array[1]); } node->b_bitmap = hamt_bitpos(hash, shift); *new_node = (PyHamtNode *)node; return W_NEWNODE; } /* Allocate a new Collision node with capacity for one less key/value pair */ PyHamtNode_Collision *new = (PyHamtNode_Collision *) hamt_node_collision_new( self->c_hash, Py_SIZE(self) - 2); if (new == NULL) { return W_ERROR; } /* Copy all other keys from `self` to `new` */ Py_ssize_t i; for (i = 0; i < key_idx; i++) { new->c_array[i] = Py_NewRef(self->c_array[i]); } for (i = key_idx + 2; i < Py_SIZE(self); i++) { new->c_array[i - 2] = Py_NewRef(self->c_array[i]); } *new_node = (PyHamtNode*)new; return W_NEWNODE; default: Py_UNREACHABLE(); } } static hamt_find_t hamt_node_collision_find(PyHamtNode_Collision *self, uint32_t shift, int32_t hash, PyObject *key, PyObject **val) { /* Lookup `key` in the Collision node `self`. Set the value for the found key to 'val'. */ Py_ssize_t idx = -1; hamt_find_t res; res = hamt_node_collision_find_index(self, key, &idx); if (res == F_ERROR || res == F_NOT_FOUND) { return res; } assert(idx >= 0); assert(idx + 1 < Py_SIZE(self)); *val = self->c_array[idx + 1]; assert(*val != NULL); return F_FOUND; } static int hamt_node_collision_traverse(PyHamtNode_Collision *self, visitproc visit, void *arg) { /* Collision's tp_traverse */ Py_ssize_t i; for (i = Py_SIZE(self); --i >= 0; ) { Py_VISIT(self->c_array[i]); } return 0; } static void hamt_node_collision_dealloc(PyHamtNode_Collision *self) { /* Collision's tp_dealloc */ Py_ssize_t len = Py_SIZE(self); PyObject_GC_UnTrack(self); Py_TRASHCAN_BEGIN(self, hamt_node_collision_dealloc) if (len > 0) { while (--len >= 0) { Py_XDECREF(self->c_array[len]); } } Py_TYPE(self)->tp_free((PyObject *)self); Py_TRASHCAN_END } #ifdef Py_DEBUG static int hamt_node_collision_dump(PyHamtNode_Collision *node, _PyUnicodeWriter *writer, int level) { /* Debug build: __dump__() method implementation for Collision nodes. */ Py_ssize_t i; if (_hamt_dump_ident(writer, level + 1)) { goto error; } if (_hamt_dump_format(writer, "CollisionNode(size=%zd id=%p):\n", Py_SIZE(node), node)) { goto error; } for (i = 0; i < Py_SIZE(node); i += 2) { PyObject *key = node->c_array[i]; PyObject *val = node->c_array[i + 1]; if (_hamt_dump_ident(writer, level + 2)) { goto error; } if (_hamt_dump_format(writer, "%R: %R\n", key, val)) { goto error; } } return 0; error: return -1; } #endif /* Py_DEBUG */ /////////////////////////////////// Array Node static PyHamtNode * hamt_node_array_new(Py_ssize_t count) { Py_ssize_t i; PyHamtNode_Array *node = PyObject_GC_New( PyHamtNode_Array, &_PyHamt_ArrayNode_Type); if (node == NULL) { return NULL; } for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { node->a_array[i] = NULL; } node->a_count = count; _PyObject_GC_TRACK(node); return (PyHamtNode *)node; } static PyHamtNode_Array * hamt_node_array_clone(PyHamtNode_Array *node) { PyHamtNode_Array *clone; Py_ssize_t i; VALIDATE_ARRAY_NODE(node) /* Create a new Array node. */ clone = (PyHamtNode_Array *)hamt_node_array_new(node->a_count); if (clone == NULL) { return NULL; } /* Copy all elements from the current Array node to the new one. */ for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { clone->a_array[i] = (PyHamtNode*)Py_XNewRef(node->a_array[i]); } VALIDATE_ARRAY_NODE(clone) return clone; } static PyHamtNode * hamt_node_array_assoc(PyHamtNode_Array *self, uint32_t shift, int32_t hash, PyObject *key, PyObject *val, int* added_leaf) { /* Set a new key to this level (currently a Collision node) of the tree. Array nodes don't store values, they can only point to other nodes. They are simple arrays of 32 BaseNode pointers/ */ uint32_t idx = hamt_mask(hash, shift); PyHamtNode *node = self->a_array[idx]; PyHamtNode *child_node; PyHamtNode_Array *new_node; Py_ssize_t i; if (node == NULL) { /* There's no child node for the given hash. Create a new Bitmap node for this key. */ PyHamtNode_Bitmap *empty = NULL; /* Get an empty Bitmap node to work with. */ empty = (PyHamtNode_Bitmap *)hamt_node_bitmap_new(0); if (empty == NULL) { return NULL; } /* Set key/val to the newly created empty Bitmap, thus creating a new Bitmap node with our key/value pair. */ child_node = hamt_node_bitmap_assoc( empty, shift + 5, hash, key, val, added_leaf); Py_DECREF(empty); if (child_node == NULL) { return NULL; } /* Create a new Array node. */ new_node = (PyHamtNode_Array *)hamt_node_array_new(self->a_count + 1); if (new_node == NULL) { Py_DECREF(child_node); return NULL; } /* Copy all elements from the current Array node to the new one. */ for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { new_node->a_array[i] = (PyHamtNode*)Py_XNewRef(self->a_array[i]); } assert(new_node->a_array[idx] == NULL); new_node->a_array[idx] = child_node; /* borrow */ VALIDATE_ARRAY_NODE(new_node) } else { /* There's a child node for the given hash. Set the key to it./ */ child_node = hamt_node_assoc( node, shift + 5, hash, key, val, added_leaf); if (child_node == NULL) { return NULL; } else if (child_node == (PyHamtNode *)self) { Py_DECREF(child_node); return (PyHamtNode *)self; } new_node = hamt_node_array_clone(self); if (new_node == NULL) { Py_DECREF(child_node); return NULL; } Py_SETREF(new_node->a_array[idx], child_node); /* borrow */ VALIDATE_ARRAY_NODE(new_node) } return (PyHamtNode *)new_node; } static hamt_without_t hamt_node_array_without(PyHamtNode_Array *self, uint32_t shift, int32_t hash, PyObject *key, PyHamtNode **new_node) { uint32_t idx = hamt_mask(hash, shift); PyHamtNode *node = self->a_array[idx]; if (node == NULL) { return W_NOT_FOUND; } PyHamtNode *sub_node = NULL; hamt_without_t res = hamt_node_without( (PyHamtNode *)node, shift + 5, hash, key, &sub_node); switch (res) { case W_NOT_FOUND: case W_ERROR: assert(sub_node == NULL); return res; case W_NEWNODE: { /* We need to replace a node at the `idx` index. Clone this node and replace. */ assert(sub_node != NULL); PyHamtNode_Array *clone = hamt_node_array_clone(self); if (clone == NULL) { Py_DECREF(sub_node); return W_ERROR; } Py_SETREF(clone->a_array[idx], sub_node); /* borrow */ *new_node = (PyHamtNode*)clone; /* borrow */ return W_NEWNODE; } case W_EMPTY: { assert(sub_node == NULL); /* We need to remove a node at the `idx` index. Calculate the size of the replacement Array node. */ Py_ssize_t new_count = self->a_count - 1; if (new_count == 0) { return W_EMPTY; } if (new_count >= 16) { /* We convert Bitmap nodes to Array nodes, when a Bitmap node needs to store more than 15 key/value pairs. So we will create a new Array node if we the number of key/values after deletion is still greater than 15. */ PyHamtNode_Array *new = hamt_node_array_clone(self); if (new == NULL) { return W_ERROR; } new->a_count = new_count; Py_CLEAR(new->a_array[idx]); *new_node = (PyHamtNode*)new; /* borrow */ return W_NEWNODE; } /* New Array node would have less than 16 key/value pairs. We need to create a replacement Bitmap node. */ Py_ssize_t bitmap_size = new_count * 2; uint32_t bitmap = 0; PyHamtNode_Bitmap *new = (PyHamtNode_Bitmap *) hamt_node_bitmap_new(bitmap_size); if (new == NULL) { return W_ERROR; } Py_ssize_t new_i = 0; for (uint32_t i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { if (i == idx) { /* Skip the node we are deleting. */ continue; } PyHamtNode *node = self->a_array[i]; if (node == NULL) { /* Skip any missing nodes. */ continue; } bitmap |= 1U << i; if (IS_BITMAP_NODE(node)) { PyHamtNode_Bitmap *child = (PyHamtNode_Bitmap *)node; if (hamt_node_bitmap_count(child) == 1 && child->b_array[0] != NULL) { /* node is a Bitmap with one key/value pair, just merge it into the new Bitmap node we're building. Note that we don't inline Bitmap nodes that have a NULL key -- those nodes point to another tree level, and we cannot simply move tree levels up or down. */ PyObject *key = child->b_array[0]; PyObject *val = child->b_array[1]; new->b_array[new_i] = Py_NewRef(key); new->b_array[new_i + 1] = Py_NewRef(val); } else { new->b_array[new_i] = NULL; new->b_array[new_i + 1] = Py_NewRef(node); } } else { #ifdef Py_DEBUG if (IS_COLLISION_NODE(node)) { Py_ssize_t child_count = hamt_node_collision_count( (PyHamtNode_Collision*)node); assert(child_count > 1); } else if (IS_ARRAY_NODE(node)) { assert(((PyHamtNode_Array*)node)->a_count >= 16); } #endif /* Just copy the node into our new Bitmap */ new->b_array[new_i] = NULL; new->b_array[new_i + 1] = Py_NewRef(node); } new_i += 2; } new->b_bitmap = bitmap; *new_node = (PyHamtNode*)new; /* borrow */ return W_NEWNODE; } default: Py_UNREACHABLE(); } } static hamt_find_t hamt_node_array_find(PyHamtNode_Array *self, uint32_t shift, int32_t hash, PyObject *key, PyObject **val) { /* Lookup `key` in the Array node `self`. Set the value for the found key to 'val'. */ uint32_t idx = hamt_mask(hash, shift); PyHamtNode *node; node = self->a_array[idx]; if (node == NULL) { return F_NOT_FOUND; } /* Dispatch to the generic hamt_node_find */ return hamt_node_find(node, shift + 5, hash, key, val); } static int hamt_node_array_traverse(PyHamtNode_Array *self, visitproc visit, void *arg) { /* Array's tp_traverse */ Py_ssize_t i; for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { Py_VISIT(self->a_array[i]); } return 0; } static void hamt_node_array_dealloc(PyHamtNode_Array *self) { /* Array's tp_dealloc */ Py_ssize_t i; PyObject_GC_UnTrack(self); Py_TRASHCAN_BEGIN(self, hamt_node_array_dealloc) for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { Py_XDECREF(self->a_array[i]); } Py_TYPE(self)->tp_free((PyObject *)self); Py_TRASHCAN_END } #ifdef Py_DEBUG static int hamt_node_array_dump(PyHamtNode_Array *node, _PyUnicodeWriter *writer, int level) { /* Debug build: __dump__() method implementation for Array nodes. */ Py_ssize_t i; if (_hamt_dump_ident(writer, level + 1)) { goto error; } if (_hamt_dump_format(writer, "ArrayNode(id=%p):\n", node)) { goto error; } for (i = 0; i < HAMT_ARRAY_NODE_SIZE; i++) { if (node->a_array[i] == NULL) { continue; } if (_hamt_dump_ident(writer, level + 2)) { goto error; } if (_hamt_dump_format(writer, "%zd::\n", i)) { goto error; } if (hamt_node_dump(node->a_array[i], writer, level + 1)) { goto error; } if (_hamt_dump_format(writer, "\n")) { goto error; } } return 0; error: return -1; } #endif /* Py_DEBUG */ /////////////////////////////////// Node Dispatch static PyHamtNode * hamt_node_assoc(PyHamtNode *node, uint32_t shift, int32_t hash, PyObject *key, PyObject *val, int* added_leaf) { /* Set key/value to the 'node' starting with the given shift/hash. Return a new node, or the same node if key/value already set. added_leaf will be set to 1 if key/value wasn't in the tree before. This method automatically dispatches to the suitable hamt_node_{nodetype}_assoc method. */ if (IS_BITMAP_NODE(node)) { return hamt_node_bitmap_assoc( (PyHamtNode_Bitmap *)node, shift, hash, key, val, added_leaf); } else if (IS_ARRAY_NODE(node)) { return hamt_node_array_assoc( (PyHamtNode_Array *)node, shift, hash, key, val, added_leaf); } else { assert(IS_COLLISION_NODE(node)); return hamt_node_collision_assoc( (PyHamtNode_Collision *)node, shift, hash, key, val, added_leaf); } } static hamt_without_t hamt_node_without(PyHamtNode *node, uint32_t shift, int32_t hash, PyObject *key, PyHamtNode **new_node) { if (IS_BITMAP_NODE(node)) { return hamt_node_bitmap_without( (PyHamtNode_Bitmap *)node, shift, hash, key, new_node); } else if (IS_ARRAY_NODE(node)) { return hamt_node_array_without( (PyHamtNode_Array *)node, shift, hash, key, new_node); } else { assert(IS_COLLISION_NODE(node)); return hamt_node_collision_without( (PyHamtNode_Collision *)node, shift, hash, key, new_node); } } static hamt_find_t hamt_node_find(PyHamtNode *node, uint32_t shift, int32_t hash, PyObject *key, PyObject **val) { /* Find the key in the node starting with the given shift/hash. If a value is found, the result will be set to F_FOUND, and *val will point to the found value object. If a value wasn't found, the result will be set to F_NOT_FOUND. If an exception occurs during the call, the result will be F_ERROR. This method automatically dispatches to the suitable hamt_node_{nodetype}_find method. */ if (IS_BITMAP_NODE(node)) { return hamt_node_bitmap_find( (PyHamtNode_Bitmap *)node, shift, hash, key, val); } else if (IS_ARRAY_NODE(node)) { return hamt_node_array_find( (PyHamtNode_Array *)node, shift, hash, key, val); } else { assert(IS_COLLISION_NODE(node)); return hamt_node_collision_find( (PyHamtNode_Collision *)node, shift, hash, key, val); } } #ifdef Py_DEBUG static int hamt_node_dump(PyHamtNode *node, _PyUnicodeWriter *writer, int level) { /* Debug build: __dump__() method implementation for a node. This method automatically dispatches to the suitable hamt_node_{nodetype})_dump method. */ if (IS_BITMAP_NODE(node)) { return hamt_node_bitmap_dump( (PyHamtNode_Bitmap *)node, writer, level); } else if (IS_ARRAY_NODE(node)) { return hamt_node_array_dump( (PyHamtNode_Array *)node, writer, level); } else { assert(IS_COLLISION_NODE(node)); return hamt_node_collision_dump( (PyHamtNode_Collision *)node, writer, level); } } #endif /* Py_DEBUG */ /////////////////////////////////// Iterators: Machinery static hamt_iter_t hamt_iterator_next(PyHamtIteratorState *iter, PyObject **key, PyObject **val); static void hamt_iterator_init(PyHamtIteratorState *iter, PyHamtNode *root) { for (uint32_t i = 0; i < _Py_HAMT_MAX_TREE_DEPTH; i++) { iter->i_nodes[i] = NULL; iter->i_pos[i] = 0; } iter->i_level = 0; /* Note: we don't incref/decref nodes in i_nodes. */ iter->i_nodes[0] = root; } static hamt_iter_t hamt_iterator_bitmap_next(PyHamtIteratorState *iter, PyObject **key, PyObject **val) { int8_t level = iter->i_level; PyHamtNode_Bitmap *node = (PyHamtNode_Bitmap *)(iter->i_nodes[level]); Py_ssize_t pos = iter->i_pos[level]; if (pos + 1 >= Py_SIZE(node)) { #ifdef Py_DEBUG assert(iter->i_level >= 0); iter->i_nodes[iter->i_level] = NULL; #endif iter->i_level--; return hamt_iterator_next(iter, key, val); } if (node->b_array[pos] == NULL) { iter->i_pos[level] = pos + 2; int8_t next_level = level + 1; assert(next_level < _Py_HAMT_MAX_TREE_DEPTH); iter->i_level = next_level; iter->i_pos[next_level] = 0; iter->i_nodes[next_level] = (PyHamtNode *) node->b_array[pos + 1]; return hamt_iterator_next(iter, key, val); } *key = node->b_array[pos]; *val = node->b_array[pos + 1]; iter->i_pos[level] = pos + 2; return I_ITEM; } static hamt_iter_t hamt_iterator_collision_next(PyHamtIteratorState *iter, PyObject **key, PyObject **val) { int8_t level = iter->i_level; PyHamtNode_Collision *node = (PyHamtNode_Collision *)(iter->i_nodes[level]); Py_ssize_t pos = iter->i_pos[level]; if (pos + 1 >= Py_SIZE(node)) { #ifdef Py_DEBUG assert(iter->i_level >= 0); iter->i_nodes[iter->i_level] = NULL; #endif iter->i_level--; return hamt_iterator_next(iter, key, val); } *key = node->c_array[pos]; *val = node->c_array[pos + 1]; iter->i_pos[level] = pos + 2; return I_ITEM; } static hamt_iter_t hamt_iterator_array_next(PyHamtIteratorState *iter, PyObject **key, PyObject **val) { int8_t level = iter->i_level; PyHamtNode_Array *node = (PyHamtNode_Array *)(iter->i_nodes[level]); Py_ssize_t pos = iter->i_pos[level]; if (pos >= HAMT_ARRAY_NODE_SIZE) { #ifdef Py_DEBUG assert(iter->i_level >= 0); iter->i_nodes[iter->i_level] = NULL; #endif iter->i_level--; return hamt_iterator_next(iter, key, val); } for (Py_ssize_t i = pos; i < HAMT_ARRAY_NODE_SIZE; i++) { if (node->a_array[i] != NULL) { iter->i_pos[level] = i + 1; int8_t next_level = level + 1; assert(next_level < _Py_HAMT_MAX_TREE_DEPTH); iter->i_pos[next_level] = 0; iter->i_nodes[next_level] = node->a_array[i]; iter->i_level = next_level; return hamt_iterator_next(iter, key, val); } } #ifdef Py_DEBUG assert(iter->i_level >= 0); iter->i_nodes[iter->i_level] = NULL; #endif iter->i_level--; return hamt_iterator_next(iter, key, val); } static hamt_iter_t hamt_iterator_next(PyHamtIteratorState *iter, PyObject **key, PyObject **val) { if (iter->i_level < 0) { return I_END; } assert(iter->i_level < _Py_HAMT_MAX_TREE_DEPTH); PyHamtNode *current = iter->i_nodes[iter->i_level]; if (IS_BITMAP_NODE(current)) { return hamt_iterator_bitmap_next(iter, key, val); } else if (IS_ARRAY_NODE(current)) { return hamt_iterator_array_next(iter, key, val); } else { assert(IS_COLLISION_NODE(current)); return hamt_iterator_collision_next(iter, key, val); } } /////////////////////////////////// HAMT high-level functions PyHamtObject * _PyHamt_Assoc(PyHamtObject *o, PyObject *key, PyObject *val) { int32_t key_hash; int added_leaf = 0; PyHamtNode *new_root; PyHamtObject *new_o; key_hash = hamt_hash(key); if (key_hash == -1) { return NULL; } new_root = hamt_node_assoc( (PyHamtNode *)(o->h_root), 0, key_hash, key, val, &added_leaf); if (new_root == NULL) { return NULL; } if (new_root == o->h_root) { Py_DECREF(new_root); return (PyHamtObject*)Py_NewRef(o); } new_o = hamt_alloc(); if (new_o == NULL) { Py_DECREF(new_root); return NULL; } new_o->h_root = new_root; /* borrow */ new_o->h_count = added_leaf ? o->h_count + 1 : o->h_count; return new_o; } PyHamtObject * _PyHamt_Without(PyHamtObject *o, PyObject *key) { int32_t key_hash = hamt_hash(key); if (key_hash == -1) { return NULL; } PyHamtNode *new_root = NULL; hamt_without_t res = hamt_node_without( (PyHamtNode *)(o->h_root), 0, key_hash, key, &new_root); switch (res) { case W_ERROR: return NULL; case W_EMPTY: return _PyHamt_New(); case W_NOT_FOUND: return (PyHamtObject*)Py_NewRef(o); case W_NEWNODE: { assert(new_root != NULL); PyHamtObject *new_o = hamt_alloc(); if (new_o == NULL) { Py_DECREF(new_root); return NULL; } new_o->h_root = new_root; /* borrow */ new_o->h_count = o->h_count - 1; assert(new_o->h_count >= 0); return new_o; } default: Py_UNREACHABLE(); } } static hamt_find_t hamt_find(PyHamtObject *o, PyObject *key, PyObject **val) { if (o->h_count == 0) { return F_NOT_FOUND; } int32_t key_hash = hamt_hash(key); if (key_hash == -1) { return F_ERROR; } return hamt_node_find(o->h_root, 0, key_hash, key, val); } int _PyHamt_Find(PyHamtObject *o, PyObject *key, PyObject **val) { hamt_find_t res = hamt_find(o, key, val); switch (res) { case F_ERROR: return -1; case F_NOT_FOUND: return 0; case F_FOUND: return 1; default: Py_UNREACHABLE(); } } int _PyHamt_Eq(PyHamtObject *v, PyHamtObject *w) { if (v == w) { return 1; } if (v->h_count != w->h_count) { return 0; } PyHamtIteratorState iter; hamt_iter_t iter_res; hamt_find_t find_res; PyObject *v_key; PyObject *v_val; PyObject *w_val; hamt_iterator_init(&iter, v->h_root); do { iter_res = hamt_iterator_next(&iter, &v_key, &v_val); if (iter_res == I_ITEM) { find_res = hamt_find(w, v_key, &w_val); switch (find_res) { case F_ERROR: return -1; case F_NOT_FOUND: return 0; case F_FOUND: { int cmp = PyObject_RichCompareBool(v_val, w_val, Py_EQ); if (cmp < 0) { return -1; } if (cmp == 0) { return 0; } } } } } while (iter_res != I_END); return 1; } Py_ssize_t _PyHamt_Len(PyHamtObject *o) { return o->h_count; } static PyHamtObject * hamt_alloc(void) { PyHamtObject *o; o = PyObject_GC_New(PyHamtObject, &_PyHamt_Type); if (o == NULL) { return NULL; } o->h_count = 0; o->h_root = NULL; o->h_weakreflist = NULL; PyObject_GC_Track(o); return o; } #define _empty_hamt \ (&_Py_INTERP_SINGLETON(_PyInterpreterState_Get(), hamt_empty)) PyHamtObject * _PyHamt_New(void) { /* HAMT is an immutable object so we can easily cache an empty instance. */ return (PyHamtObject*)Py_NewRef(_empty_hamt); } #ifdef Py_DEBUG static PyObject * hamt_dump(PyHamtObject *self) { _PyUnicodeWriter writer; _PyUnicodeWriter_Init(&writer); if (_hamt_dump_format(&writer, "HAMT(len=%zd):\n", self->h_count)) { goto error; } if (hamt_node_dump(self->h_root, &writer, 0)) { goto error; } return _PyUnicodeWriter_Finish(&writer); error: _PyUnicodeWriter_Dealloc(&writer); return NULL; } #endif /* Py_DEBUG */ /////////////////////////////////// Iterators: Shared Iterator Implementation static int hamt_baseiter_tp_clear(PyHamtIterator *it) { Py_CLEAR(it->hi_obj); return 0; } static void hamt_baseiter_tp_dealloc(PyHamtIterator *it) { PyObject_GC_UnTrack(it); (void)hamt_baseiter_tp_clear(it); PyObject_GC_Del(it); } static int hamt_baseiter_tp_traverse(PyHamtIterator *it, visitproc visit, void *arg) { Py_VISIT(it->hi_obj); return 0; } static PyObject * hamt_baseiter_tp_iternext(PyHamtIterator *it) { PyObject *key; PyObject *val; hamt_iter_t res = hamt_iterator_next(&it->hi_iter, &key, &val); switch (res) { case I_END: PyErr_SetNone(PyExc_StopIteration); return NULL; case I_ITEM: { return (*(it->hi_yield))(key, val); } default: { Py_UNREACHABLE(); } } } static Py_ssize_t hamt_baseiter_tp_len(PyHamtIterator *it) { return it->hi_obj->h_count; } static PyMappingMethods PyHamtIterator_as_mapping = { (lenfunc)hamt_baseiter_tp_len, }; static PyObject * hamt_baseiter_new(PyTypeObject *type, binaryfunc yield, PyHamtObject *o) { PyHamtIterator *it = PyObject_GC_New(PyHamtIterator, type); if (it == NULL) { return NULL; } it->hi_obj = (PyHamtObject*)Py_NewRef(o); it->hi_yield = yield; hamt_iterator_init(&it->hi_iter, o->h_root); return (PyObject*)it; } #define ITERATOR_TYPE_SHARED_SLOTS \ .tp_basicsize = sizeof(PyHamtIterator), \ .tp_itemsize = 0, \ .tp_as_mapping = &PyHamtIterator_as_mapping, \ .tp_dealloc = (destructor)hamt_baseiter_tp_dealloc, \ .tp_getattro = PyObject_GenericGetAttr, \ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, \ .tp_traverse = (traverseproc)hamt_baseiter_tp_traverse, \ .tp_clear = (inquiry)hamt_baseiter_tp_clear, \ .tp_iter = PyObject_SelfIter, \ .tp_iternext = (iternextfunc)hamt_baseiter_tp_iternext, /////////////////////////////////// _PyHamtItems_Type PyTypeObject _PyHamtItems_Type = { PyVarObject_HEAD_INIT(NULL, 0) "items", ITERATOR_TYPE_SHARED_SLOTS }; static PyObject * hamt_iter_yield_items(PyObject *key, PyObject *val) { return PyTuple_Pack(2, key, val); } PyObject * _PyHamt_NewIterItems(PyHamtObject *o) { return hamt_baseiter_new( &_PyHamtItems_Type, hamt_iter_yield_items, o); } /////////////////////////////////// _PyHamtKeys_Type PyTypeObject _PyHamtKeys_Type = { PyVarObject_HEAD_INIT(NULL, 0) "keys", ITERATOR_TYPE_SHARED_SLOTS }; static PyObject * hamt_iter_yield_keys(PyObject *key, PyObject *val) { return Py_NewRef(key); } PyObject * _PyHamt_NewIterKeys(PyHamtObject *o) { return hamt_baseiter_new( &_PyHamtKeys_Type, hamt_iter_yield_keys, o); } /////////////////////////////////// _PyHamtValues_Type PyTypeObject _PyHamtValues_Type = { PyVarObject_HEAD_INIT(NULL, 0) "values", ITERATOR_TYPE_SHARED_SLOTS }; static PyObject * hamt_iter_yield_values(PyObject *key, PyObject *val) { return Py_NewRef(val); } PyObject * _PyHamt_NewIterValues(PyHamtObject *o) { return hamt_baseiter_new( &_PyHamtValues_Type, hamt_iter_yield_values, o); } /////////////////////////////////// _PyHamt_Type #ifdef Py_DEBUG static PyObject * hamt_dump(PyHamtObject *self); #endif static PyObject * hamt_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { return (PyObject*)_PyHamt_New(); } static int hamt_tp_clear(PyHamtObject *self) { Py_CLEAR(self->h_root); return 0; } static int hamt_tp_traverse(PyHamtObject *self, visitproc visit, void *arg) { Py_VISIT(self->h_root); return 0; } static void hamt_tp_dealloc(PyHamtObject *self) { if (self == _empty_hamt) { /* The empty one is statically allocated. */ #ifdef Py_DEBUG _Py_FatalRefcountError("deallocating the empty hamt singleton"); #else return; #endif } PyObject_GC_UnTrack(self); if (self->h_weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject*)self); } (void)hamt_tp_clear(self); Py_TYPE(self)->tp_free(self); } static PyObject * hamt_tp_richcompare(PyObject *v, PyObject *w, int op) { if (!PyHamt_Check(v) || !PyHamt_Check(w) || (op != Py_EQ && op != Py_NE)) { Py_RETURN_NOTIMPLEMENTED; } int res = _PyHamt_Eq((PyHamtObject *)v, (PyHamtObject *)w); if (res < 0) { return NULL; } if (op == Py_NE) { res = !res; } if (res) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } static int hamt_tp_contains(PyHamtObject *self, PyObject *key) { PyObject *val; return _PyHamt_Find(self, key, &val); } static PyObject * hamt_tp_subscript(PyHamtObject *self, PyObject *key) { PyObject *val; hamt_find_t res = hamt_find(self, key, &val); switch (res) { case F_ERROR: return NULL; case F_FOUND: return Py_NewRef(val); case F_NOT_FOUND: PyErr_SetObject(PyExc_KeyError, key); return NULL; default: Py_UNREACHABLE(); } } static Py_ssize_t hamt_tp_len(PyHamtObject *self) { return _PyHamt_Len(self); } static PyObject * hamt_tp_iter(PyHamtObject *self) { return _PyHamt_NewIterKeys(self); } static PyObject * hamt_py_set(PyHamtObject *self, PyObject *args) { PyObject *key; PyObject *val; if (!PyArg_UnpackTuple(args, "set", 2, 2, &key, &val)) { return NULL; } return (PyObject *)_PyHamt_Assoc(self, key, val); } static PyObject * hamt_py_get(PyHamtObject *self, PyObject *args) { PyObject *key; PyObject *def = NULL; if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def)) { return NULL; } PyObject *val = NULL; hamt_find_t res = hamt_find(self, key, &val); switch (res) { case F_ERROR: return NULL; case F_FOUND: return Py_NewRef(val); case F_NOT_FOUND: if (def == NULL) { Py_RETURN_NONE; } return Py_NewRef(def); default: Py_UNREACHABLE(); } } static PyObject * hamt_py_delete(PyHamtObject *self, PyObject *key) { return (PyObject *)_PyHamt_Without(self, key); } static PyObject * hamt_py_items(PyHamtObject *self, PyObject *args) { return _PyHamt_NewIterItems(self); } static PyObject * hamt_py_values(PyHamtObject *self, PyObject *args) { return _PyHamt_NewIterValues(self); } static PyObject * hamt_py_keys(PyHamtObject *self, PyObject *Py_UNUSED(args)) { return _PyHamt_NewIterKeys(self); } #ifdef Py_DEBUG static PyObject * hamt_py_dump(PyHamtObject *self, PyObject *Py_UNUSED(args)) { return hamt_dump(self); } #endif static PyMethodDef PyHamt_methods[] = { {"set", _PyCFunction_CAST(hamt_py_set), METH_VARARGS, NULL}, {"get", _PyCFunction_CAST(hamt_py_get), METH_VARARGS, NULL}, {"delete", _PyCFunction_CAST(hamt_py_delete), METH_O, NULL}, {"items", _PyCFunction_CAST(hamt_py_items), METH_NOARGS, NULL}, {"keys", _PyCFunction_CAST(hamt_py_keys), METH_NOARGS, NULL}, {"values", _PyCFunction_CAST(hamt_py_values), METH_NOARGS, NULL}, #ifdef Py_DEBUG {"__dump__", _PyCFunction_CAST(hamt_py_dump), METH_NOARGS, NULL}, #endif {NULL, NULL} }; static PySequenceMethods PyHamt_as_sequence = { 0, /* sq_length */ 0, /* sq_concat */ 0, /* sq_repeat */ 0, /* sq_item */ 0, /* sq_slice */ 0, /* sq_ass_item */ 0, /* sq_ass_slice */ (objobjproc)hamt_tp_contains, /* sq_contains */ 0, /* sq_inplace_concat */ 0, /* sq_inplace_repeat */ }; static PyMappingMethods PyHamt_as_mapping = { (lenfunc)hamt_tp_len, /* mp_length */ (binaryfunc)hamt_tp_subscript, /* mp_subscript */ }; PyTypeObject _PyHamt_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "hamt", sizeof(PyHamtObject), .tp_methods = PyHamt_methods, .tp_as_mapping = &PyHamt_as_mapping, .tp_as_sequence = &PyHamt_as_sequence, .tp_iter = (getiterfunc)hamt_tp_iter, .tp_dealloc = (destructor)hamt_tp_dealloc, .tp_getattro = PyObject_GenericGetAttr, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_richcompare = hamt_tp_richcompare, .tp_traverse = (traverseproc)hamt_tp_traverse, .tp_clear = (inquiry)hamt_tp_clear, .tp_new = hamt_tp_new, .tp_weaklistoffset = offsetof(PyHamtObject, h_weakreflist), .tp_hash = PyObject_HashNotImplemented, }; /////////////////////////////////// Tree Node Types PyTypeObject _PyHamt_ArrayNode_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "hamt_array_node", sizeof(PyHamtNode_Array), 0, .tp_dealloc = (destructor)hamt_node_array_dealloc, .tp_getattro = PyObject_GenericGetAttr, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = (traverseproc)hamt_node_array_traverse, .tp_free = PyObject_GC_Del, .tp_hash = PyObject_HashNotImplemented, }; PyTypeObject _PyHamt_BitmapNode_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "hamt_bitmap_node", sizeof(PyHamtNode_Bitmap) - sizeof(PyObject *), sizeof(PyObject *), .tp_dealloc = (destructor)hamt_node_bitmap_dealloc, .tp_getattro = PyObject_GenericGetAttr, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = (traverseproc)hamt_node_bitmap_traverse, .tp_free = PyObject_GC_Del, .tp_hash = PyObject_HashNotImplemented, }; PyTypeObject _PyHamt_CollisionNode_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "hamt_collision_node", sizeof(PyHamtNode_Collision) - sizeof(PyObject *), sizeof(PyObject *), .tp_dealloc = (destructor)hamt_node_collision_dealloc, .tp_getattro = PyObject_GenericGetAttr, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = (traverseproc)hamt_node_collision_traverse, .tp_free = PyObject_GC_Del, .tp_hash = PyObject_HashNotImplemented, }; ================================================ FILE: HashTable.c ================================================ /* The implementation of the hash table (_Py_hashtable_t) is based on the cfuhash project: http://sourceforge.net/projects/libcfu/ Copyright of cfuhash: ---------------------------------- Creation date: 2005-06-24 21:22:40 Authors: Don Change log: Copyright (c) 2005 Don Owens All rights reserved. This code is released under the BSD license: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------- */ #include "Python.h" #include "pycore_hashtable.h" #define HASHTABLE_MIN_SIZE 16 #define HASHTABLE_HIGH 0.50 #define HASHTABLE_LOW 0.10 #define HASHTABLE_REHASH_FACTOR 2.0 / (HASHTABLE_LOW + HASHTABLE_HIGH) #define BUCKETS_HEAD(SLIST) \ ((_Py_hashtable_entry_t *)_Py_SLIST_HEAD(&(SLIST))) #define TABLE_HEAD(HT, BUCKET) \ ((_Py_hashtable_entry_t *)_Py_SLIST_HEAD(&(HT)->buckets[BUCKET])) #define ENTRY_NEXT(ENTRY) \ ((_Py_hashtable_entry_t *)_Py_SLIST_ITEM_NEXT(ENTRY)) /* Forward declaration */ static int hashtable_rehash(_Py_hashtable_t *ht); static void _Py_slist_init(_Py_slist_t *list) { list->head = NULL; } static void _Py_slist_prepend(_Py_slist_t *list, _Py_slist_item_t *item) { item->next = list->head; list->head = item; } static void _Py_slist_remove(_Py_slist_t *list, _Py_slist_item_t *previous, _Py_slist_item_t *item) { if (previous != NULL) previous->next = item->next; else list->head = item->next; } Py_uhash_t _Py_hashtable_hash_ptr(const void *key) { return (Py_uhash_t)_Py_HashPointerRaw(key); } int _Py_hashtable_compare_direct(const void *key1, const void *key2) { return (key1 == key2); } /* makes sure the real size of the buckets array is a power of 2 */ static size_t round_size(size_t s) { size_t i; if (s < HASHTABLE_MIN_SIZE) return HASHTABLE_MIN_SIZE; i = 1; while (i < s) i <<= 1; return i; } size_t _Py_hashtable_size(const _Py_hashtable_t *ht) { size_t size = sizeof(_Py_hashtable_t); /* buckets */ size += ht->nbuckets * sizeof(_Py_hashtable_entry_t *); /* entries */ size += ht->nentries * sizeof(_Py_hashtable_entry_t); return size; } _Py_hashtable_entry_t * _Py_hashtable_get_entry_generic(_Py_hashtable_t *ht, const void *key) { Py_uhash_t key_hash = ht->hash_func(key); size_t index = key_hash & (ht->nbuckets - 1); _Py_hashtable_entry_t *entry = TABLE_HEAD(ht, index); while (1) { if (entry == NULL) { return NULL; } if (entry->key_hash == key_hash && ht->compare_func(key, entry->key)) { break; } entry = ENTRY_NEXT(entry); } return entry; } // Specialized for: // hash_func == _Py_hashtable_hash_ptr // compare_func == _Py_hashtable_compare_direct static _Py_hashtable_entry_t * _Py_hashtable_get_entry_ptr(_Py_hashtable_t *ht, const void *key) { Py_uhash_t key_hash = _Py_hashtable_hash_ptr(key); size_t index = key_hash & (ht->nbuckets - 1); _Py_hashtable_entry_t *entry = TABLE_HEAD(ht, index); while (1) { if (entry == NULL) { return NULL; } // Compare directly keys (ignore entry->key_hash) if (entry->key == key) { break; } entry = ENTRY_NEXT(entry); } return entry; } void* _Py_hashtable_steal(_Py_hashtable_t *ht, const void *key) { Py_uhash_t key_hash = ht->hash_func(key); size_t index = key_hash & (ht->nbuckets - 1); _Py_hashtable_entry_t *entry = TABLE_HEAD(ht, index); _Py_hashtable_entry_t *previous = NULL; while (1) { if (entry == NULL) { // not found return NULL; } if (entry->key_hash == key_hash && ht->compare_func(key, entry->key)) { break; } previous = entry; entry = ENTRY_NEXT(entry); } _Py_slist_remove(&ht->buckets[index], (_Py_slist_item_t *)previous, (_Py_slist_item_t *)entry); ht->nentries--; void *value = entry->value; ht->alloc.free(entry); if ((float)ht->nentries / (float)ht->nbuckets < HASHTABLE_LOW) { // Ignore failure: error cannot be reported to the caller hashtable_rehash(ht); } return value; } int _Py_hashtable_set(_Py_hashtable_t *ht, const void *key, void *value) { _Py_hashtable_entry_t *entry; #ifndef NDEBUG /* Don't write the assertion on a single line because it is interesting to know the duplicated entry if the assertion failed. The entry can be read using a debugger. */ entry = ht->get_entry_func(ht, key); assert(entry == NULL); #endif entry = ht->alloc.malloc(sizeof(_Py_hashtable_entry_t)); if (entry == NULL) { /* memory allocation failed */ return -1; } entry->key_hash = ht->hash_func(key); entry->key = (void *)key; entry->value = value; ht->nentries++; if ((float)ht->nentries / (float)ht->nbuckets > HASHTABLE_HIGH) { if (hashtable_rehash(ht) < 0) { ht->nentries--; ht->alloc.free(entry); return -1; } } size_t index = entry->key_hash & (ht->nbuckets - 1); _Py_slist_prepend(&ht->buckets[index], (_Py_slist_item_t*)entry); return 0; } void* _Py_hashtable_get(_Py_hashtable_t *ht, const void *key) { _Py_hashtable_entry_t *entry = ht->get_entry_func(ht, key); if (entry != NULL) { return entry->value; } else { return NULL; } } int _Py_hashtable_foreach(_Py_hashtable_t *ht, _Py_hashtable_foreach_func func, void *user_data) { for (size_t hv = 0; hv < ht->nbuckets; hv++) { _Py_hashtable_entry_t *entry = TABLE_HEAD(ht, hv); while (entry != NULL) { int res = func(ht, entry->key, entry->value, user_data); if (res) { return res; } entry = ENTRY_NEXT(entry); } } return 0; } static int hashtable_rehash(_Py_hashtable_t *ht) { size_t new_size = round_size((size_t)(ht->nentries * HASHTABLE_REHASH_FACTOR)); if (new_size == ht->nbuckets) { return 0; } size_t buckets_size = new_size * sizeof(ht->buckets[0]); _Py_slist_t *new_buckets = ht->alloc.malloc(buckets_size); if (new_buckets == NULL) { /* memory allocation failed */ return -1; } memset(new_buckets, 0, buckets_size); for (size_t bucket = 0; bucket < ht->nbuckets; bucket++) { _Py_hashtable_entry_t *entry = BUCKETS_HEAD(ht->buckets[bucket]); while (entry != NULL) { assert(ht->hash_func(entry->key) == entry->key_hash); _Py_hashtable_entry_t *next = ENTRY_NEXT(entry); size_t entry_index = entry->key_hash & (new_size - 1); _Py_slist_prepend(&new_buckets[entry_index], (_Py_slist_item_t*)entry); entry = next; } } ht->alloc.free(ht->buckets); ht->nbuckets = new_size; ht->buckets = new_buckets; return 0; } _Py_hashtable_t * _Py_hashtable_new_full(_Py_hashtable_hash_func hash_func, _Py_hashtable_compare_func compare_func, _Py_hashtable_destroy_func key_destroy_func, _Py_hashtable_destroy_func value_destroy_func, _Py_hashtable_allocator_t *allocator) { _Py_hashtable_allocator_t alloc; if (allocator == NULL) { alloc.malloc = PyMem_Malloc; alloc.free = PyMem_Free; } else { alloc = *allocator; } _Py_hashtable_t *ht = (_Py_hashtable_t *)alloc.malloc(sizeof(_Py_hashtable_t)); if (ht == NULL) { return ht; } ht->nbuckets = HASHTABLE_MIN_SIZE; ht->nentries = 0; size_t buckets_size = ht->nbuckets * sizeof(ht->buckets[0]); ht->buckets = alloc.malloc(buckets_size); if (ht->buckets == NULL) { alloc.free(ht); return NULL; } memset(ht->buckets, 0, buckets_size); ht->get_entry_func = _Py_hashtable_get_entry_generic; ht->hash_func = hash_func; ht->compare_func = compare_func; ht->key_destroy_func = key_destroy_func; ht->value_destroy_func = value_destroy_func; ht->alloc = alloc; if (ht->hash_func == _Py_hashtable_hash_ptr && ht->compare_func == _Py_hashtable_compare_direct) { ht->get_entry_func = _Py_hashtable_get_entry_ptr; } return ht; } _Py_hashtable_t * _Py_hashtable_new(_Py_hashtable_hash_func hash_func, _Py_hashtable_compare_func compare_func) { return _Py_hashtable_new_full(hash_func, compare_func, NULL, NULL, NULL); } static void _Py_hashtable_destroy_entry(_Py_hashtable_t *ht, _Py_hashtable_entry_t *entry) { if (ht->key_destroy_func) { ht->key_destroy_func(entry->key); } if (ht->value_destroy_func) { ht->value_destroy_func(entry->value); } ht->alloc.free(entry); } void _Py_hashtable_clear(_Py_hashtable_t *ht) { for (size_t i=0; i < ht->nbuckets; i++) { _Py_hashtable_entry_t *entry = TABLE_HEAD(ht, i); while (entry != NULL) { _Py_hashtable_entry_t *next = ENTRY_NEXT(entry); _Py_hashtable_destroy_entry(ht, entry); entry = next; } _Py_slist_init(&ht->buckets[i]); } ht->nentries = 0; // Ignore failure: clear function is not expected to fail // because of a memory allocation failure. (void)hashtable_rehash(ht); } void _Py_hashtable_destroy(_Py_hashtable_t *ht) { for (size_t i = 0; i < ht->nbuckets; i++) { _Py_hashtable_entry_t *entry = TABLE_HEAD(ht, i); while (entry) { _Py_hashtable_entry_t *entry_next = ENTRY_NEXT(entry); _Py_hashtable_destroy_entry(ht, entry); entry = entry_next; } } ht->alloc.free(ht->buckets); ht->alloc.free(ht); } ================================================ FILE: ImPort.c ================================================ /* Module definition and import implementation */ #include "Python.h" #include "pycore_import.h" // _PyImport_BootstrapImp() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_interp.h" // struct _import_runtime_state #include "pycore_namespace.h" // _PyNamespace_Type #include "pycore_pyerrors.h" // _PyErr_SetString() #include "pycore_pyhash.h" // _Py_KeyedHash() #include "pycore_pylifecycle.h" #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_sysmodule.h" // _PySys_Audit() #include "marshal.h" // PyMarshal_ReadObjectFromString() #include "importdl.h" // _PyImport_DynLoadFiletab #include "pydtrace.h" // PyDTrace_IMPORT_FIND_LOAD_START_ENABLED() #include // bool #ifdef HAVE_FCNTL_H #include #endif #ifdef __cplusplus extern "C" { #endif /*[clinic input] module _imp [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=9c332475d8686284]*/ #include "clinic/import.c.h" /*******************************/ /* process-global import state */ /*******************************/ /* This table is defined in config.c: */ extern struct _inittab _PyImport_Inittab[]; // This is not used after Py_Initialize() is called. // (See _PyRuntimeState.imports.inittab.) struct _inittab *PyImport_Inittab = _PyImport_Inittab; // When we dynamically allocate a larger table for PyImport_ExtendInittab(), // we track the pointer here so we can deallocate it during finalization. static struct _inittab *inittab_copy = NULL; /*******************************/ /* runtime-global import state */ /*******************************/ #define INITTAB _PyRuntime.imports.inittab #define LAST_MODULE_INDEX _PyRuntime.imports.last_module_index #define EXTENSIONS _PyRuntime.imports.extensions #define PKGCONTEXT (_PyRuntime.imports.pkgcontext) /*******************************/ /* interpreter import state */ /*******************************/ #define MODULES(interp) \ (interp)->imports.modules #define MODULES_BY_INDEX(interp) \ (interp)->imports.modules_by_index #define IMPORTLIB(interp) \ (interp)->imports.importlib #define OVERRIDE_MULTI_INTERP_EXTENSIONS_CHECK(interp) \ (interp)->imports.override_multi_interp_extensions_check #define OVERRIDE_FROZEN_MODULES(interp) \ (interp)->imports.override_frozen_modules #ifdef HAVE_DLOPEN # define DLOPENFLAGS(interp) \ (interp)->imports.dlopenflags #endif #define IMPORT_FUNC(interp) \ (interp)->imports.import_func #define IMPORT_LOCK(interp) \ (interp)->imports.lock.mutex #define IMPORT_LOCK_THREAD(interp) \ (interp)->imports.lock.thread #define IMPORT_LOCK_LEVEL(interp) \ (interp)->imports.lock.level #define FIND_AND_LOAD(interp) \ (interp)->imports.find_and_load /*******************/ /* the import lock */ /*******************/ /* Locking primitives to prevent parallel imports of the same module in different threads to return with a partially loaded module. These calls are serialized by the global interpreter lock. */ void _PyImport_AcquireLock(PyInterpreterState *interp) { unsigned long me = PyThread_get_thread_ident(); if (me == PYTHREAD_INVALID_THREAD_ID) return; /* Too bad */ if (IMPORT_LOCK(interp) == NULL) { IMPORT_LOCK(interp) = PyThread_allocate_lock(); if (IMPORT_LOCK(interp) == NULL) return; /* Nothing much we can do. */ } if (IMPORT_LOCK_THREAD(interp) == me) { IMPORT_LOCK_LEVEL(interp)++; return; } if (IMPORT_LOCK_THREAD(interp) != PYTHREAD_INVALID_THREAD_ID || !PyThread_acquire_lock(IMPORT_LOCK(interp), 0)) { PyThreadState *tstate = PyEval_SaveThread(); PyThread_acquire_lock(IMPORT_LOCK(interp), WAIT_LOCK); PyEval_RestoreThread(tstate); } assert(IMPORT_LOCK_LEVEL(interp) == 0); IMPORT_LOCK_THREAD(interp) = me; IMPORT_LOCK_LEVEL(interp) = 1; } int _PyImport_ReleaseLock(PyInterpreterState *interp) { unsigned long me = PyThread_get_thread_ident(); if (me == PYTHREAD_INVALID_THREAD_ID || IMPORT_LOCK(interp) == NULL) return 0; /* Too bad */ if (IMPORT_LOCK_THREAD(interp) != me) return -1; IMPORT_LOCK_LEVEL(interp)--; assert(IMPORT_LOCK_LEVEL(interp) >= 0); if (IMPORT_LOCK_LEVEL(interp) == 0) { IMPORT_LOCK_THREAD(interp) = PYTHREAD_INVALID_THREAD_ID; PyThread_release_lock(IMPORT_LOCK(interp)); } return 1; } #ifdef HAVE_FORK /* This function is called from PyOS_AfterFork_Child() to ensure that newly created child processes do not share locks with the parent. We now acquire the import lock around fork() calls but on some platforms (Solaris 9 and earlier? see isue7242) that still left us with problems. */ PyStatus _PyImport_ReInitLock(PyInterpreterState *interp) { if (IMPORT_LOCK(interp) != NULL) { if (_PyThread_at_fork_reinit(&IMPORT_LOCK(interp)) < 0) { return _PyStatus_ERR("failed to create a new lock"); } } if (IMPORT_LOCK_LEVEL(interp) > 1) { /* Forked as a side effect of import */ unsigned long me = PyThread_get_thread_ident(); PyThread_acquire_lock(IMPORT_LOCK(interp), WAIT_LOCK); IMPORT_LOCK_THREAD(interp) = me; IMPORT_LOCK_LEVEL(interp)--; } else { IMPORT_LOCK_THREAD(interp) = PYTHREAD_INVALID_THREAD_ID; IMPORT_LOCK_LEVEL(interp) = 0; } return _PyStatus_OK(); } #endif /***************/ /* sys.modules */ /***************/ PyObject * _PyImport_InitModules(PyInterpreterState *interp) { assert(MODULES(interp) == NULL); MODULES(interp) = PyDict_New(); if (MODULES(interp) == NULL) { return NULL; } return MODULES(interp); } PyObject * _PyImport_GetModules(PyInterpreterState *interp) { return MODULES(interp); } void _PyImport_ClearModules(PyInterpreterState *interp) { Py_SETREF(MODULES(interp), NULL); } PyObject * PyImport_GetModuleDict(void) { PyInterpreterState *interp = _PyInterpreterState_GET(); if (MODULES(interp) == NULL) { Py_FatalError("interpreter has no modules dictionary"); } return MODULES(interp); } // This is only kept around for extensions that use _Py_IDENTIFIER. PyObject * _PyImport_GetModuleId(_Py_Identifier *nameid) { PyObject *name = _PyUnicode_FromId(nameid); /* borrowed */ if (name == NULL) { return NULL; } return PyImport_GetModule(name); } int _PyImport_SetModule(PyObject *name, PyObject *m) { PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *modules = MODULES(interp); return PyObject_SetItem(modules, name, m); } int _PyImport_SetModuleString(const char *name, PyObject *m) { PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *modules = MODULES(interp); return PyMapping_SetItemString(modules, name, m); } static PyObject * import_get_module(PyThreadState *tstate, PyObject *name) { PyObject *modules = MODULES(tstate->interp); if (modules == NULL) { _PyErr_SetString(tstate, PyExc_RuntimeError, "unable to get sys.modules"); return NULL; } PyObject *m; Py_INCREF(modules); if (PyDict_CheckExact(modules)) { m = PyDict_GetItemWithError(modules, name); /* borrowed */ Py_XINCREF(m); } else { m = PyObject_GetItem(modules, name); if (m == NULL && _PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { _PyErr_Clear(tstate); } } Py_DECREF(modules); return m; } static int import_ensure_initialized(PyInterpreterState *interp, PyObject *mod, PyObject *name) { PyObject *spec; /* Optimization: only call _bootstrap._lock_unlock_module() if __spec__._initializing is true. NOTE: because of this, initializing must be set *before* stuffing the new module in sys.modules. */ spec = PyObject_GetAttr(mod, &_Py_ID(__spec__)); int busy = _PyModuleSpec_IsInitializing(spec); Py_XDECREF(spec); if (busy) { /* Wait until module is done importing. */ PyObject *value = _PyObject_CallMethodOneArg( IMPORTLIB(interp), &_Py_ID(_lock_unlock_module), name); if (value == NULL) { return -1; } Py_DECREF(value); } return 0; } static void remove_importlib_frames(PyThreadState *tstate); PyObject * PyImport_GetModule(PyObject *name) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *mod; mod = import_get_module(tstate, name); if (mod != NULL && mod != Py_None) { if (import_ensure_initialized(tstate->interp, mod, name) < 0) { Py_DECREF(mod); remove_importlib_frames(tstate); return NULL; } } return mod; } /* Get the module object corresponding to a module name. First check the modules dictionary if there's one there, if not, create a new one and insert it in the modules dictionary. */ static PyObject * import_add_module(PyThreadState *tstate, PyObject *name) { PyObject *modules = MODULES(tstate->interp); if (modules == NULL) { _PyErr_SetString(tstate, PyExc_RuntimeError, "no import module dictionary"); return NULL; } PyObject *m; if (PyDict_CheckExact(modules)) { m = Py_XNewRef(PyDict_GetItemWithError(modules, name)); } else { m = PyObject_GetItem(modules, name); // For backward-compatibility we copy the behavior // of PyDict_GetItemWithError(). if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { _PyErr_Clear(tstate); } } if (_PyErr_Occurred(tstate)) { return NULL; } if (m != NULL && PyModule_Check(m)) { return m; } Py_XDECREF(m); m = PyModule_NewObject(name); if (m == NULL) return NULL; if (PyObject_SetItem(modules, name, m) != 0) { Py_DECREF(m); return NULL; } return m; } PyObject * PyImport_AddModuleObject(PyObject *name) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *mod = import_add_module(tstate, name); if (mod) { PyObject *ref = PyWeakref_NewRef(mod, NULL); Py_DECREF(mod); if (ref == NULL) { return NULL; } mod = PyWeakref_GetObject(ref); Py_DECREF(ref); } return mod; /* borrowed reference */ } PyObject * PyImport_AddModule(const char *name) { PyObject *nameobj = PyUnicode_FromString(name); if (nameobj == NULL) { return NULL; } PyObject *module = PyImport_AddModuleObject(nameobj); Py_DECREF(nameobj); return module; } /* Remove name from sys.modules, if it's there. * Can be called with an exception raised. * If fail to remove name a new exception will be chained with the old * exception, otherwise the old exception is preserved. */ static void remove_module(PyThreadState *tstate, PyObject *name) { PyObject *exc = _PyErr_GetRaisedException(tstate); PyObject *modules = MODULES(tstate->interp); if (PyDict_CheckExact(modules)) { PyObject *mod = _PyDict_Pop(modules, name, Py_None); Py_XDECREF(mod); } else if (PyMapping_DelItem(modules, name) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { _PyErr_Clear(tstate); } } _PyErr_ChainExceptions1(exc); } /************************************/ /* per-interpreter modules-by-index */ /************************************/ Py_ssize_t _PyImport_GetNextModuleIndex(void) { PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK); LAST_MODULE_INDEX++; Py_ssize_t index = LAST_MODULE_INDEX; PyThread_release_lock(EXTENSIONS.mutex); return index; } static const char * _modules_by_index_check(PyInterpreterState *interp, Py_ssize_t index) { if (index == 0) { return "invalid module index"; } if (MODULES_BY_INDEX(interp) == NULL) { return "Interpreters module-list not accessible."; } if (index > PyList_GET_SIZE(MODULES_BY_INDEX(interp))) { return "Module index out of bounds."; } return NULL; } static PyObject * _modules_by_index_get(PyInterpreterState *interp, PyModuleDef *def) { Py_ssize_t index = def->m_base.m_index; if (_modules_by_index_check(interp, index) != NULL) { return NULL; } PyObject *res = PyList_GET_ITEM(MODULES_BY_INDEX(interp), index); return res==Py_None ? NULL : res; } static int _modules_by_index_set(PyInterpreterState *interp, PyModuleDef *def, PyObject *module) { assert(def != NULL); assert(def->m_slots == NULL); assert(def->m_base.m_index > 0); if (MODULES_BY_INDEX(interp) == NULL) { MODULES_BY_INDEX(interp) = PyList_New(0); if (MODULES_BY_INDEX(interp) == NULL) { return -1; } } Py_ssize_t index = def->m_base.m_index; while (PyList_GET_SIZE(MODULES_BY_INDEX(interp)) <= index) { if (PyList_Append(MODULES_BY_INDEX(interp), Py_None) < 0) { return -1; } } return PyList_SetItem(MODULES_BY_INDEX(interp), index, Py_NewRef(module)); } static int _modules_by_index_clear_one(PyInterpreterState *interp, PyModuleDef *def) { Py_ssize_t index = def->m_base.m_index; const char *err = _modules_by_index_check(interp, index); if (err != NULL) { Py_FatalError(err); return -1; } return PyList_SetItem(MODULES_BY_INDEX(interp), index, Py_NewRef(Py_None)); } PyObject* PyState_FindModule(PyModuleDef* module) { PyInterpreterState *interp = _PyInterpreterState_GET(); if (module->m_slots) { return NULL; } return _modules_by_index_get(interp, module); } /* _PyState_AddModule() has been completely removed from the C-API (and was removed from the limited API in 3.6). However, we're playing it safe and keeping it around for any stable ABI extensions built against 3.2-3.5. */ int _PyState_AddModule(PyThreadState *tstate, PyObject* module, PyModuleDef* def) { if (!def) { assert(_PyErr_Occurred(tstate)); return -1; } if (def->m_slots) { _PyErr_SetString(tstate, PyExc_SystemError, "PyState_AddModule called on module with slots"); return -1; } return _modules_by_index_set(tstate->interp, def, module); } int PyState_AddModule(PyObject* module, PyModuleDef* def) { if (!def) { Py_FatalError("module definition is NULL"); return -1; } PyThreadState *tstate = _PyThreadState_GET(); if (def->m_slots) { _PyErr_SetString(tstate, PyExc_SystemError, "PyState_AddModule called on module with slots"); return -1; } PyInterpreterState *interp = tstate->interp; Py_ssize_t index = def->m_base.m_index; if (MODULES_BY_INDEX(interp) && index < PyList_GET_SIZE(MODULES_BY_INDEX(interp)) && module == PyList_GET_ITEM(MODULES_BY_INDEX(interp), index)) { _Py_FatalErrorFormat(__func__, "module %p already added", module); return -1; } return _modules_by_index_set(interp, def, module); } int PyState_RemoveModule(PyModuleDef* def) { PyThreadState *tstate = _PyThreadState_GET(); if (def->m_slots) { _PyErr_SetString(tstate, PyExc_SystemError, "PyState_RemoveModule called on module with slots"); return -1; } return _modules_by_index_clear_one(tstate->interp, def); } // Used by finalize_modules() void _PyImport_ClearModulesByIndex(PyInterpreterState *interp) { if (!MODULES_BY_INDEX(interp)) { return; } Py_ssize_t i; for (i = 0; i < PyList_GET_SIZE(MODULES_BY_INDEX(interp)); i++) { PyObject *m = PyList_GET_ITEM(MODULES_BY_INDEX(interp), i); if (PyModule_Check(m)) { /* cleanup the saved copy of module dicts */ PyModuleDef *md = PyModule_GetDef(m); if (md) { Py_CLEAR(md->m_base.m_copy); } } } /* Setting modules_by_index to NULL could be dangerous, so we clear the list instead. */ if (PyList_SetSlice(MODULES_BY_INDEX(interp), 0, PyList_GET_SIZE(MODULES_BY_INDEX(interp)), NULL)) { PyErr_WriteUnraisable(MODULES_BY_INDEX(interp)); } } /*********************/ /* extension modules */ /*********************/ /* It may help to have a big picture view of what happens when an extension is loaded. This includes when it is imported for the first time. Here's a summary, using importlib._boostrap._load() as a starting point. 1. importlib._bootstrap._load() 2. _load(): acquire import lock 3. _load() -> importlib._bootstrap._load_unlocked() 4. _load_unlocked() -> importlib._bootstrap.module_from_spec() 5. module_from_spec() -> ExtensionFileLoader.create_module() 6. create_module() -> _imp.create_dynamic() (see below) 7. module_from_spec() -> importlib._bootstrap._init_module_attrs() 8. _load_unlocked(): sys.modules[name] = module 9. _load_unlocked() -> ExtensionFileLoader.exec_module() 10. exec_module() -> _imp.exec_dynamic() (see below) 11. _load(): release import lock ...for single-phase init modules, where m_size == -1: (6). first time (not found in _PyRuntime.imports.extensions): 1. _imp_create_dynamic_impl() -> import_find_extension() 2. _imp_create_dynamic_impl() -> _PyImport_LoadDynamicModuleWithSpec() 3. _PyImport_LoadDynamicModuleWithSpec(): load 4. _PyImport_LoadDynamicModuleWithSpec(): call 5. -> PyModule_Create() -> PyModule_Create2() -> PyModule_CreateInitialized() 6. PyModule_CreateInitialized() -> PyModule_New() 7. PyModule_CreateInitialized(): allocate mod->md_state 8. PyModule_CreateInitialized() -> PyModule_AddFunctions() 9. PyModule_CreateInitialized() -> PyModule_SetDocString() 10. PyModule_CreateInitialized(): set mod->md_def 11. : initialize the module 12. _PyImport_LoadDynamicModuleWithSpec() -> _PyImport_CheckSubinterpIncompatibleExtensionAllowed() 13. _PyImport_LoadDynamicModuleWithSpec(): set def->m_base.m_init 14. _PyImport_LoadDynamicModuleWithSpec(): set __file__ 15. _PyImport_LoadDynamicModuleWithSpec() -> _PyImport_FixupExtensionObject() 16. _PyImport_FixupExtensionObject(): add it to interp->imports.modules_by_index 17. _PyImport_FixupExtensionObject(): copy __dict__ into def->m_base.m_copy 18. _PyImport_FixupExtensionObject(): add it to _PyRuntime.imports.extensions (6). subsequent times (found in _PyRuntime.imports.extensions): 1. _imp_create_dynamic_impl() -> import_find_extension() 2. import_find_extension() -> import_add_module() 3. if name in sys.modules: use that module 4. else: 1. import_add_module() -> PyModule_NewObject() 2. import_add_module(): set it on sys.modules 5. import_find_extension(): copy the "m_copy" dict into __dict__ 6. _imp_create_dynamic_impl() -> _PyImport_CheckSubinterpIncompatibleExtensionAllowed() (10). (every time): 1. noop ...for single-phase init modules, where m_size >= 0: (6). not main interpreter and never loaded there - every time (not found in _PyRuntime.imports.extensions): 1-16. (same as for m_size == -1) (6). main interpreter - first time (not found in _PyRuntime.imports.extensions): 1-16. (same as for m_size == -1) 17. _PyImport_FixupExtensionObject(): add it to _PyRuntime.imports.extensions (6). previously loaded in main interpreter (found in _PyRuntime.imports.extensions): 1. _imp_create_dynamic_impl() -> import_find_extension() 2. import_find_extension(): call def->m_base.m_init 3. import_find_extension(): add the module to sys.modules (10). every time: 1. noop ...for multi-phase init modules: (6). every time: 1. _imp_create_dynamic_impl() -> import_find_extension() (not found) 2. _imp_create_dynamic_impl() -> _PyImport_LoadDynamicModuleWithSpec() 3. _PyImport_LoadDynamicModuleWithSpec(): load module init func 4. _PyImport_LoadDynamicModuleWithSpec(): call module init func 5. _PyImport_LoadDynamicModuleWithSpec() -> PyModule_FromDefAndSpec() 6. PyModule_FromDefAndSpec(): gather/check moduledef slots 7. if there's a Py_mod_create slot: 1. PyModule_FromDefAndSpec(): call its function 8. else: 1. PyModule_FromDefAndSpec() -> PyModule_NewObject() 9: PyModule_FromDefAndSpec(): set mod->md_def 10. PyModule_FromDefAndSpec() -> _add_methods_to_object() 11. PyModule_FromDefAndSpec() -> PyModule_SetDocString() (10). every time: 1. _imp_exec_dynamic_impl() -> exec_builtin_or_dynamic() 2. if mod->md_state == NULL (including if m_size == 0): 1. exec_builtin_or_dynamic() -> PyModule_ExecDef() 2. PyModule_ExecDef(): allocate mod->md_state 3. if there's a Py_mod_exec slot: 1. PyModule_ExecDef(): call its function */ /* Make sure name is fully qualified. This is a bit of a hack: when the shared library is loaded, the module name is "package.module", but the module calls PyModule_Create*() with just "module" for the name. The shared library loader squirrels away the true name of the module in _PyRuntime.imports.pkgcontext, and PyModule_Create*() will substitute this (if the name actually matches). */ const char * _PyImport_ResolveNameWithPackageContext(const char *name) { PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK); if (PKGCONTEXT != NULL) { const char *p = strrchr(PKGCONTEXT, '.'); if (p != NULL && strcmp(name, p+1) == 0) { name = PKGCONTEXT; PKGCONTEXT = NULL; } } PyThread_release_lock(EXTENSIONS.mutex); return name; } const char * _PyImport_SwapPackageContext(const char *newcontext) { PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK); const char *oldcontext = PKGCONTEXT; PKGCONTEXT = newcontext; PyThread_release_lock(EXTENSIONS.mutex); return oldcontext; } #ifdef HAVE_DLOPEN int _PyImport_GetDLOpenFlags(PyInterpreterState *interp) { return DLOPENFLAGS(interp); } void _PyImport_SetDLOpenFlags(PyInterpreterState *interp, int new_val) { DLOPENFLAGS(interp) = new_val; } #endif // HAVE_DLOPEN /* Common implementation for _imp.exec_dynamic and _imp.exec_builtin */ static int exec_builtin_or_dynamic(PyObject *mod) { PyModuleDef *def; void *state; if (!PyModule_Check(mod)) { return 0; } def = PyModule_GetDef(mod); if (def == NULL) { return 0; } state = PyModule_GetState(mod); if (state) { /* Already initialized; skip reload */ return 0; } return PyModule_ExecDef(mod, def); } static int clear_singlephase_extension(PyInterpreterState *interp, PyObject *name, PyObject *filename); // Currently, this is only used for testing. // (See _testinternalcapi.clear_extension().) int _PyImport_ClearExtension(PyObject *name, PyObject *filename) { PyInterpreterState *interp = _PyInterpreterState_GET(); /* Clearing a module's C globals is up to the module. */ if (clear_singlephase_extension(interp, name, filename) < 0) { return -1; } // In the future we'll probably also make sure the extension's // file handle (and DL handle) is closed (requires saving it). return 0; } /*******************/ #if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE) #include EM_JS(PyObject*, _PyImport_InitFunc_TrampolineCall, (PyModInitFunction func), { return wasmTable.get(func)(); }); #endif // __EMSCRIPTEN__ && PY_CALL_TRAMPOLINE /*****************************/ /* single-phase init modules */ /*****************************/ /* We support a number of kinds of single-phase init builtin/extension modules: * "basic" * no module state (PyModuleDef.m_size == -1) * does not support repeated init (we use PyModuleDef.m_base.m_copy) * may have process-global state * the module's def is cached in _PyRuntime.imports.extensions, by (name, filename) * "reinit" * no module state (PyModuleDef.m_size == 0) * supports repeated init (m_copy is never used) * should not have any process-global state * its def is never cached in _PyRuntime.imports.extensions (except, currently, under the main interpreter, for some reason) * "with state" (almost the same as reinit) * has module state (PyModuleDef.m_size > 0) * supports repeated init (m_copy is never used) * should not have any process-global state * its def is never cached in _PyRuntime.imports.extensions (except, currently, under the main interpreter, for some reason) There are also variants within those classes: * two or more modules share a PyModuleDef * a module's init func uses another module's PyModuleDef * a module's init func calls another's module's init func * a module's init "func" is actually a variable statically initialized to another module's init func * two or modules share "methods" * a module's init func copies another module's PyModuleDef (with a different name) * (basic-only) two or modules share process-global state In the first case, where modules share a PyModuleDef, the following notable weirdness happens: * the module's __name__ matches the def, not the requested name * the last module (with the same def) to be imported for the first time wins * returned by PyState_Find_Module() (via interp->modules_by_index) * (non-basic-only) its init func is used when re-loading any of them (via the def's m_init) * (basic-only) the copy of its __dict__ is used when re-loading any of them (via the def's m_copy) However, the following happens as expected: * a new module object (with its own __dict__) is created for each request * the module's __spec__ has the requested name * the loaded module is cached in sys.modules under the requested name * the m_index field of the shared def is not changed, so at least PyState_FindModule() will always look in the same place For "basic" modules there are other quirks: * (whether sharing a def or not) when loaded the first time, m_copy is set before _init_module_attrs() is called in importlib._bootstrap.module_from_spec(), so when the module is re-loaded, the previous value for __wpec__ (and others) is reset, possibly unexpectedly. Generally, when multiple interpreters are involved, some of the above gets even messier. */ static inline void extensions_lock_acquire(void) { PyThread_acquire_lock(_PyRuntime.imports.extensions.mutex, WAIT_LOCK); } static inline void extensions_lock_release(void) { PyThread_release_lock(_PyRuntime.imports.extensions.mutex); } /* Magic for extension modules (built-in as well as dynamically loaded). To prevent initializing an extension module more than once, we keep a static dictionary 'extensions' keyed by the tuple (module name, module name) (for built-in modules) or by (filename, module name) (for dynamically loaded modules), containing these modules. A copy of the module's dictionary is stored by calling _PyImport_FixupExtensionObject() immediately after the module initialization function succeeds. A copy can be retrieved from there by calling import_find_extension(). Modules which do support multiple initialization set their m_size field to a non-negative number (indicating the size of the module-specific state). They are still recorded in the extensions dictionary, to avoid loading shared libraries twice. */ static void _extensions_cache_init(void) { /* The runtime (i.e. main interpreter) must be initializing, so we don't need to worry about the lock. */ _PyThreadState_InitDetached(&EXTENSIONS.main_tstate, _PyInterpreterState_Main()); } static PyModuleDef * _extensions_cache_get(PyObject *filename, PyObject *name) { PyModuleDef *def = NULL; extensions_lock_acquire(); PyObject *key = PyTuple_Pack(2, filename, name); if (key == NULL) { goto finally; } PyObject *extensions = EXTENSIONS.dict; if (extensions == NULL) { goto finally; } def = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); finally: Py_XDECREF(key); extensions_lock_release(); return def; } static int _extensions_cache_set(PyObject *filename, PyObject *name, PyModuleDef *def) { int res = -1; PyThreadState *oldts = NULL; extensions_lock_acquire(); /* Swap to the main interpreter, if necessary. This matters if the dict hasn't been created yet or if the item isn't in the dict yet. In both cases we must ensure the relevant objects are created using the main interpreter. */ PyThreadState *main_tstate = &EXTENSIONS.main_tstate; PyInterpreterState *interp = _PyInterpreterState_GET(); if (!_Py_IsMainInterpreter(interp)) { _PyThreadState_BindDetached(main_tstate); oldts = _PyThreadState_Swap(interp->runtime, main_tstate); assert(!_Py_IsMainInterpreter(oldts->interp)); /* Make sure the name and filename objects are owned by the main interpreter. */ name = PyUnicode_InternFromString(PyUnicode_AsUTF8(name)); assert(name != NULL); filename = PyUnicode_InternFromString(PyUnicode_AsUTF8(filename)); assert(filename != NULL); } PyObject *key = PyTuple_Pack(2, filename, name); if (key == NULL) { goto finally; } PyObject *extensions = EXTENSIONS.dict; if (extensions == NULL) { extensions = PyDict_New(); if (extensions == NULL) { goto finally; } EXTENSIONS.dict = extensions; } PyModuleDef *actual = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); if (PyErr_Occurred()) { goto finally; } else if (actual != NULL) { /* We expect it to be static, so it must be the same pointer. */ assert(def == actual); res = 0; goto finally; } /* This might trigger a resize, which is why we must switch to the main interpreter. */ res = PyDict_SetItem(extensions, key, (PyObject *)def); if (res < 0) { res = -1; goto finally; } res = 0; finally: Py_XDECREF(key); if (oldts != NULL) { _PyThreadState_Swap(interp->runtime, oldts); _PyThreadState_UnbindDetached(main_tstate); Py_DECREF(name); Py_DECREF(filename); } extensions_lock_release(); return res; } static int _extensions_cache_delete(PyObject *filename, PyObject *name) { int res = -1; PyThreadState *oldts = NULL; extensions_lock_acquire(); PyObject *key = PyTuple_Pack(2, filename, name); if (key == NULL) { goto finally; } PyObject *extensions = EXTENSIONS.dict; if (extensions == NULL) { res = 0; goto finally; } PyModuleDef *actual = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); if (PyErr_Occurred()) { goto finally; } else if (actual == NULL) { /* It was already removed or never added. */ res = 0; goto finally; } /* Swap to the main interpreter, if necessary. */ PyThreadState *main_tstate = &EXTENSIONS.main_tstate; PyInterpreterState *interp = _PyInterpreterState_GET(); if (!_Py_IsMainInterpreter(interp)) { _PyThreadState_BindDetached(main_tstate); oldts = _PyThreadState_Swap(interp->runtime, main_tstate); assert(!_Py_IsMainInterpreter(oldts->interp)); } if (PyDict_DelItem(extensions, key) < 0) { goto finally; } res = 0; finally: if (oldts != NULL) { _PyThreadState_Swap(interp->runtime, oldts); _PyThreadState_UnbindDetached(main_tstate); } Py_XDECREF(key); extensions_lock_release(); return res; } static void _extensions_cache_clear_all(void) { /* The runtime (i.e. main interpreter) must be finalizing, so we don't need to worry about the lock. */ // XXX assert(_Py_IsMainInterpreter(_PyInterpreterState_GET())); Py_CLEAR(EXTENSIONS.dict); _PyThreadState_ClearDetached(&EXTENSIONS.main_tstate); } static bool check_multi_interp_extensions(PyInterpreterState *interp) { int override = OVERRIDE_MULTI_INTERP_EXTENSIONS_CHECK(interp); if (override < 0) { return false; } else if (override > 0) { return true; } else if (_PyInterpreterState_HasFeature( interp, Py_RTFLAGS_MULTI_INTERP_EXTENSIONS)) { return true; } return false; } int _PyImport_CheckSubinterpIncompatibleExtensionAllowed(const char *name) { PyInterpreterState *interp = _PyInterpreterState_Get(); if (check_multi_interp_extensions(interp)) { assert(!_Py_IsMainInterpreter(interp)); PyErr_Format(PyExc_ImportError, "module %s does not support loading in subinterpreters", name); return -1; } return 0; } static PyObject * get_core_module_dict(PyInterpreterState *interp, PyObject *name, PyObject *filename) { /* Only builtin modules are core. */ if (filename == name) { assert(!PyErr_Occurred()); if (PyUnicode_CompareWithASCIIString(name, "sys") == 0) { return interp->sysdict_copy; } assert(!PyErr_Occurred()); if (PyUnicode_CompareWithASCIIString(name, "builtins") == 0) { return interp->builtins_copy; } assert(!PyErr_Occurred()); } return NULL; } static inline int is_core_module(PyInterpreterState *interp, PyObject *name, PyObject *filename) { /* This might be called before the core dict copies are in place, so we can't rely on get_core_module_dict() here. */ if (filename == name) { if (PyUnicode_CompareWithASCIIString(name, "sys") == 0) { return 1; } if (PyUnicode_CompareWithASCIIString(name, "builtins") == 0) { return 1; } } return 0; } static int fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename) { if (mod == NULL || !PyModule_Check(mod)) { PyErr_BadInternalCall(); return -1; } struct PyModuleDef *def = PyModule_GetDef(mod); if (!def) { PyErr_BadInternalCall(); return -1; } PyThreadState *tstate = _PyThreadState_GET(); if (_modules_by_index_set(tstate->interp, def, mod) < 0) { return -1; } // bpo-44050: Extensions and def->m_base.m_copy can be updated // when the extension module doesn't support sub-interpreters. if (def->m_size == -1) { if (!is_core_module(tstate->interp, name, filename)) { assert(PyUnicode_CompareWithASCIIString(name, "sys") != 0); assert(PyUnicode_CompareWithASCIIString(name, "builtins") != 0); if (def->m_base.m_copy) { /* Somebody already imported the module, likely under a different name. XXX this should really not happen. */ Py_CLEAR(def->m_base.m_copy); } PyObject *dict = PyModule_GetDict(mod); if (dict == NULL) { return -1; } def->m_base.m_copy = PyDict_Copy(dict); if (def->m_base.m_copy == NULL) { return -1; } } } // XXX Why special-case the main interpreter? if (_Py_IsMainInterpreter(tstate->interp) || def->m_size == -1) { if (_extensions_cache_set(filename, name, def) < 0) { return -1; } } return 0; } int _PyImport_FixupExtensionObject(PyObject *mod, PyObject *name, PyObject *filename, PyObject *modules) { if (PyObject_SetItem(modules, name, mod) < 0) { return -1; } if (fix_up_extension(mod, name, filename) < 0) { PyMapping_DelItem(modules, name); return -1; } return 0; } static PyObject * import_find_extension(PyThreadState *tstate, PyObject *name, PyObject *filename) { /* Only single-phase init modules will be in the cache. */ PyModuleDef *def = _extensions_cache_get(filename, name); if (def == NULL) { return NULL; } PyObject *mod, *mdict; PyObject *modules = MODULES(tstate->interp); if (def->m_size == -1) { PyObject *m_copy = def->m_base.m_copy; /* Module does not support repeated initialization */ if (m_copy == NULL) { m_copy = get_core_module_dict(tstate->interp, name, filename); if (m_copy == NULL) { return NULL; } } mod = import_add_module(tstate, name); if (mod == NULL) { return NULL; } mdict = PyModule_GetDict(mod); if (mdict == NULL) { Py_DECREF(mod); return NULL; } if (PyDict_Update(mdict, m_copy)) { Py_DECREF(mod); return NULL; } } else { if (def->m_base.m_init == NULL) return NULL; mod = _PyImport_InitFunc_TrampolineCall(def->m_base.m_init); if (mod == NULL) return NULL; if (PyObject_SetItem(modules, name, mod) == -1) { Py_DECREF(mod); return NULL; } } if (_modules_by_index_set(tstate->interp, def, mod) < 0) { PyMapping_DelItem(modules, name); Py_DECREF(mod); return NULL; } int verbose = _PyInterpreterState_GetConfig(tstate->interp)->verbose; if (verbose) { PySys_FormatStderr("import %U # previously loaded (%R)\n", name, filename); } return mod; } static int clear_singlephase_extension(PyInterpreterState *interp, PyObject *name, PyObject *filename) { PyModuleDef *def = _extensions_cache_get(filename, name); if (def == NULL) { if (PyErr_Occurred()) { return -1; } return 0; } /* Clear data set when the module was initially loaded. */ def->m_base.m_init = NULL; Py_CLEAR(def->m_base.m_copy); // We leave m_index alone since there's no reason to reset it. /* Clear the PyState_*Module() cache entry. */ if (_modules_by_index_check(interp, def->m_base.m_index) == NULL) { if (_modules_by_index_clear_one(interp, def) < 0) { return -1; } } /* Clear the cached module def. */ if (_extensions_cache_delete(filename, name) < 0) { return -1; } return 0; } /*******************/ /* builtin modules */ /*******************/ int _PyImport_FixupBuiltin(PyObject *mod, const char *name, PyObject *modules) { int res = -1; PyObject *nameobj; nameobj = PyUnicode_InternFromString(name); if (nameobj == NULL) { return -1; } if (PyObject_SetItem(modules, nameobj, mod) < 0) { goto finally; } if (fix_up_extension(mod, nameobj, nameobj) < 0) { PyMapping_DelItem(modules, nameobj); goto finally; } res = 0; finally: Py_DECREF(nameobj); return res; } /* Helper to test for built-in module */ static int is_builtin(PyObject *name) { int i; struct _inittab *inittab = INITTAB; for (i = 0; inittab[i].name != NULL; i++) { if (_PyUnicode_EqualToASCIIString(name, inittab[i].name)) { if (inittab[i].initfunc == NULL) return -1; else return 1; } } return 0; } static PyObject* create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) { PyObject *mod = import_find_extension(tstate, name, name); if (mod || _PyErr_Occurred(tstate)) { return mod; } PyObject *modules = MODULES(tstate->interp); for (struct _inittab *p = INITTAB; p->name != NULL; p++) { if (_PyUnicode_EqualToASCIIString(name, p->name)) { if (p->initfunc == NULL) { /* Cannot re-init internal module ("sys" or "builtins") */ mod = PyImport_AddModuleObject(name); return Py_XNewRef(mod); } mod = _PyImport_InitFunc_TrampolineCall(*p->initfunc); if (mod == NULL) { return NULL; } if (PyObject_TypeCheck(mod, &PyModuleDef_Type)) { return PyModule_FromDefAndSpec((PyModuleDef*)mod, spec); } else { /* Remember pointer to module init function. */ PyModuleDef *def = PyModule_GetDef(mod); if (def == NULL) { return NULL; } def->m_base.m_init = p->initfunc; if (_PyImport_FixupExtensionObject(mod, name, name, modules) < 0) { return NULL; } return mod; } } } // not found Py_RETURN_NONE; } /*****************************/ /* the builtin modules table */ /*****************************/ /* API for embedding applications that want to add their own entries to the table of built-in modules. This should normally be called *before* Py_Initialize(). When the table resize fails, -1 is returned and the existing table is unchanged. After a similar function by Just van Rossum. */ int PyImport_ExtendInittab(struct _inittab *newtab) { struct _inittab *p; size_t i, n; int res = 0; if (INITTAB != NULL) { Py_FatalError("PyImport_ExtendInittab() may not be called after Py_Initialize()"); } /* Count the number of entries in both tables */ for (n = 0; newtab[n].name != NULL; n++) ; if (n == 0) return 0; /* Nothing to do */ for (i = 0; PyImport_Inittab[i].name != NULL; i++) ; /* Force default raw memory allocator to get a known allocator to be able to release the memory in _PyImport_Fini2() */ PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); /* Allocate new memory for the combined table */ p = NULL; if (i + n <= SIZE_MAX / sizeof(struct _inittab) - 1) { size_t size = sizeof(struct _inittab) * (i + n + 1); p = PyMem_RawRealloc(inittab_copy, size); } if (p == NULL) { res = -1; goto done; } /* Copy the tables into the new memory at the first call to PyImport_ExtendInittab(). */ if (inittab_copy != PyImport_Inittab) { memcpy(p, PyImport_Inittab, (i+1) * sizeof(struct _inittab)); } memcpy(p + i, newtab, (n + 1) * sizeof(struct _inittab)); PyImport_Inittab = inittab_copy = p; done: PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); return res; } /* Shorthand to add a single entry given a name and a function */ int PyImport_AppendInittab(const char *name, PyObject* (*initfunc)(void)) { struct _inittab newtab[2]; if (INITTAB != NULL) { Py_FatalError("PyImport_AppendInittab() may not be called after Py_Initialize()"); } memset(newtab, '\0', sizeof newtab); newtab[0].name = name; newtab[0].initfunc = initfunc; return PyImport_ExtendInittab(newtab); } /* the internal table */ static int init_builtin_modules_table(void) { size_t size; for (size = 0; PyImport_Inittab[size].name != NULL; size++) ; size++; /* Make the copy. */ struct _inittab *copied = PyMem_RawMalloc(size * sizeof(struct _inittab)); if (copied == NULL) { return -1; } memcpy(copied, PyImport_Inittab, size * sizeof(struct _inittab)); INITTAB = copied; return 0; } static void fini_builtin_modules_table(void) { struct _inittab *inittab = INITTAB; INITTAB = NULL; PyMem_RawFree(inittab); } PyObject * _PyImport_GetBuiltinModuleNames(void) { PyObject *list = PyList_New(0); if (list == NULL) { return NULL; } struct _inittab *inittab = INITTAB; for (Py_ssize_t i = 0; inittab[i].name != NULL; i++) { PyObject *name = PyUnicode_FromString(inittab[i].name); if (name == NULL) { Py_DECREF(list); return NULL; } if (PyList_Append(list, name) < 0) { Py_DECREF(name); Py_DECREF(list); return NULL; } Py_DECREF(name); } return list; } /********************/ /* the magic number */ /********************/ /* Helper for pythonrun.c -- return magic number and tag. */ long PyImport_GetMagicNumber(void) { long res; PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *external, *pyc_magic; external = PyObject_GetAttrString(IMPORTLIB(interp), "_bootstrap_external"); if (external == NULL) return -1; pyc_magic = PyObject_GetAttrString(external, "_RAW_MAGIC_NUMBER"); Py_DECREF(external); if (pyc_magic == NULL) return -1; res = PyLong_AsLong(pyc_magic); Py_DECREF(pyc_magic); return res; } extern const char * _PySys_ImplCacheTag; const char * PyImport_GetMagicTag(void) { return _PySys_ImplCacheTag; } /*********************************/ /* a Python module's code object */ /*********************************/ /* Execute a code object in a module and return the module object * WITH INCREMENTED REFERENCE COUNT. If an error occurs, name is * removed from sys.modules, to avoid leaving damaged module objects * in sys.modules. The caller may wish to restore the original * module object (if any) in this case; PyImport_ReloadModule is an * example. * * Note that PyImport_ExecCodeModuleWithPathnames() is the preferred, richer * interface. The other two exist primarily for backward compatibility. */ PyObject * PyImport_ExecCodeModule(const char *name, PyObject *co) { return PyImport_ExecCodeModuleWithPathnames( name, co, (char *)NULL, (char *)NULL); } PyObject * PyImport_ExecCodeModuleEx(const char *name, PyObject *co, const char *pathname) { return PyImport_ExecCodeModuleWithPathnames( name, co, pathname, (char *)NULL); } PyObject * PyImport_ExecCodeModuleWithPathnames(const char *name, PyObject *co, const char *pathname, const char *cpathname) { PyObject *m = NULL; PyObject *nameobj, *pathobj = NULL, *cpathobj = NULL, *external= NULL; nameobj = PyUnicode_FromString(name); if (nameobj == NULL) return NULL; if (cpathname != NULL) { cpathobj = PyUnicode_DecodeFSDefault(cpathname); if (cpathobj == NULL) goto error; } else cpathobj = NULL; if (pathname != NULL) { pathobj = PyUnicode_DecodeFSDefault(pathname); if (pathobj == NULL) goto error; } else if (cpathobj != NULL) { PyInterpreterState *interp = _PyInterpreterState_GET(); if (interp == NULL) { Py_FatalError("no current interpreter"); } external= PyObject_GetAttrString(IMPORTLIB(interp), "_bootstrap_external"); if (external != NULL) { pathobj = _PyObject_CallMethodOneArg( external, &_Py_ID(_get_sourcefile), cpathobj); Py_DECREF(external); } if (pathobj == NULL) PyErr_Clear(); } else pathobj = NULL; m = PyImport_ExecCodeModuleObject(nameobj, co, pathobj, cpathobj); error: Py_DECREF(nameobj); Py_XDECREF(pathobj); Py_XDECREF(cpathobj); return m; } static PyObject * module_dict_for_exec(PyThreadState *tstate, PyObject *name) { PyObject *m, *d; m = import_add_module(tstate, name); if (m == NULL) return NULL; /* If the module is being reloaded, we get the old module back and re-use its dict to exec the new code. */ d = PyModule_GetDict(m); int r = PyDict_Contains(d, &_Py_ID(__builtins__)); if (r == 0) { r = PyDict_SetItem(d, &_Py_ID(__builtins__), PyEval_GetBuiltins()); } if (r < 0) { remove_module(tstate, name); Py_DECREF(m); return NULL; } Py_INCREF(d); Py_DECREF(m); return d; } static PyObject * exec_code_in_module(PyThreadState *tstate, PyObject *name, PyObject *module_dict, PyObject *code_object) { PyObject *v, *m; v = PyEval_EvalCode(code_object, module_dict, module_dict); if (v == NULL) { remove_module(tstate, name); return NULL; } Py_DECREF(v); m = import_get_module(tstate, name); if (m == NULL && !_PyErr_Occurred(tstate)) { _PyErr_Format(tstate, PyExc_ImportError, "Loaded module %R not found in sys.modules", name); } return m; } PyObject* PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname, PyObject *cpathname) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *d, *external, *res; d = module_dict_for_exec(tstate, name); if (d == NULL) { return NULL; } if (pathname == NULL) { pathname = ((PyCodeObject *)co)->co_filename; } external = PyObject_GetAttrString(IMPORTLIB(tstate->interp), "_bootstrap_external"); if (external == NULL) { Py_DECREF(d); return NULL; } res = PyObject_CallMethodObjArgs(external, &_Py_ID(_fix_up_module), d, name, pathname, cpathname, NULL); Py_DECREF(external); if (res != NULL) { Py_DECREF(res); res = exec_code_in_module(tstate, name, d, co); } Py_DECREF(d); return res; } static void update_code_filenames(PyCodeObject *co, PyObject *oldname, PyObject *newname) { PyObject *constants, *tmp; Py_ssize_t i, n; if (PyUnicode_Compare(co->co_filename, oldname)) return; Py_XSETREF(co->co_filename, Py_NewRef(newname)); constants = co->co_consts; n = PyTuple_GET_SIZE(constants); for (i = 0; i < n; i++) { tmp = PyTuple_GET_ITEM(constants, i); if (PyCode_Check(tmp)) update_code_filenames((PyCodeObject *)tmp, oldname, newname); } } static void update_compiled_module(PyCodeObject *co, PyObject *newname) { PyObject *oldname; if (PyUnicode_Compare(co->co_filename, newname) == 0) return; oldname = co->co_filename; Py_INCREF(oldname); update_code_filenames(co, oldname, newname); Py_DECREF(oldname); } /******************/ /* frozen modules */ /******************/ /* Return true if the name is an alias. In that case, "alias" is set to the original module name. If it is an alias but the original module isn't known then "alias" is set to NULL while true is returned. */ static bool resolve_module_alias(const char *name, const struct _module_alias *aliases, const char **alias) { const struct _module_alias *entry; for (entry = aliases; ; entry++) { if (entry->name == NULL) { /* It isn't an alias. */ return false; } if (strcmp(name, entry->name) == 0) { if (alias != NULL) { *alias = entry->orig; } return true; } } } static bool use_frozen(void) { PyInterpreterState *interp = _PyInterpreterState_GET(); int override = OVERRIDE_FROZEN_MODULES(interp); if (override > 0) { return true; } else if (override < 0) { return false; } else { return interp->config.use_frozen_modules; } } static PyObject * list_frozen_module_names(void) { PyObject *names = PyList_New(0); if (names == NULL) { return NULL; } bool enabled = use_frozen(); const struct _frozen *p; #define ADD_MODULE(name) \ do { \ PyObject *nameobj = PyUnicode_FromString(name); \ if (nameobj == NULL) { \ goto error; \ } \ int res = PyList_Append(names, nameobj); \ Py_DECREF(nameobj); \ if (res != 0) { \ goto error; \ } \ } while(0) // We always use the bootstrap modules. for (p = _PyImport_FrozenBootstrap; ; p++) { if (p->name == NULL) { break; } ADD_MODULE(p->name); } // Frozen stdlib modules may be disabled. for (p = _PyImport_FrozenStdlib; ; p++) { if (p->name == NULL) { break; } if (enabled) { ADD_MODULE(p->name); } } for (p = _PyImport_FrozenTest; ; p++) { if (p->name == NULL) { break; } if (enabled) { ADD_MODULE(p->name); } } #undef ADD_MODULE // Add any custom modules. if (PyImport_FrozenModules != NULL) { for (p = PyImport_FrozenModules; ; p++) { if (p->name == NULL) { break; } PyObject *nameobj = PyUnicode_FromString(p->name); if (nameobj == NULL) { goto error; } int found = PySequence_Contains(names, nameobj); if (found < 0) { Py_DECREF(nameobj); goto error; } else if (found) { Py_DECREF(nameobj); } else { int res = PyList_Append(names, nameobj); Py_DECREF(nameobj); if (res != 0) { goto error; } } } } return names; error: Py_DECREF(names); return NULL; } typedef enum { FROZEN_OKAY, FROZEN_BAD_NAME, // The given module name wasn't valid. FROZEN_NOT_FOUND, // It wasn't in PyImport_FrozenModules. FROZEN_DISABLED, // -X frozen_modules=off (and not essential) FROZEN_EXCLUDED, /* The PyImport_FrozenModules entry has NULL "code" (module is present but marked as unimportable, stops search). */ FROZEN_INVALID, /* The PyImport_FrozenModules entry is bogus (eg. does not contain executable code). */ } frozen_status; static inline void set_frozen_error(frozen_status status, PyObject *modname) { const char *err = NULL; switch (status) { case FROZEN_BAD_NAME: case FROZEN_NOT_FOUND: err = "No such frozen object named %R"; break; case FROZEN_DISABLED: err = "Frozen modules are disabled and the frozen object named %R is not essential"; break; case FROZEN_EXCLUDED: err = "Excluded frozen object named %R"; break; case FROZEN_INVALID: err = "Frozen object named %R is invalid"; break; case FROZEN_OKAY: // There was no error. break; default: Py_UNREACHABLE(); } if (err != NULL) { PyObject *msg = PyUnicode_FromFormat(err, modname); if (msg == NULL) { PyErr_Clear(); } PyErr_SetImportError(msg, modname, NULL); Py_XDECREF(msg); } } static const struct _frozen * look_up_frozen(const char *name) { const struct _frozen *p; // We always use the bootstrap modules. for (p = _PyImport_FrozenBootstrap; ; p++) { if (p->name == NULL) { // We hit the end-of-list sentinel value. break; } if (strcmp(name, p->name) == 0) { return p; } } // Prefer custom modules, if any. Frozen stdlib modules can be // disabled here by setting "code" to NULL in the array entry. if (PyImport_FrozenModules != NULL) { for (p = PyImport_FrozenModules; ; p++) { if (p->name == NULL) { break; } if (strcmp(name, p->name) == 0) { return p; } } } // Frozen stdlib modules may be disabled. if (use_frozen()) { for (p = _PyImport_FrozenStdlib; ; p++) { if (p->name == NULL) { break; } if (strcmp(name, p->name) == 0) { return p; } } for (p = _PyImport_FrozenTest; ; p++) { if (p->name == NULL) { break; } if (strcmp(name, p->name) == 0) { return p; } } } return NULL; } struct frozen_info { PyObject *nameobj; const char *data; PyObject *(*get_code)(void); Py_ssize_t size; bool is_package; bool is_alias; const char *origname; }; static frozen_status find_frozen(PyObject *nameobj, struct frozen_info *info) { if (info != NULL) { memset(info, 0, sizeof(*info)); } if (nameobj == NULL || nameobj == Py_None) { return FROZEN_BAD_NAME; } const char *name = PyUnicode_AsUTF8(nameobj); if (name == NULL) { // Note that this function previously used // _PyUnicode_EqualToASCIIString(). We clear the error here // (instead of propagating it) to match the earlier behavior // more closely. PyErr_Clear(); return FROZEN_BAD_NAME; } const struct _frozen *p = look_up_frozen(name); if (p == NULL) { return FROZEN_NOT_FOUND; } if (info != NULL) { info->nameobj = nameobj; // borrowed info->data = (const char *)p->code; info->get_code = p->get_code; info->size = p->size; info->is_package = p->is_package; if (p->size < 0) { // backward compatibility with negative size values info->size = -(p->size); info->is_package = true; } info->origname = name; info->is_alias = resolve_module_alias(name, _PyImport_FrozenAliases, &info->origname); } if (p->code == NULL && p->size == 0 && p->get_code != NULL) { /* It is only deepfrozen. */ return FROZEN_OKAY; } if (p->code == NULL) { /* It is frozen but marked as un-importable. */ return FROZEN_EXCLUDED; } if (p->code[0] == '\0' || p->size == 0) { /* Does not contain executable code. */ return FROZEN_INVALID; } return FROZEN_OKAY; } static PyObject * unmarshal_frozen_code(PyInterpreterState *interp, struct frozen_info *info) { if (info->get_code && _Py_IsMainInterpreter(interp)) { PyObject *code = info->get_code(); assert(code != NULL); return code; } PyObject *co = PyMarshal_ReadObjectFromString(info->data, info->size); if (co == NULL) { /* Does not contain executable code. */ set_frozen_error(FROZEN_INVALID, info->nameobj); return NULL; } if (!PyCode_Check(co)) { // We stick with TypeError for backward compatibility. PyErr_Format(PyExc_TypeError, "frozen object %R is not a code object", info->nameobj); Py_DECREF(co); return NULL; } return co; } /* Initialize a frozen module. Return 1 for success, 0 if the module is not found, and -1 with an exception set if the initialization failed. This function is also used from frozenmain.c */ int PyImport_ImportFrozenModuleObject(PyObject *name) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *co, *m, *d = NULL; int err; struct frozen_info info; frozen_status status = find_frozen(name, &info); if (status == FROZEN_NOT_FOUND || status == FROZEN_DISABLED) { return 0; } else if (status == FROZEN_BAD_NAME) { return 0; } else if (status != FROZEN_OKAY) { set_frozen_error(status, name); return -1; } co = unmarshal_frozen_code(tstate->interp, &info); if (co == NULL) { return -1; } if (info.is_package) { /* Set __path__ to the empty list */ PyObject *l; m = import_add_module(tstate, name); if (m == NULL) goto err_return; d = PyModule_GetDict(m); l = PyList_New(0); if (l == NULL) { Py_DECREF(m); goto err_return; } err = PyDict_SetItemString(d, "__path__", l); Py_DECREF(l); Py_DECREF(m); if (err != 0) goto err_return; } d = module_dict_for_exec(tstate, name); if (d == NULL) { goto err_return; } m = exec_code_in_module(tstate, name, d, co); if (m == NULL) { goto err_return; } Py_DECREF(m); /* Set __origname__ (consumed in FrozenImporter._setup_module()). */ PyObject *origname; if (info.origname) { origname = PyUnicode_FromString(info.origname); if (origname == NULL) { goto err_return; } } else { origname = Py_NewRef(Py_None); } err = PyDict_SetItemString(d, "__origname__", origname); Py_DECREF(origname); if (err != 0) { goto err_return; } Py_DECREF(d); Py_DECREF(co); return 1; err_return: Py_XDECREF(d); Py_DECREF(co); return -1; } int PyImport_ImportFrozenModule(const char *name) { PyObject *nameobj; int ret; nameobj = PyUnicode_InternFromString(name); if (nameobj == NULL) return -1; ret = PyImport_ImportFrozenModuleObject(nameobj); Py_DECREF(nameobj); return ret; } /*************/ /* importlib */ /*************/ /* Import the _imp extension by calling manually _imp.create_builtin() and _imp.exec_builtin() since importlib is not initialized yet. Initializing importlib requires the _imp module: this function fix the bootstrap issue. */ static PyObject* bootstrap_imp(PyThreadState *tstate) { PyObject *name = PyUnicode_FromString("_imp"); if (name == NULL) { return NULL; } // Mock a ModuleSpec object just good enough for PyModule_FromDefAndSpec(): // an object with just a name attribute. // // _imp.__spec__ is overridden by importlib._bootstrap._instal() anyway. PyObject *attrs = Py_BuildValue("{sO}", "name", name); if (attrs == NULL) { goto error; } PyObject *spec = _PyNamespace_New(attrs); Py_DECREF(attrs); if (spec == NULL) { goto error; } // Create the _imp module from its definition. PyObject *mod = create_builtin(tstate, name, spec); Py_CLEAR(name); Py_DECREF(spec); if (mod == NULL) { goto error; } assert(mod != Py_None); // not found // Execute the _imp module: call imp_module_exec(). if (exec_builtin_or_dynamic(mod) < 0) { Py_DECREF(mod); goto error; } return mod; error: Py_XDECREF(name); return NULL; } /* Global initializations. Can be undone by Py_FinalizeEx(). Don't call this twice without an intervening Py_FinalizeEx() call. When initializations fail, a fatal error is issued and the function does not return. On return, the first thread and interpreter state have been created. Locking: you must hold the interpreter lock while calling this. (If the lock has not yet been initialized, that's equivalent to having the lock, but you cannot use multiple threads.) */ static int init_importlib(PyThreadState *tstate, PyObject *sysmod) { assert(!_PyErr_Occurred(tstate)); PyInterpreterState *interp = tstate->interp; int verbose = _PyInterpreterState_GetConfig(interp)->verbose; // Import _importlib through its frozen version, _frozen_importlib. if (verbose) { PySys_FormatStderr("import _frozen_importlib # frozen\n"); } if (PyImport_ImportFrozenModule("_frozen_importlib") <= 0) { return -1; } PyObject *importlib = PyImport_AddModule("_frozen_importlib"); // borrowed if (importlib == NULL) { return -1; } IMPORTLIB(interp) = Py_NewRef(importlib); // Import the _imp module if (verbose) { PySys_FormatStderr("import _imp # builtin\n"); } PyObject *imp_mod = bootstrap_imp(tstate); if (imp_mod == NULL) { return -1; } if (_PyImport_SetModuleString("_imp", imp_mod) < 0) { Py_DECREF(imp_mod); return -1; } // Install importlib as the implementation of import PyObject *value = PyObject_CallMethod(importlib, "_install", "OO", sysmod, imp_mod); Py_DECREF(imp_mod); if (value == NULL) { return -1; } Py_DECREF(value); assert(!_PyErr_Occurred(tstate)); return 0; } static int init_importlib_external(PyInterpreterState *interp) { PyObject *value; value = PyObject_CallMethod(IMPORTLIB(interp), "_install_external_importers", ""); if (value == NULL) { return -1; } Py_DECREF(value); return 0; } PyObject * _PyImport_GetImportlibLoader(PyInterpreterState *interp, const char *loader_name) { return PyObject_GetAttrString(IMPORTLIB(interp), loader_name); } PyObject * _PyImport_GetImportlibExternalLoader(PyInterpreterState *interp, const char *loader_name) { PyObject *bootstrap = PyObject_GetAttrString(IMPORTLIB(interp), "_bootstrap_external"); if (bootstrap == NULL) { return NULL; } PyObject *loader_type = PyObject_GetAttrString(bootstrap, loader_name); Py_DECREF(bootstrap); return loader_type; } PyObject * _PyImport_BlessMyLoader(PyInterpreterState *interp, PyObject *module_globals) { PyObject *external = PyObject_GetAttrString(IMPORTLIB(interp), "_bootstrap_external"); if (external == NULL) { return NULL; } PyObject *loader = PyObject_CallMethod(external, "_bless_my_loader", "O", module_globals, NULL); Py_DECREF(external); return loader; } PyObject * _PyImport_ImportlibModuleRepr(PyInterpreterState *interp, PyObject *m) { return PyObject_CallMethod(IMPORTLIB(interp), "_module_repr", "O", m); } /*******************/ /* Return a finder object for a sys.path/pkg.__path__ item 'p', possibly by fetching it from the path_importer_cache dict. If it wasn't yet cached, traverse path_hooks until a hook is found that can handle the path item. Return None if no hook could; this tells our caller that the path based finder could not find a finder for this path item. Cache the result in path_importer_cache. */ static PyObject * get_path_importer(PyThreadState *tstate, PyObject *path_importer_cache, PyObject *path_hooks, PyObject *p) { PyObject *importer; Py_ssize_t j, nhooks; /* These conditions are the caller's responsibility: */ assert(PyList_Check(path_hooks)); assert(PyDict_Check(path_importer_cache)); nhooks = PyList_Size(path_hooks); if (nhooks < 0) return NULL; /* Shouldn't happen */ importer = PyDict_GetItemWithError(path_importer_cache, p); if (importer != NULL || _PyErr_Occurred(tstate)) { return Py_XNewRef(importer); } /* set path_importer_cache[p] to None to avoid recursion */ if (PyDict_SetItem(path_importer_cache, p, Py_None) != 0) return NULL; for (j = 0; j < nhooks; j++) { PyObject *hook = PyList_GetItem(path_hooks, j); if (hook == NULL) return NULL; importer = PyObject_CallOneArg(hook, p); if (importer != NULL) break; if (!_PyErr_ExceptionMatches(tstate, PyExc_ImportError)) { return NULL; } _PyErr_Clear(tstate); } if (importer == NULL) { Py_RETURN_NONE; } if (PyDict_SetItem(path_importer_cache, p, importer) < 0) { Py_DECREF(importer); return NULL; } return importer; } PyObject * PyImport_GetImporter(PyObject *path) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *path_importer_cache = PySys_GetObject("path_importer_cache"); PyObject *path_hooks = PySys_GetObject("path_hooks"); if (path_importer_cache == NULL || path_hooks == NULL) { return NULL; } return get_path_importer(tstate, path_importer_cache, path_hooks, path); } /*********************/ /* importing modules */ /*********************/ int _PyImport_InitDefaultImportFunc(PyInterpreterState *interp) { // Get the __import__ function PyObject *import_func = _PyDict_GetItemStringWithError(interp->builtins, "__import__"); if (import_func == NULL) { return -1; } IMPORT_FUNC(interp) = Py_NewRef(import_func); return 0; } int _PyImport_IsDefaultImportFunc(PyInterpreterState *interp, PyObject *func) { return func == IMPORT_FUNC(interp); } /* Import a module, either built-in, frozen, or external, and return its module object WITH INCREMENTED REFERENCE COUNT */ PyObject * PyImport_ImportModule(const char *name) { PyObject *pname; PyObject *result; pname = PyUnicode_FromString(name); if (pname == NULL) return NULL; result = PyImport_Import(pname); Py_DECREF(pname); return result; } /* Import a module without blocking * * At first it tries to fetch the module from sys.modules. If the module was * never loaded before it loads it with PyImport_ImportModule() unless another * thread holds the import lock. In the latter case the function raises an * ImportError instead of blocking. * * Returns the module object with incremented ref count. */ PyObject * PyImport_ImportModuleNoBlock(const char *name) { return PyImport_ImportModule(name); } /* Remove importlib frames from the traceback, * except in Verbose mode. */ static void remove_importlib_frames(PyThreadState *tstate) { const char *importlib_filename = ""; const char *external_filename = ""; const char *remove_frames = "_call_with_frames_removed"; int always_trim = 0; int in_importlib = 0; PyObject **prev_link, **outer_link = NULL; PyObject *base_tb = NULL; /* Synopsis: if it's an ImportError, we trim all importlib chunks from the traceback. We always trim chunks which end with a call to "_call_with_frames_removed". */ PyObject *exc = _PyErr_GetRaisedException(tstate); if (exc == NULL || _PyInterpreterState_GetConfig(tstate->interp)->verbose) { goto done; } if (PyType_IsSubtype(Py_TYPE(exc), (PyTypeObject *) PyExc_ImportError)) { always_trim = 1; } assert(PyExceptionInstance_Check(exc)); base_tb = PyException_GetTraceback(exc); prev_link = &base_tb; PyObject *tb = base_tb; while (tb != NULL) { assert(PyTraceBack_Check(tb)); PyTracebackObject *traceback = (PyTracebackObject *)tb; PyObject *next = (PyObject *) traceback->tb_next; PyFrameObject *frame = traceback->tb_frame; PyCodeObject *code = PyFrame_GetCode(frame); int now_in_importlib; now_in_importlib = _PyUnicode_EqualToASCIIString(code->co_filename, importlib_filename) || _PyUnicode_EqualToASCIIString(code->co_filename, external_filename); if (now_in_importlib && !in_importlib) { /* This is the link to this chunk of importlib tracebacks */ outer_link = prev_link; } in_importlib = now_in_importlib; if (in_importlib && (always_trim || _PyUnicode_EqualToASCIIString(code->co_name, remove_frames))) { Py_XSETREF(*outer_link, Py_XNewRef(next)); prev_link = outer_link; } else { prev_link = (PyObject **) &traceback->tb_next; } Py_DECREF(code); tb = next; } if (base_tb == NULL) { base_tb = Py_None; Py_INCREF(Py_None); } PyException_SetTraceback(exc, base_tb); done: Py_XDECREF(base_tb); _PyErr_SetRaisedException(tstate, exc); } static PyObject * resolve_name(PyThreadState *tstate, PyObject *name, PyObject *globals, int level) { PyObject *abs_name; PyObject *package = NULL; PyObject *spec; Py_ssize_t last_dot; PyObject *base; int level_up; if (globals == NULL) { _PyErr_SetString(tstate, PyExc_KeyError, "'__name__' not in globals"); goto error; } if (!PyDict_Check(globals)) { _PyErr_SetString(tstate, PyExc_TypeError, "globals must be a dict"); goto error; } package = PyDict_GetItemWithError(globals, &_Py_ID(__package__)); if (package == Py_None) { package = NULL; } else if (package == NULL && _PyErr_Occurred(tstate)) { goto error; } spec = PyDict_GetItemWithError(globals, &_Py_ID(__spec__)); if (spec == NULL && _PyErr_Occurred(tstate)) { goto error; } if (package != NULL) { Py_INCREF(package); if (!PyUnicode_Check(package)) { _PyErr_SetString(tstate, PyExc_TypeError, "package must be a string"); goto error; } else if (spec != NULL && spec != Py_None) { int equal; PyObject *parent = PyObject_GetAttr(spec, &_Py_ID(parent)); if (parent == NULL) { goto error; } equal = PyObject_RichCompareBool(package, parent, Py_EQ); Py_DECREF(parent); if (equal < 0) { goto error; } else if (equal == 0) { if (PyErr_WarnEx(PyExc_DeprecationWarning, "__package__ != __spec__.parent", 1) < 0) { goto error; } } } } else if (spec != NULL && spec != Py_None) { package = PyObject_GetAttr(spec, &_Py_ID(parent)); if (package == NULL) { goto error; } else if (!PyUnicode_Check(package)) { _PyErr_SetString(tstate, PyExc_TypeError, "__spec__.parent must be a string"); goto error; } } else { if (PyErr_WarnEx(PyExc_ImportWarning, "can't resolve package from __spec__ or __package__, " "falling back on __name__ and __path__", 1) < 0) { goto error; } package = PyDict_GetItemWithError(globals, &_Py_ID(__name__)); if (package == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_SetString(tstate, PyExc_KeyError, "'__name__' not in globals"); } goto error; } Py_INCREF(package); if (!PyUnicode_Check(package)) { _PyErr_SetString(tstate, PyExc_TypeError, "__name__ must be a string"); goto error; } int haspath = PyDict_Contains(globals, &_Py_ID(__path__)); if (haspath < 0) { goto error; } if (!haspath) { Py_ssize_t dot; dot = PyUnicode_FindChar(package, '.', 0, PyUnicode_GET_LENGTH(package), -1); if (dot == -2) { goto error; } else if (dot == -1) { goto no_parent_error; } PyObject *substr = PyUnicode_Substring(package, 0, dot); if (substr == NULL) { goto error; } Py_SETREF(package, substr); } } last_dot = PyUnicode_GET_LENGTH(package); if (last_dot == 0) { goto no_parent_error; } for (level_up = 1; level_up < level; level_up += 1) { last_dot = PyUnicode_FindChar(package, '.', 0, last_dot, -1); if (last_dot == -2) { goto error; } else if (last_dot == -1) { _PyErr_SetString(tstate, PyExc_ImportError, "attempted relative import beyond top-level " "package"); goto error; } } base = PyUnicode_Substring(package, 0, last_dot); Py_DECREF(package); if (base == NULL || PyUnicode_GET_LENGTH(name) == 0) { return base; } abs_name = PyUnicode_FromFormat("%U.%U", base, name); Py_DECREF(base); return abs_name; no_parent_error: _PyErr_SetString(tstate, PyExc_ImportError, "attempted relative import " "with no known parent package"); error: Py_XDECREF(package); return NULL; } static PyObject * import_find_and_load(PyThreadState *tstate, PyObject *abs_name) { PyObject *mod = NULL; PyInterpreterState *interp = tstate->interp; int import_time = _PyInterpreterState_GetConfig(interp)->import_time; #define import_level FIND_AND_LOAD(interp).import_level #define accumulated FIND_AND_LOAD(interp).accumulated _PyTime_t t1 = 0, accumulated_copy = accumulated; PyObject *sys_path = PySys_GetObject("path"); PyObject *sys_meta_path = PySys_GetObject("meta_path"); PyObject *sys_path_hooks = PySys_GetObject("path_hooks"); if (_PySys_Audit(tstate, "import", "OOOOO", abs_name, Py_None, sys_path ? sys_path : Py_None, sys_meta_path ? sys_meta_path : Py_None, sys_path_hooks ? sys_path_hooks : Py_None) < 0) { return NULL; } /* XOptions is initialized after first some imports. * So we can't have negative cache before completed initialization. * Anyway, importlib._find_and_load is much slower than * _PyDict_GetItemIdWithError(). */ if (import_time) { #define header FIND_AND_LOAD(interp).header if (header) { fputs("import time: self [us] | cumulative | imported package\n", stderr); header = 0; } #undef header import_level++; t1 = _PyTime_GetPerfCounter(); accumulated = 0; } if (PyDTrace_IMPORT_FIND_LOAD_START_ENABLED()) PyDTrace_IMPORT_FIND_LOAD_START(PyUnicode_AsUTF8(abs_name)); mod = PyObject_CallMethodObjArgs(IMPORTLIB(interp), &_Py_ID(_find_and_load), abs_name, IMPORT_FUNC(interp), NULL); if (PyDTrace_IMPORT_FIND_LOAD_DONE_ENABLED()) PyDTrace_IMPORT_FIND_LOAD_DONE(PyUnicode_AsUTF8(abs_name), mod != NULL); if (import_time) { _PyTime_t cum = _PyTime_GetPerfCounter() - t1; import_level--; fprintf(stderr, "import time: %9ld | %10ld | %*s%s\n", (long)_PyTime_AsMicroseconds(cum - accumulated, _PyTime_ROUND_CEILING), (long)_PyTime_AsMicroseconds(cum, _PyTime_ROUND_CEILING), import_level*2, "", PyUnicode_AsUTF8(abs_name)); accumulated = accumulated_copy + cum; } return mod; #undef import_level #undef accumulated } PyObject * PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *abs_name = NULL; PyObject *final_mod = NULL; PyObject *mod = NULL; PyObject *package = NULL; PyInterpreterState *interp = tstate->interp; int has_from; if (name == NULL) { _PyErr_SetString(tstate, PyExc_ValueError, "Empty module name"); goto error; } /* The below code is importlib.__import__() & _gcd_import(), ported to C for added performance. */ if (!PyUnicode_Check(name)) { _PyErr_SetString(tstate, PyExc_TypeError, "module name must be a string"); goto error; } if (level < 0) { _PyErr_SetString(tstate, PyExc_ValueError, "level must be >= 0"); goto error; } if (level > 0) { abs_name = resolve_name(tstate, name, globals, level); if (abs_name == NULL) goto error; } else { /* level == 0 */ if (PyUnicode_GET_LENGTH(name) == 0) { _PyErr_SetString(tstate, PyExc_ValueError, "Empty module name"); goto error; } abs_name = Py_NewRef(name); } mod = import_get_module(tstate, abs_name); if (mod == NULL && _PyErr_Occurred(tstate)) { goto error; } if (mod != NULL && mod != Py_None) { if (import_ensure_initialized(tstate->interp, mod, abs_name) < 0) { goto error; } } else { Py_XDECREF(mod); mod = import_find_and_load(tstate, abs_name); if (mod == NULL) { goto error; } } has_from = 0; if (fromlist != NULL && fromlist != Py_None) { has_from = PyObject_IsTrue(fromlist); if (has_from < 0) goto error; } if (!has_from) { Py_ssize_t len = PyUnicode_GET_LENGTH(name); if (level == 0 || len > 0) { Py_ssize_t dot; dot = PyUnicode_FindChar(name, '.', 0, len, 1); if (dot == -2) { goto error; } if (dot == -1) { /* No dot in module name, simple exit */ final_mod = Py_NewRef(mod); goto error; } if (level == 0) { PyObject *front = PyUnicode_Substring(name, 0, dot); if (front == NULL) { goto error; } final_mod = PyImport_ImportModuleLevelObject(front, NULL, NULL, NULL, 0); Py_DECREF(front); } else { Py_ssize_t cut_off = len - dot; Py_ssize_t abs_name_len = PyUnicode_GET_LENGTH(abs_name); PyObject *to_return = PyUnicode_Substring(abs_name, 0, abs_name_len - cut_off); if (to_return == NULL) { goto error; } final_mod = import_get_module(tstate, to_return); Py_DECREF(to_return); if (final_mod == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_Format(tstate, PyExc_KeyError, "%R not in sys.modules as expected", to_return); } goto error; } } } else { final_mod = Py_NewRef(mod); } } else { PyObject *path; if (_PyObject_LookupAttr(mod, &_Py_ID(__path__), &path) < 0) { goto error; } if (path) { Py_DECREF(path); final_mod = PyObject_CallMethodObjArgs( IMPORTLIB(interp), &_Py_ID(_handle_fromlist), mod, fromlist, IMPORT_FUNC(interp), NULL); } else { final_mod = Py_NewRef(mod); } } error: Py_XDECREF(abs_name); Py_XDECREF(mod); Py_XDECREF(package); if (final_mod == NULL) { remove_importlib_frames(tstate); } return final_mod; } PyObject * PyImport_ImportModuleLevel(const char *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level) { PyObject *nameobj, *mod; nameobj = PyUnicode_FromString(name); if (nameobj == NULL) return NULL; mod = PyImport_ImportModuleLevelObject(nameobj, globals, locals, fromlist, level); Py_DECREF(nameobj); return mod; } /* Re-import a module of any kind and return its module object, WITH INCREMENTED REFERENCE COUNT */ PyObject * PyImport_ReloadModule(PyObject *m) { PyObject *reloaded_module = NULL; PyObject *importlib = PyImport_GetModule(&_Py_ID(importlib)); if (importlib == NULL) { if (PyErr_Occurred()) { return NULL; } importlib = PyImport_ImportModule("importlib"); if (importlib == NULL) { return NULL; } } reloaded_module = PyObject_CallMethodOneArg(importlib, &_Py_ID(reload), m); Py_DECREF(importlib); return reloaded_module; } /* Higher-level import emulator which emulates the "import" statement more accurately -- it invokes the __import__() function from the builtins of the current globals. This means that the import is done using whatever import hooks are installed in the current environment. A dummy list ["__doc__"] is passed as the 4th argument so that e.g. PyImport_Import(PyUnicode_FromString("win32com.client.gencache")) will return instead of . */ PyObject * PyImport_Import(PyObject *module_name) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *globals = NULL; PyObject *import = NULL; PyObject *builtins = NULL; PyObject *r = NULL; PyObject *from_list = PyList_New(0); if (from_list == NULL) { goto err; } /* Get the builtins from current globals */ globals = PyEval_GetGlobals(); if (globals != NULL) { Py_INCREF(globals); builtins = PyObject_GetItem(globals, &_Py_ID(__builtins__)); if (builtins == NULL) goto err; } else { /* No globals -- use standard builtins, and fake globals */ builtins = PyImport_ImportModuleLevel("builtins", NULL, NULL, NULL, 0); if (builtins == NULL) { goto err; } globals = Py_BuildValue("{OO}", &_Py_ID(__builtins__), builtins); if (globals == NULL) goto err; } /* Get the __import__ function from the builtins */ if (PyDict_Check(builtins)) { import = PyObject_GetItem(builtins, &_Py_ID(__import__)); if (import == NULL) { _PyErr_SetObject(tstate, PyExc_KeyError, &_Py_ID(__import__)); } } else import = PyObject_GetAttr(builtins, &_Py_ID(__import__)); if (import == NULL) goto err; /* Call the __import__ function with the proper argument list Always use absolute import here. Calling for side-effect of import. */ r = PyObject_CallFunction(import, "OOOOi", module_name, globals, globals, from_list, 0, NULL); if (r == NULL) goto err; Py_DECREF(r); r = import_get_module(tstate, module_name); if (r == NULL && !_PyErr_Occurred(tstate)) { _PyErr_SetObject(tstate, PyExc_KeyError, module_name); } err: Py_XDECREF(globals); Py_XDECREF(builtins); Py_XDECREF(import); Py_XDECREF(from_list); return r; } /*********************/ /* runtime lifecycle */ /*********************/ PyStatus _PyImport_Init(void) { if (INITTAB != NULL) { return _PyStatus_ERR("global import state already initialized"); } PyStatus status = _PyStatus_OK(); /* Force default raw memory allocator to get a known allocator to be able to release the memory in _PyImport_Fini() */ PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); if (init_builtin_modules_table() != 0) { status = PyStatus_NoMemory(); goto done; } done: PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); return status; } void _PyImport_Fini(void) { /* Destroy the database used by _PyImport_{Fixup,Find}Extension */ _extensions_cache_clear_all(); /* Use the same memory allocator as _PyImport_Init(). */ PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); /* Free memory allocated by _PyImport_Init() */ fini_builtin_modules_table(); PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); } void _PyImport_Fini2(void) { /* Use the same memory allocator than PyImport_ExtendInittab(). */ PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); // Reset PyImport_Inittab PyImport_Inittab = _PyImport_Inittab; /* Free memory allocated by PyImport_ExtendInittab() */ PyMem_RawFree(inittab_copy); inittab_copy = NULL; PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); } /*************************/ /* interpreter lifecycle */ /*************************/ PyStatus _PyImport_InitCore(PyThreadState *tstate, PyObject *sysmod, int importlib) { if (_Py_IsMainInterpreter(tstate->interp)) { _extensions_cache_init(); } // XXX Initialize here: interp->modules and interp->import_func. // XXX Initialize here: sys.modules and sys.meta_path. if (importlib) { /* This call sets up builtin and frozen import support */ if (init_importlib(tstate, sysmod) < 0) { return _PyStatus_ERR("failed to initialize importlib"); } } return _PyStatus_OK(); } /* In some corner cases it is important to be sure that the import machinery has been initialized (or not cleaned up yet). For example, see issue #4236 and PyModule_Create2(). */ int _PyImport_IsInitialized(PyInterpreterState *interp) { if (MODULES(interp) == NULL) return 0; return 1; } /* Clear the direct per-interpreter import state, if not cleared already. */ void _PyImport_ClearCore(PyInterpreterState *interp) { /* interp->modules should have been cleaned up and cleared already by _PyImport_FiniCore(). */ Py_CLEAR(MODULES(interp)); Py_CLEAR(MODULES_BY_INDEX(interp)); Py_CLEAR(IMPORTLIB(interp)); Py_CLEAR(IMPORT_FUNC(interp)); } void _PyImport_FiniCore(PyInterpreterState *interp) { int verbose = _PyInterpreterState_GetConfig(interp)->verbose; if (_PySys_ClearAttrString(interp, "meta_path", verbose) < 0) { PyErr_WriteUnraisable(NULL); } // XXX Pull in most of finalize_modules() in pylifecycle.c. if (_PySys_ClearAttrString(interp, "modules", verbose) < 0) { PyErr_WriteUnraisable(NULL); } if (IMPORT_LOCK(interp) != NULL) { PyThread_free_lock(IMPORT_LOCK(interp)); IMPORT_LOCK(interp) = NULL; } _PyImport_ClearCore(interp); } // XXX Add something like _PyImport_Disable() for use early in interp fini? /* "external" imports */ static int init_zipimport(PyThreadState *tstate, int verbose) { PyObject *path_hooks = PySys_GetObject("path_hooks"); if (path_hooks == NULL) { _PyErr_SetString(tstate, PyExc_RuntimeError, "unable to get sys.path_hooks"); return -1; } if (verbose) { PySys_WriteStderr("# installing zipimport hook\n"); } PyObject *zipimporter = _PyImport_GetModuleAttrString("zipimport", "zipimporter"); if (zipimporter == NULL) { _PyErr_Clear(tstate); /* No zipimporter object -- okay */ if (verbose) { PySys_WriteStderr("# can't import zipimport.zipimporter\n"); } } else { /* sys.path_hooks.insert(0, zipimporter) */ int err = PyList_Insert(path_hooks, 0, zipimporter); Py_DECREF(zipimporter); if (err < 0) { return -1; } if (verbose) { PySys_WriteStderr("# installed zipimport hook\n"); } } return 0; } PyStatus _PyImport_InitExternal(PyThreadState *tstate) { int verbose = _PyInterpreterState_GetConfig(tstate->interp)->verbose; // XXX Initialize here: sys.path_hooks and sys.path_importer_cache. if (init_importlib_external(tstate->interp) != 0) { _PyErr_Print(tstate); return _PyStatus_ERR("external importer setup failed"); } if (init_zipimport(tstate, verbose) != 0) { PyErr_Print(); return _PyStatus_ERR("initializing zipimport failed"); } return _PyStatus_OK(); } void _PyImport_FiniExternal(PyInterpreterState *interp) { int verbose = _PyInterpreterState_GetConfig(interp)->verbose; // XXX Uninstall importlib metapath importers here? if (_PySys_ClearAttrString(interp, "path_importer_cache", verbose) < 0) { PyErr_WriteUnraisable(NULL); } if (_PySys_ClearAttrString(interp, "path_hooks", verbose) < 0) { PyErr_WriteUnraisable(NULL); } } /******************/ /* module helpers */ /******************/ PyObject * _PyImport_GetModuleAttr(PyObject *modname, PyObject *attrname) { PyObject *mod = PyImport_Import(modname); if (mod == NULL) { return NULL; } PyObject *result = PyObject_GetAttr(mod, attrname); Py_DECREF(mod); return result; } PyObject * _PyImport_GetModuleAttrString(const char *modname, const char *attrname) { PyObject *pmodname = PyUnicode_FromString(modname); if (pmodname == NULL) { return NULL; } PyObject *pattrname = PyUnicode_FromString(attrname); if (pattrname == NULL) { Py_DECREF(pmodname); return NULL; } PyObject *result = _PyImport_GetModuleAttr(pmodname, pattrname); Py_DECREF(pattrname); Py_DECREF(pmodname); return result; } /**************/ /* the module */ /**************/ /*[clinic input] _imp.lock_held Return True if the import lock is currently held, else False. On platforms without threads, return False. [clinic start generated code]*/ static PyObject * _imp_lock_held_impl(PyObject *module) /*[clinic end generated code: output=8b89384b5e1963fc input=9b088f9b217d9bdf]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); return PyBool_FromLong( IMPORT_LOCK_THREAD(interp) != PYTHREAD_INVALID_THREAD_ID); } /*[clinic input] _imp.acquire_lock Acquires the interpreter's import lock for the current thread. This lock should be used by import hooks to ensure thread-safety when importing modules. On platforms without threads, this function does nothing. [clinic start generated code]*/ static PyObject * _imp_acquire_lock_impl(PyObject *module) /*[clinic end generated code: output=1aff58cb0ee1b026 input=4a2d4381866d5fdc]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); _PyImport_AcquireLock(interp); Py_RETURN_NONE; } /*[clinic input] _imp.release_lock Release the interpreter's import lock. On platforms without threads, this function does nothing. [clinic start generated code]*/ static PyObject * _imp_release_lock_impl(PyObject *module) /*[clinic end generated code: output=7faab6d0be178b0a input=934fb11516dd778b]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); if (_PyImport_ReleaseLock(interp) < 0) { PyErr_SetString(PyExc_RuntimeError, "not holding the import lock"); return NULL; } Py_RETURN_NONE; } /*[clinic input] _imp._fix_co_filename code: object(type="PyCodeObject *", subclass_of="&PyCode_Type") Code object to change. path: unicode File path to use. / Changes code.co_filename to specify the passed-in file path. [clinic start generated code]*/ static PyObject * _imp__fix_co_filename_impl(PyObject *module, PyCodeObject *code, PyObject *path) /*[clinic end generated code: output=1d002f100235587d input=895ba50e78b82f05]*/ { update_compiled_module(code, path); Py_RETURN_NONE; } /*[clinic input] _imp.create_builtin spec: object / Create an extension module. [clinic start generated code]*/ static PyObject * _imp_create_builtin(PyObject *module, PyObject *spec) /*[clinic end generated code: output=ace7ff22271e6f39 input=37f966f890384e47]*/ { PyThreadState *tstate = _PyThreadState_GET(); PyObject *name = PyObject_GetAttrString(spec, "name"); if (name == NULL) { return NULL; } if (!PyUnicode_Check(name)) { PyErr_Format(PyExc_TypeError, "name must be string, not %.200s", Py_TYPE(name)->tp_name); Py_DECREF(name); return NULL; } PyObject *mod = create_builtin(tstate, name, spec); Py_DECREF(name); return mod; } /*[clinic input] _imp.extension_suffixes Returns the list of file suffixes used to identify extension modules. [clinic start generated code]*/ static PyObject * _imp_extension_suffixes_impl(PyObject *module) /*[clinic end generated code: output=0bf346e25a8f0cd3 input=ecdeeecfcb6f839e]*/ { PyObject *list; list = PyList_New(0); if (list == NULL) return NULL; #ifdef HAVE_DYNAMIC_LOADING const char *suffix; unsigned int index = 0; while ((suffix = _PyImport_DynLoadFiletab[index])) { PyObject *item = PyUnicode_FromString(suffix); if (item == NULL) { Py_DECREF(list); return NULL; } if (PyList_Append(list, item) < 0) { Py_DECREF(list); Py_DECREF(item); return NULL; } Py_DECREF(item); index += 1; } #endif return list; } /*[clinic input] _imp.init_frozen name: unicode / Initializes a frozen module. [clinic start generated code]*/ static PyObject * _imp_init_frozen_impl(PyObject *module, PyObject *name) /*[clinic end generated code: output=fc0511ed869fd69c input=13019adfc04f3fb3]*/ { PyThreadState *tstate = _PyThreadState_GET(); int ret; ret = PyImport_ImportFrozenModuleObject(name); if (ret < 0) return NULL; if (ret == 0) { Py_RETURN_NONE; } return import_add_module(tstate, name); } /*[clinic input] _imp.find_frozen name: unicode / * withdata: bool = False Return info about the corresponding frozen module (if there is one) or None. The returned info (a 2-tuple): * data the raw marshalled bytes * is_package whether or not it is a package * origname the originally frozen module's name, or None if not a stdlib module (this will usually be the same as the module's current name) [clinic start generated code]*/ static PyObject * _imp_find_frozen_impl(PyObject *module, PyObject *name, int withdata) /*[clinic end generated code: output=8c1c3c7f925397a5 input=22a8847c201542fd]*/ { struct frozen_info info; frozen_status status = find_frozen(name, &info); if (status == FROZEN_NOT_FOUND || status == FROZEN_DISABLED) { Py_RETURN_NONE; } else if (status == FROZEN_BAD_NAME) { Py_RETURN_NONE; } else if (status != FROZEN_OKAY) { set_frozen_error(status, name); return NULL; } PyObject *data = NULL; if (withdata) { data = PyMemoryView_FromMemory((char *)info.data, info.size, PyBUF_READ); if (data == NULL) { return NULL; } } PyObject *origname = NULL; if (info.origname != NULL && info.origname[0] != '\0') { origname = PyUnicode_FromString(info.origname); if (origname == NULL) { Py_DECREF(data); return NULL; } } PyObject *result = PyTuple_Pack(3, data ? data : Py_None, info.is_package ? Py_True : Py_False, origname ? origname : Py_None); Py_XDECREF(origname); Py_XDECREF(data); return result; } /*[clinic input] _imp.get_frozen_object name: unicode data as dataobj: object = None / Create a code object for a frozen module. [clinic start generated code]*/ static PyObject * _imp_get_frozen_object_impl(PyObject *module, PyObject *name, PyObject *dataobj) /*[clinic end generated code: output=54368a673a35e745 input=034bdb88f6460b7b]*/ { struct frozen_info info = {0}; Py_buffer buf = {0}; if (PyObject_CheckBuffer(dataobj)) { if (PyObject_GetBuffer(dataobj, &buf, PyBUF_READ) != 0) { return NULL; } info.data = (const char *)buf.buf; info.size = buf.len; } else if (dataobj != Py_None) { _PyArg_BadArgument("get_frozen_object", "argument 2", "bytes", dataobj); return NULL; } else { frozen_status status = find_frozen(name, &info); if (status != FROZEN_OKAY) { set_frozen_error(status, name); return NULL; } } if (info.nameobj == NULL) { info.nameobj = name; } if (info.size == 0 && info.get_code == NULL) { /* Does not contain executable code. */ set_frozen_error(FROZEN_INVALID, name); return NULL; } PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *codeobj = unmarshal_frozen_code(interp, &info); if (dataobj != Py_None) { PyBuffer_Release(&buf); } return codeobj; } /*[clinic input] _imp.is_frozen_package name: unicode / Returns True if the module name is of a frozen package. [clinic start generated code]*/ static PyObject * _imp_is_frozen_package_impl(PyObject *module, PyObject *name) /*[clinic end generated code: output=e70cbdb45784a1c9 input=81b6cdecd080fbb8]*/ { struct frozen_info info; frozen_status status = find_frozen(name, &info); if (status != FROZEN_OKAY && status != FROZEN_EXCLUDED) { set_frozen_error(status, name); return NULL; } return PyBool_FromLong(info.is_package); } /*[clinic input] _imp.is_builtin name: unicode / Returns True if the module name corresponds to a built-in module. [clinic start generated code]*/ static PyObject * _imp_is_builtin_impl(PyObject *module, PyObject *name) /*[clinic end generated code: output=3bfd1162e2d3be82 input=86befdac021dd1c7]*/ { return PyLong_FromLong(is_builtin(name)); } /*[clinic input] _imp.is_frozen name: unicode / Returns True if the module name corresponds to a frozen module. [clinic start generated code]*/ static PyObject * _imp_is_frozen_impl(PyObject *module, PyObject *name) /*[clinic end generated code: output=01f408f5ec0f2577 input=7301dbca1897d66b]*/ { struct frozen_info info; frozen_status status = find_frozen(name, &info); if (status != FROZEN_OKAY) { Py_RETURN_FALSE; } Py_RETURN_TRUE; } /*[clinic input] _imp._frozen_module_names Returns the list of available frozen modules. [clinic start generated code]*/ static PyObject * _imp__frozen_module_names_impl(PyObject *module) /*[clinic end generated code: output=80609ef6256310a8 input=76237fbfa94460d2]*/ { return list_frozen_module_names(); } /*[clinic input] _imp._override_frozen_modules_for_tests override: int / (internal-only) Override PyConfig.use_frozen_modules. (-1: "off", 1: "on", 0: no override) See frozen_modules() in Lib/test/support/import_helper.py. [clinic start generated code]*/ static PyObject * _imp__override_frozen_modules_for_tests_impl(PyObject *module, int override) /*[clinic end generated code: output=36d5cb1594160811 input=8f1f95a3ef21aec3]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); OVERRIDE_FROZEN_MODULES(interp) = override; Py_RETURN_NONE; } /*[clinic input] _imp._override_multi_interp_extensions_check override: int / (internal-only) Override PyInterpreterConfig.check_multi_interp_extensions. (-1: "never", 1: "always", 0: no override) [clinic start generated code]*/ static PyObject * _imp__override_multi_interp_extensions_check_impl(PyObject *module, int override) /*[clinic end generated code: output=3ff043af52bbf280 input=e086a2ea181f92ae]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); if (_Py_IsMainInterpreter(interp)) { PyErr_SetString(PyExc_RuntimeError, "_imp._override_multi_interp_extensions_check() " "cannot be used in the main interpreter"); return NULL; } int oldvalue = OVERRIDE_MULTI_INTERP_EXTENSIONS_CHECK(interp); OVERRIDE_MULTI_INTERP_EXTENSIONS_CHECK(interp) = override; return PyLong_FromLong(oldvalue); } #ifdef HAVE_DYNAMIC_LOADING /*[clinic input] _imp.create_dynamic spec: object file: object = NULL / Create an extension module. [clinic start generated code]*/ static PyObject * _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) /*[clinic end generated code: output=83249b827a4fde77 input=c31b954f4cf4e09d]*/ { PyObject *mod, *name, *path; FILE *fp; name = PyObject_GetAttrString(spec, "name"); if (name == NULL) { return NULL; } path = PyObject_GetAttrString(spec, "origin"); if (path == NULL) { Py_DECREF(name); return NULL; } PyThreadState *tstate = _PyThreadState_GET(); mod = import_find_extension(tstate, name, path); if (mod != NULL) { const char *name_buf = PyUnicode_AsUTF8(name); assert(name_buf != NULL); if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { Py_DECREF(mod); mod = NULL; } goto finally; } else if (PyErr_Occurred()) { goto finally; } if (file != NULL) { fp = _Py_fopen_obj(path, "r"); if (fp == NULL) { goto finally; } } else fp = NULL; mod = _PyImport_LoadDynamicModuleWithSpec(spec, fp); if (fp) fclose(fp); finally: Py_DECREF(name); Py_DECREF(path); return mod; } /*[clinic input] _imp.exec_dynamic -> int mod: object / Initialize an extension module. [clinic start generated code]*/ static int _imp_exec_dynamic_impl(PyObject *module, PyObject *mod) /*[clinic end generated code: output=f5720ac7b465877d input=9fdbfcb250280d3a]*/ { return exec_builtin_or_dynamic(mod); } #endif /* HAVE_DYNAMIC_LOADING */ /*[clinic input] _imp.exec_builtin -> int mod: object / Initialize a built-in module. [clinic start generated code]*/ static int _imp_exec_builtin_impl(PyObject *module, PyObject *mod) /*[clinic end generated code: output=0262447b240c038e input=7beed5a2f12a60ca]*/ { return exec_builtin_or_dynamic(mod); } /*[clinic input] _imp.source_hash key: long source: Py_buffer [clinic start generated code]*/ static PyObject * _imp_source_hash_impl(PyObject *module, long key, Py_buffer *source) /*[clinic end generated code: output=edb292448cf399ea input=9aaad1e590089789]*/ { union { uint64_t x; char data[sizeof(uint64_t)]; } hash; hash.x = _Py_KeyedHash((uint64_t)key, source->buf, source->len); #if !PY_LITTLE_ENDIAN // Force to little-endian. There really ought to be a succinct standard way // to do this. for (size_t i = 0; i < sizeof(hash.data)/2; i++) { char tmp = hash.data[i]; hash.data[i] = hash.data[sizeof(hash.data) - i - 1]; hash.data[sizeof(hash.data) - i - 1] = tmp; } #endif return PyBytes_FromStringAndSize(hash.data, sizeof(hash.data)); } PyDoc_STRVAR(doc_imp, "(Extremely) low-level import machinery bits as used by importlib."); static PyMethodDef imp_methods[] = { _IMP_EXTENSION_SUFFIXES_METHODDEF _IMP_LOCK_HELD_METHODDEF _IMP_ACQUIRE_LOCK_METHODDEF _IMP_RELEASE_LOCK_METHODDEF _IMP_FIND_FROZEN_METHODDEF _IMP_GET_FROZEN_OBJECT_METHODDEF _IMP_IS_FROZEN_PACKAGE_METHODDEF _IMP_CREATE_BUILTIN_METHODDEF _IMP_INIT_FROZEN_METHODDEF _IMP_IS_BUILTIN_METHODDEF _IMP_IS_FROZEN_METHODDEF _IMP__FROZEN_MODULE_NAMES_METHODDEF _IMP__OVERRIDE_FROZEN_MODULES_FOR_TESTS_METHODDEF _IMP__OVERRIDE_MULTI_INTERP_EXTENSIONS_CHECK_METHODDEF _IMP_CREATE_DYNAMIC_METHODDEF _IMP_EXEC_DYNAMIC_METHODDEF _IMP_EXEC_BUILTIN_METHODDEF _IMP__FIX_CO_FILENAME_METHODDEF _IMP_SOURCE_HASH_METHODDEF {NULL, NULL} /* sentinel */ }; static int imp_module_exec(PyObject *module) { const wchar_t *mode = _Py_GetConfig()->check_hash_pycs_mode; PyObject *pyc_mode = PyUnicode_FromWideChar(mode, -1); if (pyc_mode == NULL) { return -1; } if (PyModule_AddObjectRef(module, "check_hash_based_pycs", pyc_mode) < 0) { Py_DECREF(pyc_mode); return -1; } Py_DECREF(pyc_mode); return 0; } static PyModuleDef_Slot imp_slots[] = { {Py_mod_exec, imp_module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; static struct PyModuleDef imp_module = { PyModuleDef_HEAD_INIT, .m_name = "_imp", .m_doc = doc_imp, .m_size = 0, .m_methods = imp_methods, .m_slots = imp_slots, }; PyMODINIT_FUNC PyInit__imp(void) { return PyModuleDef_Init(&imp_module); } #ifdef __cplusplus } #endif ================================================ FILE: ImPortdl.c ================================================ /* Support for dynamic loading of extension modules */ #include "Python.h" #include "pycore_call.h" #include "pycore_import.h" #include "pycore_pystate.h" #include "pycore_runtime.h" /* ./configure sets HAVE_DYNAMIC_LOADING if dynamic loading of modules is supported on this platform. configure will then compile and link in one of the dynload_*.c files, as appropriate. We will call a function in those modules to get a function pointer to the module's init function. */ #ifdef HAVE_DYNAMIC_LOADING #include "importdl.h" #ifdef MS_WINDOWS extern dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix, const char *shortname, PyObject *pathname, FILE *fp); #else extern dl_funcptr _PyImport_FindSharedFuncptr(const char *prefix, const char *shortname, const char *pathname, FILE *fp); #endif static const char * const ascii_only_prefix = "PyInit"; static const char * const nonascii_prefix = "PyInitU"; /* Get the variable part of a module's export symbol name. * Returns a bytes instance. For non-ASCII-named modules, the name is * encoded as per PEP 489. * The hook_prefix pointer is set to either ascii_only_prefix or * nonascii_prefix, as appropriate. */ static PyObject * get_encoded_name(PyObject *name, const char **hook_prefix) { PyObject *tmp; PyObject *encoded = NULL; PyObject *modname = NULL; Py_ssize_t name_len, lastdot; /* Get the short name (substring after last dot) */ name_len = PyUnicode_GetLength(name); if (name_len < 0) { return NULL; } lastdot = PyUnicode_FindChar(name, '.', 0, name_len, -1); if (lastdot < -1) { return NULL; } else if (lastdot >= 0) { tmp = PyUnicode_Substring(name, lastdot + 1, name_len); if (tmp == NULL) return NULL; name = tmp; /* "name" now holds a new reference to the substring */ } else { Py_INCREF(name); } /* Encode to ASCII or Punycode, as needed */ encoded = PyUnicode_AsEncodedString(name, "ascii", NULL); if (encoded != NULL) { *hook_prefix = ascii_only_prefix; } else { if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) { PyErr_Clear(); encoded = PyUnicode_AsEncodedString(name, "punycode", NULL); if (encoded == NULL) { goto error; } *hook_prefix = nonascii_prefix; } else { goto error; } } /* Replace '-' by '_' */ modname = _PyObject_CallMethod(encoded, &_Py_ID(replace), "cc", '-', '_'); if (modname == NULL) goto error; Py_DECREF(name); Py_DECREF(encoded); return modname; error: Py_DECREF(name); Py_XDECREF(encoded); return NULL; } PyObject * _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp) { #ifndef MS_WINDOWS PyObject *pathbytes = NULL; #endif PyObject *name_unicode = NULL, *name = NULL, *path = NULL, *m = NULL; const char *name_buf, *hook_prefix; const char *oldcontext, *newcontext; dl_funcptr exportfunc; PyModuleDef *def; PyModInitFunction p0; name_unicode = PyObject_GetAttrString(spec, "name"); if (name_unicode == NULL) { return NULL; } if (!PyUnicode_Check(name_unicode)) { PyErr_SetString(PyExc_TypeError, "spec.name must be a string"); goto error; } newcontext = PyUnicode_AsUTF8(name_unicode); if (newcontext == NULL) { goto error; } name = get_encoded_name(name_unicode, &hook_prefix); if (name == NULL) { goto error; } name_buf = PyBytes_AS_STRING(name); path = PyObject_GetAttrString(spec, "origin"); if (path == NULL) goto error; if (PySys_Audit("import", "OOOOO", name_unicode, path, Py_None, Py_None, Py_None) < 0) { goto error; } #ifdef MS_WINDOWS exportfunc = _PyImport_FindSharedFuncptrWindows(hook_prefix, name_buf, path, fp); #else pathbytes = PyUnicode_EncodeFSDefault(path); if (pathbytes == NULL) goto error; exportfunc = _PyImport_FindSharedFuncptr(hook_prefix, name_buf, PyBytes_AS_STRING(pathbytes), fp); Py_DECREF(pathbytes); #endif if (exportfunc == NULL) { if (!PyErr_Occurred()) { PyObject *msg; msg = PyUnicode_FromFormat( "dynamic module does not define " "module export function (%s_%s)", hook_prefix, name_buf); if (msg == NULL) goto error; PyErr_SetImportError(msg, name_unicode, path); Py_DECREF(msg); } goto error; } p0 = (PyModInitFunction)exportfunc; /* Package context is needed for single-phase init */ oldcontext = _PyImport_SwapPackageContext(newcontext); m = _PyImport_InitFunc_TrampolineCall(p0); _PyImport_SwapPackageContext(oldcontext); if (m == NULL) { if (!PyErr_Occurred()) { PyErr_Format( PyExc_SystemError, "initialization of %s failed without raising an exception", name_buf); } goto error; } else if (PyErr_Occurred()) { _PyErr_FormatFromCause( PyExc_SystemError, "initialization of %s raised unreported exception", name_buf); m = NULL; goto error; } if (Py_IS_TYPE(m, NULL)) { /* This can happen when a PyModuleDef is returned without calling * PyModuleDef_Init on it */ PyErr_Format(PyExc_SystemError, "init function of %s returned uninitialized object", name_buf); m = NULL; /* prevent segfault in DECREF */ goto error; } if (PyObject_TypeCheck(m, &PyModuleDef_Type)) { Py_DECREF(name_unicode); Py_DECREF(name); Py_DECREF(path); return PyModule_FromDefAndSpec((PyModuleDef*)m, spec); } /* Fall back to single-phase init mechanism */ if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { goto error; } if (hook_prefix == nonascii_prefix) { /* don't allow legacy init for non-ASCII module names */ PyErr_Format( PyExc_SystemError, "initialization of %s did not return PyModuleDef", name_buf); goto error; } /* Remember pointer to module init function. */ def = PyModule_GetDef(m); if (def == NULL) { PyErr_Format(PyExc_SystemError, "initialization of %s did not return an extension " "module", name_buf); goto error; } def->m_base.m_init = p0; /* Remember the filename as the __file__ attribute */ if (PyModule_AddObjectRef(m, "__file__", path) < 0) { PyErr_Clear(); /* Not important enough to report */ } PyObject *modules = PyImport_GetModuleDict(); if (_PyImport_FixupExtensionObject(m, name_unicode, path, modules) < 0) goto error; Py_DECREF(name_unicode); Py_DECREF(name); Py_DECREF(path); return m; error: Py_DECREF(name_unicode); Py_XDECREF(name); Py_XDECREF(path); Py_XDECREF(m); return NULL; } #endif /* HAVE_DYNAMIC_LOADING */ ================================================ FILE: ImPortdl.h ================================================ #ifndef Py_IMPORTDL_H #define Py_IMPORTDL_H #ifdef __cplusplus extern "C" { #endif extern const char *_PyImport_DynLoadFiletab[]; extern PyObject *_PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *); typedef PyObject *(*PyModInitFunction)(void); #if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE) extern PyObject *_PyImport_InitFunc_TrampolineCall(PyModInitFunction func); #else #define _PyImport_InitFunc_TrampolineCall(func) (func)() #endif /* Max length of module suffix searched for -- accommodates "module.slb" */ #define MAXSUFFIXSIZE 12 #ifdef MS_WINDOWS #include typedef FARPROC dl_funcptr; #else typedef void (*dl_funcptr)(void); #endif #ifdef __cplusplus } #endif #endif /* !Py_IMPORTDL_H */ ================================================ FILE: InTrinSics.c ================================================ #define _PY_INTERPRETER #include "Python.h" #include "pycore_frame.h" #include "pycore_function.h" #include "pycore_runtime.h" #include "pycore_global_objects.h" #include "pycore_intrinsics.h" #include "pycore_pyerrors.h" #include "pycore_typevarobject.h" /******** Unary functions ********/ static PyObject * no_intrinsic(PyThreadState* tstate, PyObject *unused) { _PyErr_SetString(tstate, PyExc_SystemError, "invalid intrinsic function"); return NULL; } static PyObject * print_expr(PyThreadState* tstate, PyObject *value) { PyObject *hook = _PySys_GetAttr(tstate, &_Py_ID(displayhook)); // Can't use ERROR_IF here. if (hook == NULL) { _PyErr_SetString(tstate, PyExc_RuntimeError, "lost sys.displayhook"); return NULL; } return PyObject_CallOneArg(hook, value); } static int import_all_from(PyThreadState *tstate, PyObject *locals, PyObject *v) { PyObject *all, *dict, *name, *value; int skip_leading_underscores = 0; int pos, err; if (_PyObject_LookupAttr(v, &_Py_ID(__all__), &all) < 0) { return -1; /* Unexpected error */ } if (all == NULL) { if (_PyObject_LookupAttr(v, &_Py_ID(__dict__), &dict) < 0) { return -1; } if (dict == NULL) { _PyErr_SetString(tstate, PyExc_ImportError, "from-import-* object has no __dict__ and no __all__"); return -1; } all = PyMapping_Keys(dict); Py_DECREF(dict); if (all == NULL) return -1; skip_leading_underscores = 1; } for (pos = 0, err = 0; ; pos++) { name = PySequence_GetItem(all, pos); if (name == NULL) { if (!_PyErr_ExceptionMatches(tstate, PyExc_IndexError)) { err = -1; } else { _PyErr_Clear(tstate); } break; } if (!PyUnicode_Check(name)) { PyObject *modname = PyObject_GetAttr(v, &_Py_ID(__name__)); if (modname == NULL) { Py_DECREF(name); err = -1; break; } if (!PyUnicode_Check(modname)) { _PyErr_Format(tstate, PyExc_TypeError, "module __name__ must be a string, not %.100s", Py_TYPE(modname)->tp_name); } else { _PyErr_Format(tstate, PyExc_TypeError, "%s in %U.%s must be str, not %.100s", skip_leading_underscores ? "Key" : "Item", modname, skip_leading_underscores ? "__dict__" : "__all__", Py_TYPE(name)->tp_name); } Py_DECREF(modname); Py_DECREF(name); err = -1; break; } if (skip_leading_underscores) { if (PyUnicode_READ_CHAR(name, 0) == '_') { Py_DECREF(name); continue; } } value = PyObject_GetAttr(v, name); if (value == NULL) err = -1; else if (PyDict_CheckExact(locals)) err = PyDict_SetItem(locals, name, value); else err = PyObject_SetItem(locals, name, value); Py_DECREF(name); Py_XDECREF(value); if (err < 0) break; } Py_DECREF(all); return err; } static PyObject * import_star(PyThreadState* tstate, PyObject *from) { _PyInterpreterFrame *frame = tstate->cframe->current_frame; if (_PyFrame_FastToLocalsWithError(frame) < 0) { return NULL; } PyObject *locals = frame->f_locals; if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, "no locals found during 'import *'"); return NULL; } int err = import_all_from(tstate, locals, from); _PyFrame_LocalsToFast(frame, 0); if (err < 0) { return NULL; } Py_RETURN_NONE; } static PyObject * stopiteration_error(PyThreadState* tstate, PyObject *exc) { _PyInterpreterFrame *frame = tstate->cframe->current_frame; assert(frame->owner == FRAME_OWNED_BY_GENERATOR); assert(PyExceptionInstance_Check(exc)); const char *msg = NULL; if (PyErr_GivenExceptionMatches(exc, PyExc_StopIteration)) { msg = "generator raised StopIteration"; if (frame->f_code->co_flags & CO_ASYNC_GENERATOR) { msg = "async generator raised StopIteration"; } else if (frame->f_code->co_flags & CO_COROUTINE) { msg = "coroutine raised StopIteration"; } } else if ((frame->f_code->co_flags & CO_ASYNC_GENERATOR) && PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { /* code in `gen` raised a StopAsyncIteration error: raise a RuntimeError. */ msg = "async generator raised StopAsyncIteration"; } if (msg != NULL) { PyObject *message = _PyUnicode_FromASCII(msg, strlen(msg)); if (message == NULL) { return NULL; } PyObject *error = PyObject_CallOneArg(PyExc_RuntimeError, message); if (error == NULL) { Py_DECREF(message); return NULL; } assert(PyExceptionInstance_Check(error)); PyException_SetCause(error, Py_NewRef(exc)); // Steal exc reference, rather than Py_NewRef+Py_DECREF PyException_SetContext(error, Py_NewRef(exc)); Py_DECREF(message); return error; } return Py_NewRef(exc); } static PyObject * unary_pos(PyThreadState* unused, PyObject *value) { return PyNumber_Positive(value); } static PyObject * list_to_tuple(PyThreadState* unused, PyObject *v) { assert(PyList_Check(v)); return _PyTuple_FromArray(((PyListObject *)v)->ob_item, Py_SIZE(v)); } static PyObject * make_typevar(PyThreadState* Py_UNUSED(ignored), PyObject *v) { assert(PyUnicode_Check(v)); return _Py_make_typevar(v, NULL, NULL); } const instrinsic_func1 _PyIntrinsics_UnaryFunctions[] = { [0] = no_intrinsic, [INTRINSIC_PRINT] = print_expr, [INTRINSIC_IMPORT_STAR] = import_star, [INTRINSIC_STOPITERATION_ERROR] = stopiteration_error, [INTRINSIC_ASYNC_GEN_WRAP] = _PyAsyncGenValueWrapperNew, [INTRINSIC_UNARY_POSITIVE] = unary_pos, [INTRINSIC_LIST_TO_TUPLE] = list_to_tuple, [INTRINSIC_TYPEVAR] = make_typevar, [INTRINSIC_PARAMSPEC] = _Py_make_paramspec, [INTRINSIC_TYPEVARTUPLE] = _Py_make_typevartuple, [INTRINSIC_SUBSCRIPT_GENERIC] = _Py_subscript_generic, [INTRINSIC_TYPEALIAS] = _Py_make_typealias, }; /******** Binary functions ********/ static PyObject * prep_reraise_star(PyThreadState* unused, PyObject *orig, PyObject *excs) { assert(PyList_Check(excs)); return _PyExc_PrepReraiseStar(orig, excs); } static PyObject * make_typevar_with_bound(PyThreadState* Py_UNUSED(ignored), PyObject *name, PyObject *evaluate_bound) { assert(PyUnicode_Check(name)); return _Py_make_typevar(name, evaluate_bound, NULL); } static PyObject * make_typevar_with_constraints(PyThreadState* Py_UNUSED(ignored), PyObject *name, PyObject *evaluate_constraints) { assert(PyUnicode_Check(name)); return _Py_make_typevar(name, NULL, evaluate_constraints); } const instrinsic_func2 _PyIntrinsics_BinaryFunctions[] = { [INTRINSIC_PREP_RERAISE_STAR] = prep_reraise_star, [INTRINSIC_TYPEVAR_WITH_BOUND] = make_typevar_with_bound, [INTRINSIC_TYPEVAR_WITH_CONSTRAINTS] = make_typevar_with_constraints, [INTRINSIC_SET_FUNCTION_TYPE_PARAMS] = _Py_set_function_type_params, }; ================================================ FILE: InitConfig.c ================================================ #include "Python.h" #include "pycore_fileutils.h" // _Py_HasFileSystemDefaultEncodeErrors #include "pycore_getopt.h" // _PyOS_GetOpt() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_interp.h" // _PyInterpreterState.runtime #include "pycore_long.h" // _PY_LONG_MAX_STR_DIGITS_THRESHOLD #include "pycore_pathconfig.h" // _Py_path_config #include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pylifecycle.h" // _Py_PreInitializeFromConfig() #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator() #include "pycore_pystate.h" // _PyThreadState_GET() #include "osdefs.h" // DELIM #include // setlocale() #include // getenv() #if defined(MS_WINDOWS) || defined(__CYGWIN__) # ifdef HAVE_IO_H # include # endif # ifdef HAVE_FCNTL_H # include // O_BINARY # endif #endif /* --- Command line options --------------------------------------- */ /* Short usage message (with %s for argv0) */ static const char usage_line[] = "usage: %ls [option] ... [-c cmd | -m mod | file | -] [arg] ...\n"; /* Long help message */ /* Lines sorted by option name; keep in sync with usage_envvars* below */ static const char usage_help[] = "\ Options (and corresponding environment variables):\n\ -b : issue warnings about str(bytes_instance), str(bytearray_instance)\n\ and comparing bytes/bytearray with str. (-bb: issue errors)\n\ -B : don't write .pyc files on import; also PYTHONDONTWRITEBYTECODE=x\n\ -c cmd : program passed in as string (terminates option list)\n\ -d : turn on parser debugging output (for experts only, only works on\n\ debug builds); also PYTHONDEBUG=x\n\ -E : ignore PYTHON* environment variables (such as PYTHONPATH)\n\ -h : print this help message and exit (also -? or --help)\n\ -i : inspect interactively after running script; forces a prompt even\n\ if stdin does not appear to be a terminal; also PYTHONINSPECT=x\n\ -I : isolate Python from the user's environment (implies -E and -s)\n\ -m mod : run library module as a script (terminates option list)\n\ -O : remove assert and __debug__-dependent statements; add .opt-1 before\n\ .pyc extension; also PYTHONOPTIMIZE=x\n\ -OO : do -O changes and also discard docstrings; add .opt-2 before\n\ .pyc extension\n\ -P : don't prepend a potentially unsafe path to sys.path\n\ -q : don't print version and copyright messages on interactive startup\n\ -s : don't add user site directory to sys.path; also PYTHONNOUSERSITE\n\ -S : don't imply 'import site' on initialization\n\ -u : force the stdout and stderr streams to be unbuffered;\n\ this option has no effect on stdin; also PYTHONUNBUFFERED=x\n\ -v : verbose (trace import statements); also PYTHONVERBOSE=x\n\ can be supplied multiple times to increase verbosity\n\ -V : print the Python version number and exit (also --version)\n\ when given twice, print more information about the build\n\ -W arg : warning control; arg is action:message:category:module:lineno\n\ also PYTHONWARNINGS=arg\n\ -x : skip first line of source, allowing use of non-Unix forms of #!cmd\n\ -X opt : set implementation-specific option\n\ --check-hash-based-pycs always|default|never:\n\ control how Python invalidates hash-based .pyc files\n\ --help-env : print help about Python environment variables and exit\n\ --help-xoptions : print help about implementation-specific -X options and exit\n\ --help-all : print complete help information and exit\n\ Arguments:\n\ file : program read from script file\n\ - : program read from stdin (default; interactive mode if a tty)\n\ arg ...: arguments passed to program in sys.argv[1:]\n\ "; static const char usage_xoptions[] = "\ The following implementation-specific options are available:\n\ \n\ -X faulthandler: enable faulthandler\n\ \n\ -X showrefcount: output the total reference count and number of used\n\ memory blocks when the program finishes or after each statement in the\n\ interactive interpreter. This only works on debug builds\n\ \n\ -X tracemalloc: start tracing Python memory allocations using the\n\ tracemalloc module. By default, only the most recent frame is stored in a\n\ traceback of a trace. Use -X tracemalloc=NFRAME to start tracing with a\n\ traceback limit of NFRAME frames\n\ \n\ -X importtime: show how long each import takes. It shows module name,\n\ cumulative time (including nested imports) and self time (excluding\n\ nested imports). Note that its output may be broken in multi-threaded\n\ application. Typical usage is python3 -X importtime -c 'import asyncio'\n\ \n\ -X dev: enable CPython's \"development mode\", introducing additional runtime\n\ checks which are too expensive to be enabled by default. Effect of the\n\ developer mode:\n\ * Add default warning filter, as -W default\n\ * Install debug hooks on memory allocators: see the PyMem_SetupDebugHooks()\n\ C function\n\ * Enable the faulthandler module to dump the Python traceback on a crash\n\ * Enable asyncio debug mode\n\ * Set the dev_mode attribute of sys.flags to True\n\ * io.IOBase destructor logs close() exceptions\n\ \n\ -X utf8: enable UTF-8 mode for operating system interfaces, overriding the default\n\ locale-aware mode. -X utf8=0 explicitly disables UTF-8 mode (even when it would\n\ otherwise activate automatically)\n\ \n\ -X pycache_prefix=PATH: enable writing .pyc files to a parallel tree rooted at the\n\ given directory instead of to the code tree\n\ \n\ -X warn_default_encoding: enable opt-in EncodingWarning for 'encoding=None'\n\ \n\ -X no_debug_ranges: disable the inclusion of the tables mapping extra location \n\ information (end line, start column offset and end column offset) to every \n\ instruction in code objects. This is useful when smaller code objects and pyc \n\ files are desired as well as suppressing the extra visual location indicators \n\ when the interpreter displays tracebacks.\n\ \n\ -X perf: activate support for the Linux \"perf\" profiler by activating the \"perf\"\n\ trampoline. When this option is activated, the Linux \"perf\" profiler will be \n\ able to report Python calls. This option is only available on some platforms and will \n\ do nothing if is not supported on the current system. The default value is \"off\".\n\ \n\ -X frozen_modules=[on|off]: whether or not frozen modules should be used.\n\ The default is \"on\" (or \"off\" if you are running a local build).\n\ \n\ -X int_max_str_digits=number: limit the size of int<->str conversions.\n\ This helps avoid denial of service attacks when parsing untrusted data.\n\ The default is sys.int_info.default_max_str_digits. 0 disables." #ifdef Py_STATS "\n\ \n\ -X pystats: Enable pystats collection at startup." #endif ; /* Envvars that don't have equivalent command-line options are listed first */ static const char usage_envvars[] = "Environment variables that change behavior:\n" "PYTHONSTARTUP: file executed on interactive startup (no default)\n" "PYTHONPATH : '%lc'-separated list of directories prefixed to the\n" " default module search path. The result is sys.path.\n" "PYTHONSAFEPATH: don't prepend a potentially unsafe path to sys.path.\n" "PYTHONHOME : alternate directory (or %lc).\n" " The default module search path uses %s.\n" "PYTHONPLATLIBDIR : override sys.platlibdir.\n" "PYTHONCASEOK : ignore case in 'import' statements (Windows).\n" "PYTHONUTF8: if set to 1, enable the UTF-8 mode.\n" "PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.\n" "PYTHONFAULTHANDLER: dump the Python traceback on fatal errors.\n" "PYTHONHASHSEED: if this variable is set to 'random', a random value is used\n" " to seed the hashes of str and bytes objects. It can also be set to an\n" " integer in the range [0,4294967295] to get hash values with a\n" " predictable seed.\n" "PYTHONINTMAXSTRDIGITS: limits the maximum digit characters in an int value\n" " when converting from a string and when converting an int back to a str.\n" " A value of 0 disables the limit. Conversions to or from bases 2, 4, 8,\n" " 16, and 32 are never limited.\n" "PYTHONMALLOC: set the Python memory allocators and/or install debug hooks\n" " on Python memory allocators. Use PYTHONMALLOC=debug to install debug\n" " hooks.\n" "PYTHONCOERCECLOCALE: if this variable is set to 0, it disables the locale\n" " coercion behavior. Use PYTHONCOERCECLOCALE=warn to request display of\n" " locale coercion and locale compatibility warnings on stderr.\n" "PYTHONBREAKPOINT: if this variable is set to 0, it disables the default\n" " debugger. It can be set to the callable of your debugger of choice.\n" "PYTHONDEVMODE: enable the development mode.\n" "PYTHONPYCACHEPREFIX: root directory for bytecode cache (pyc) files.\n" "PYTHONWARNDEFAULTENCODING: enable opt-in EncodingWarning for 'encoding=None'.\n" "PYTHONNODEBUGRANGES: If this variable is set, it disables the inclusion of the \n" " tables mapping extra location information (end line, start column offset \n" " and end column offset) to every instruction in code objects. This is useful \n" " when smaller code objects and pyc files are desired as well as suppressing the \n" " extra visual location indicators when the interpreter displays tracebacks.\n" "These variables have equivalent command-line parameters (see --help for details):\n" "PYTHONDEBUG : enable parser debug mode (-d)\n" "PYTHONDONTWRITEBYTECODE : don't write .pyc files (-B)\n" "PYTHONINSPECT : inspect interactively after running script (-i)\n" "PYTHONINTMAXSTRDIGITS : limit max digit characters in an int value\n" " (-X int_max_str_digits=number)\n" "PYTHONNOUSERSITE : disable user site directory (-s)\n" "PYTHONOPTIMIZE : enable level 1 optimizations (-O)\n" "PYTHONUNBUFFERED : disable stdout/stderr buffering (-u)\n" "PYTHONVERBOSE : trace import statements (-v)\n" "PYTHONWARNINGS=arg : warning control (-W arg)\n"; #if defined(MS_WINDOWS) # define PYTHONHOMEHELP "\\python{major}{minor}" #else # define PYTHONHOMEHELP "/lib/pythonX.X" #endif /* --- Global configuration variables ----------------------------- */ /* UTF-8 mode (PEP 540): if equals to 1, use the UTF-8 encoding, and change stdin and stdout error handler to "surrogateescape". */ int Py_UTF8Mode = 0; int Py_DebugFlag = 0; /* Needed by parser.c */ int Py_VerboseFlag = 0; /* Needed by import.c */ int Py_QuietFlag = 0; /* Needed by sysmodule.c */ int Py_InteractiveFlag = 0; /* Previously, was used by Py_FdIsInteractive() */ int Py_InspectFlag = 0; /* Needed to determine whether to exit at SystemExit */ int Py_OptimizeFlag = 0; /* Needed by compile.c */ int Py_NoSiteFlag = 0; /* Suppress 'import site' */ int Py_BytesWarningFlag = 0; /* Warn on str(bytes) and str(buffer) */ int Py_FrozenFlag = 0; /* Needed by getpath.c */ int Py_IgnoreEnvironmentFlag = 0; /* e.g. PYTHONPATH, PYTHONHOME */ int Py_DontWriteBytecodeFlag = 0; /* Suppress writing bytecode files (*.pyc) */ int Py_NoUserSiteDirectory = 0; /* for -s and site.py */ int Py_UnbufferedStdioFlag = 0; /* Unbuffered binary std{in,out,err} */ int Py_HashRandomizationFlag = 0; /* for -R and PYTHONHASHSEED */ int Py_IsolatedFlag = 0; /* for -I, isolate from user's env */ #ifdef MS_WINDOWS int Py_LegacyWindowsFSEncodingFlag = 0; /* Uses mbcs instead of utf-8 */ int Py_LegacyWindowsStdioFlag = 0; /* Uses FileIO instead of WindowsConsoleIO */ #endif static PyObject * _Py_GetGlobalVariablesAsDict(void) { _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS PyObject *dict, *obj; dict = PyDict_New(); if (dict == NULL) { return NULL; } #define SET_ITEM(KEY, EXPR) \ do { \ obj = (EXPR); \ if (obj == NULL) { \ return NULL; \ } \ int res = PyDict_SetItemString(dict, (KEY), obj); \ Py_DECREF(obj); \ if (res < 0) { \ goto fail; \ } \ } while (0) #define SET_ITEM_INT(VAR) \ SET_ITEM(#VAR, PyLong_FromLong(VAR)) #define FROM_STRING(STR) \ ((STR != NULL) ? \ PyUnicode_FromString(STR) \ : Py_NewRef(Py_None)) #define SET_ITEM_STR(VAR) \ SET_ITEM(#VAR, FROM_STRING(VAR)) SET_ITEM_STR(Py_FileSystemDefaultEncoding); SET_ITEM_INT(Py_HasFileSystemDefaultEncoding); SET_ITEM_STR(Py_FileSystemDefaultEncodeErrors); SET_ITEM_INT(_Py_HasFileSystemDefaultEncodeErrors); SET_ITEM_INT(Py_UTF8Mode); SET_ITEM_INT(Py_DebugFlag); SET_ITEM_INT(Py_VerboseFlag); SET_ITEM_INT(Py_QuietFlag); SET_ITEM_INT(Py_InteractiveFlag); SET_ITEM_INT(Py_InspectFlag); SET_ITEM_INT(Py_OptimizeFlag); SET_ITEM_INT(Py_NoSiteFlag); SET_ITEM_INT(Py_BytesWarningFlag); SET_ITEM_INT(Py_FrozenFlag); SET_ITEM_INT(Py_IgnoreEnvironmentFlag); SET_ITEM_INT(Py_DontWriteBytecodeFlag); SET_ITEM_INT(Py_NoUserSiteDirectory); SET_ITEM_INT(Py_UnbufferedStdioFlag); SET_ITEM_INT(Py_HashRandomizationFlag); SET_ITEM_INT(Py_IsolatedFlag); #ifdef MS_WINDOWS SET_ITEM_INT(Py_LegacyWindowsFSEncodingFlag); SET_ITEM_INT(Py_LegacyWindowsStdioFlag); #endif return dict; fail: Py_DECREF(dict); return NULL; #undef FROM_STRING #undef SET_ITEM #undef SET_ITEM_INT #undef SET_ITEM_STR _Py_COMP_DIAG_POP } char* Py_GETENV(const char *name) { _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS if (Py_IgnoreEnvironmentFlag) { return NULL; } return getenv(name); _Py_COMP_DIAG_POP } /* --- PyStatus ----------------------------------------------- */ PyStatus PyStatus_Ok(void) { return _PyStatus_OK(); } PyStatus PyStatus_Error(const char *err_msg) { assert(err_msg != NULL); return (PyStatus){._type = _PyStatus_TYPE_ERROR, .err_msg = err_msg}; } PyStatus PyStatus_NoMemory(void) { return PyStatus_Error("memory allocation failed"); } PyStatus PyStatus_Exit(int exitcode) { return _PyStatus_EXIT(exitcode); } int PyStatus_IsError(PyStatus status) { return _PyStatus_IS_ERROR(status); } int PyStatus_IsExit(PyStatus status) { return _PyStatus_IS_EXIT(status); } int PyStatus_Exception(PyStatus status) { return _PyStatus_EXCEPTION(status); } PyObject* _PyErr_SetFromPyStatus(PyStatus status) { if (!_PyStatus_IS_ERROR(status)) { PyErr_Format(PyExc_SystemError, "%s() expects an error PyStatus", _PyStatus_GET_FUNC()); } else if (status.func) { PyErr_Format(PyExc_ValueError, "%s: %s", status.func, status.err_msg); } else { PyErr_Format(PyExc_ValueError, "%s", status.err_msg); } return NULL; } /* --- PyWideStringList ------------------------------------------------ */ #ifndef NDEBUG int _PyWideStringList_CheckConsistency(const PyWideStringList *list) { assert(list->length >= 0); if (list->length != 0) { assert(list->items != NULL); } for (Py_ssize_t i = 0; i < list->length; i++) { assert(list->items[i] != NULL); } return 1; } #endif /* Py_DEBUG */ void _PyWideStringList_Clear(PyWideStringList *list) { assert(_PyWideStringList_CheckConsistency(list)); for (Py_ssize_t i=0; i < list->length; i++) { PyMem_RawFree(list->items[i]); } PyMem_RawFree(list->items); list->length = 0; list->items = NULL; } int _PyWideStringList_Copy(PyWideStringList *list, const PyWideStringList *list2) { assert(_PyWideStringList_CheckConsistency(list)); assert(_PyWideStringList_CheckConsistency(list2)); if (list2->length == 0) { _PyWideStringList_Clear(list); return 0; } PyWideStringList copy = _PyWideStringList_INIT; size_t size = list2->length * sizeof(list2->items[0]); copy.items = PyMem_RawMalloc(size); if (copy.items == NULL) { return -1; } for (Py_ssize_t i=0; i < list2->length; i++) { wchar_t *item = _PyMem_RawWcsdup(list2->items[i]); if (item == NULL) { _PyWideStringList_Clear(©); return -1; } copy.items[i] = item; copy.length = i + 1; } _PyWideStringList_Clear(list); *list = copy; return 0; } PyStatus PyWideStringList_Insert(PyWideStringList *list, Py_ssize_t index, const wchar_t *item) { Py_ssize_t len = list->length; if (len == PY_SSIZE_T_MAX) { /* length+1 would overflow */ return _PyStatus_NO_MEMORY(); } if (index < 0) { return _PyStatus_ERR("PyWideStringList_Insert index must be >= 0"); } if (index > len) { index = len; } wchar_t *item2 = _PyMem_RawWcsdup(item); if (item2 == NULL) { return _PyStatus_NO_MEMORY(); } size_t size = (len + 1) * sizeof(list->items[0]); wchar_t **items2 = (wchar_t **)PyMem_RawRealloc(list->items, size); if (items2 == NULL) { PyMem_RawFree(item2); return _PyStatus_NO_MEMORY(); } if (index < len) { memmove(&items2[index + 1], &items2[index], (len - index) * sizeof(items2[0])); } items2[index] = item2; list->items = items2; list->length++; return _PyStatus_OK(); } PyStatus PyWideStringList_Append(PyWideStringList *list, const wchar_t *item) { return PyWideStringList_Insert(list, list->length, item); } PyStatus _PyWideStringList_Extend(PyWideStringList *list, const PyWideStringList *list2) { for (Py_ssize_t i = 0; i < list2->length; i++) { PyStatus status = PyWideStringList_Append(list, list2->items[i]); if (_PyStatus_EXCEPTION(status)) { return status; } } return _PyStatus_OK(); } static int _PyWideStringList_Find(PyWideStringList *list, const wchar_t *item) { for (Py_ssize_t i = 0; i < list->length; i++) { if (wcscmp(list->items[i], item) == 0) { return 1; } } return 0; } PyObject* _PyWideStringList_AsList(const PyWideStringList *list) { assert(_PyWideStringList_CheckConsistency(list)); PyObject *pylist = PyList_New(list->length); if (pylist == NULL) { return NULL; } for (Py_ssize_t i = 0; i < list->length; i++) { PyObject *item = PyUnicode_FromWideChar(list->items[i], -1); if (item == NULL) { Py_DECREF(pylist); return NULL; } PyList_SET_ITEM(pylist, i, item); } return pylist; } /* --- Py_GetArgcArgv() ------------------------------------------- */ void _Py_ClearArgcArgv(void) { PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); _PyWideStringList_Clear(&_PyRuntime.orig_argv); PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); } static int _Py_SetArgcArgv(Py_ssize_t argc, wchar_t * const *argv) { const PyWideStringList argv_list = {.length = argc, .items = (wchar_t **)argv}; int res; PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); // XXX _PyRuntime.orig_argv only gets cleared by Py_Main(), // so it it currently leaks for embedders. res = _PyWideStringList_Copy(&_PyRuntime.orig_argv, &argv_list); PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); return res; } // _PyConfig_Write() calls _Py_SetArgcArgv() with PyConfig.orig_argv. void Py_GetArgcArgv(int *argc, wchar_t ***argv) { *argc = (int)_PyRuntime.orig_argv.length; *argv = _PyRuntime.orig_argv.items; } /* --- PyConfig ---------------------------------------------- */ #define MAX_HASH_SEED 4294967295UL #ifndef NDEBUG static int config_check_consistency(const PyConfig *config) { /* Check config consistency */ assert(config->isolated >= 0); assert(config->use_environment >= 0); assert(config->dev_mode >= 0); assert(config->install_signal_handlers >= 0); assert(config->use_hash_seed >= 0); assert(config->hash_seed <= MAX_HASH_SEED); assert(config->faulthandler >= 0); assert(config->tracemalloc >= 0); assert(config->import_time >= 0); assert(config->code_debug_ranges >= 0); assert(config->show_ref_count >= 0); assert(config->dump_refs >= 0); assert(config->malloc_stats >= 0); assert(config->site_import >= 0); assert(config->bytes_warning >= 0); assert(config->warn_default_encoding >= 0); assert(config->inspect >= 0); assert(config->interactive >= 0); assert(config->optimization_level >= 0); assert(config->parser_debug >= 0); assert(config->write_bytecode >= 0); assert(config->verbose >= 0); assert(config->quiet >= 0); assert(config->user_site_directory >= 0); assert(config->parse_argv >= 0); assert(config->configure_c_stdio >= 0); assert(config->buffered_stdio >= 0); assert(_PyWideStringList_CheckConsistency(&config->orig_argv)); assert(_PyWideStringList_CheckConsistency(&config->argv)); /* sys.argv must be non-empty: empty argv is replaced with [''] */ assert(config->argv.length >= 1); assert(_PyWideStringList_CheckConsistency(&config->xoptions)); assert(_PyWideStringList_CheckConsistency(&config->warnoptions)); assert(_PyWideStringList_CheckConsistency(&config->module_search_paths)); assert(config->module_search_paths_set >= 0); assert(config->filesystem_encoding != NULL); assert(config->filesystem_errors != NULL); assert(config->stdio_encoding != NULL); assert(config->stdio_errors != NULL); #ifdef MS_WINDOWS assert(config->legacy_windows_stdio >= 0); #endif /* -c and -m options are exclusive */ assert(!(config->run_command != NULL && config->run_module != NULL)); assert(config->check_hash_pycs_mode != NULL); assert(config->_install_importlib >= 0); assert(config->pathconfig_warnings >= 0); assert(config->_is_python_build >= 0); assert(config->safe_path >= 0); assert(config->int_max_str_digits >= 0); // config->use_frozen_modules is initialized later // by _PyConfig_InitImportConfig(). return 1; } #endif /* Free memory allocated in config, but don't clear all attributes */ void PyConfig_Clear(PyConfig *config) { #define CLEAR(ATTR) \ do { \ PyMem_RawFree(ATTR); \ ATTR = NULL; \ } while (0) CLEAR(config->pycache_prefix); CLEAR(config->pythonpath_env); CLEAR(config->home); CLEAR(config->program_name); _PyWideStringList_Clear(&config->argv); _PyWideStringList_Clear(&config->warnoptions); _PyWideStringList_Clear(&config->xoptions); _PyWideStringList_Clear(&config->module_search_paths); config->module_search_paths_set = 0; CLEAR(config->stdlib_dir); CLEAR(config->executable); CLEAR(config->base_executable); CLEAR(config->prefix); CLEAR(config->base_prefix); CLEAR(config->exec_prefix); CLEAR(config->base_exec_prefix); CLEAR(config->platlibdir); CLEAR(config->filesystem_encoding); CLEAR(config->filesystem_errors); CLEAR(config->stdio_encoding); CLEAR(config->stdio_errors); CLEAR(config->run_command); CLEAR(config->run_module); CLEAR(config->run_filename); CLEAR(config->check_hash_pycs_mode); _PyWideStringList_Clear(&config->orig_argv); #undef CLEAR } void _PyConfig_InitCompatConfig(PyConfig *config) { memset(config, 0, sizeof(*config)); config->_config_init = (int)_PyConfig_INIT_COMPAT; config->isolated = -1; config->use_environment = -1; config->dev_mode = -1; config->install_signal_handlers = 1; config->use_hash_seed = -1; config->faulthandler = -1; config->tracemalloc = -1; config->perf_profiling = -1; config->module_search_paths_set = 0; config->parse_argv = 0; config->site_import = -1; config->bytes_warning = -1; config->warn_default_encoding = 0; config->inspect = -1; config->interactive = -1; config->optimization_level = -1; config->parser_debug= -1; config->write_bytecode = -1; config->verbose = -1; config->quiet = -1; config->user_site_directory = -1; config->configure_c_stdio = 0; config->buffered_stdio = -1; config->_install_importlib = 1; config->check_hash_pycs_mode = NULL; config->pathconfig_warnings = -1; config->_init_main = 1; #ifdef MS_WINDOWS config->legacy_windows_stdio = -1; #endif #ifdef Py_DEBUG config->use_frozen_modules = 0; #else config->use_frozen_modules = 1; #endif config->safe_path = 0; config->int_max_str_digits = -1; config->_is_python_build = 0; config->code_debug_ranges = 1; } static void config_init_defaults(PyConfig *config) { _PyConfig_InitCompatConfig(config); config->isolated = 0; config->use_environment = 1; config->site_import = 1; config->bytes_warning = 0; config->inspect = 0; config->interactive = 0; config->optimization_level = 0; config->parser_debug= 0; config->write_bytecode = 1; config->verbose = 0; config->quiet = 0; config->user_site_directory = 1; config->buffered_stdio = 1; config->pathconfig_warnings = 1; #ifdef MS_WINDOWS config->legacy_windows_stdio = 0; #endif } void PyConfig_InitPythonConfig(PyConfig *config) { config_init_defaults(config); config->_config_init = (int)_PyConfig_INIT_PYTHON; config->configure_c_stdio = 1; config->parse_argv = 1; } void PyConfig_InitIsolatedConfig(PyConfig *config) { config_init_defaults(config); config->_config_init = (int)_PyConfig_INIT_ISOLATED; config->isolated = 1; config->use_environment = 0; config->user_site_directory = 0; config->dev_mode = 0; config->install_signal_handlers = 0; config->use_hash_seed = 0; config->faulthandler = 0; config->tracemalloc = 0; config->perf_profiling = 0; config->int_max_str_digits = _PY_LONG_DEFAULT_MAX_STR_DIGITS; config->safe_path = 1; config->pathconfig_warnings = 0; #ifdef MS_WINDOWS config->legacy_windows_stdio = 0; #endif } /* Copy str into *config_str (duplicate the string) */ PyStatus PyConfig_SetString(PyConfig *config, wchar_t **config_str, const wchar_t *str) { PyStatus status = _Py_PreInitializeFromConfig(config, NULL); if (_PyStatus_EXCEPTION(status)) { return status; } wchar_t *str2; if (str != NULL) { str2 = _PyMem_RawWcsdup(str); if (str2 == NULL) { return _PyStatus_NO_MEMORY(); } } else { str2 = NULL; } PyMem_RawFree(*config_str); *config_str = str2; return _PyStatus_OK(); } static PyStatus config_set_bytes_string(PyConfig *config, wchar_t **config_str, const char *str, const char *decode_err_msg) { PyStatus status = _Py_PreInitializeFromConfig(config, NULL); if (_PyStatus_EXCEPTION(status)) { return status; } wchar_t *str2; if (str != NULL) { size_t len; str2 = Py_DecodeLocale(str, &len); if (str2 == NULL) { if (len == (size_t)-2) { return _PyStatus_ERR(decode_err_msg); } else { return _PyStatus_NO_MEMORY(); } } } else { str2 = NULL; } PyMem_RawFree(*config_str); *config_str = str2; return _PyStatus_OK(); } #define CONFIG_SET_BYTES_STR(config, config_str, str, NAME) \ config_set_bytes_string(config, config_str, str, "cannot decode " NAME) /* Decode str using Py_DecodeLocale() and set the result into *config_str. Pre-initialize Python if needed to ensure that encodings are properly configured. */ PyStatus PyConfig_SetBytesString(PyConfig *config, wchar_t **config_str, const char *str) { return CONFIG_SET_BYTES_STR(config, config_str, str, "string"); } PyStatus _PyConfig_Copy(PyConfig *config, const PyConfig *config2) { PyStatus status; PyConfig_Clear(config); #define COPY_ATTR(ATTR) config->ATTR = config2->ATTR #define COPY_WSTR_ATTR(ATTR) \ do { \ status = PyConfig_SetString(config, &config->ATTR, config2->ATTR); \ if (_PyStatus_EXCEPTION(status)) { \ return status; \ } \ } while (0) #define COPY_WSTRLIST(LIST) \ do { \ if (_PyWideStringList_Copy(&config->LIST, &config2->LIST) < 0) { \ return _PyStatus_NO_MEMORY(); \ } \ } while (0) COPY_ATTR(_config_init); COPY_ATTR(isolated); COPY_ATTR(use_environment); COPY_ATTR(dev_mode); COPY_ATTR(install_signal_handlers); COPY_ATTR(use_hash_seed); COPY_ATTR(hash_seed); COPY_ATTR(_install_importlib); COPY_ATTR(faulthandler); COPY_ATTR(tracemalloc); COPY_ATTR(perf_profiling); COPY_ATTR(import_time); COPY_ATTR(code_debug_ranges); COPY_ATTR(show_ref_count); COPY_ATTR(dump_refs); COPY_ATTR(dump_refs_file); COPY_ATTR(malloc_stats); COPY_WSTR_ATTR(pycache_prefix); COPY_WSTR_ATTR(pythonpath_env); COPY_WSTR_ATTR(home); COPY_WSTR_ATTR(program_name); COPY_ATTR(parse_argv); COPY_WSTRLIST(argv); COPY_WSTRLIST(warnoptions); COPY_WSTRLIST(xoptions); COPY_WSTRLIST(module_search_paths); COPY_ATTR(module_search_paths_set); COPY_WSTR_ATTR(stdlib_dir); COPY_WSTR_ATTR(executable); COPY_WSTR_ATTR(base_executable); COPY_WSTR_ATTR(prefix); COPY_WSTR_ATTR(base_prefix); COPY_WSTR_ATTR(exec_prefix); COPY_WSTR_ATTR(base_exec_prefix); COPY_WSTR_ATTR(platlibdir); COPY_ATTR(site_import); COPY_ATTR(bytes_warning); COPY_ATTR(warn_default_encoding); COPY_ATTR(inspect); COPY_ATTR(interactive); COPY_ATTR(optimization_level); COPY_ATTR(parser_debug); COPY_ATTR(write_bytecode); COPY_ATTR(verbose); COPY_ATTR(quiet); COPY_ATTR(user_site_directory); COPY_ATTR(configure_c_stdio); COPY_ATTR(buffered_stdio); COPY_WSTR_ATTR(filesystem_encoding); COPY_WSTR_ATTR(filesystem_errors); COPY_WSTR_ATTR(stdio_encoding); COPY_WSTR_ATTR(stdio_errors); #ifdef MS_WINDOWS COPY_ATTR(legacy_windows_stdio); #endif COPY_ATTR(skip_source_first_line); COPY_WSTR_ATTR(run_command); COPY_WSTR_ATTR(run_module); COPY_WSTR_ATTR(run_filename); COPY_WSTR_ATTR(check_hash_pycs_mode); COPY_ATTR(pathconfig_warnings); COPY_ATTR(_init_main); COPY_ATTR(use_frozen_modules); COPY_ATTR(safe_path); COPY_WSTRLIST(orig_argv); COPY_ATTR(_is_python_build); COPY_ATTR(int_max_str_digits); #undef COPY_ATTR #undef COPY_WSTR_ATTR #undef COPY_WSTRLIST return _PyStatus_OK(); } PyObject * _PyConfig_AsDict(const PyConfig *config) { PyObject *dict = PyDict_New(); if (dict == NULL) { return NULL; } #define SET_ITEM(KEY, EXPR) \ do { \ PyObject *obj = (EXPR); \ if (obj == NULL) { \ goto fail; \ } \ int res = PyDict_SetItemString(dict, (KEY), obj); \ Py_DECREF(obj); \ if (res < 0) { \ goto fail; \ } \ } while (0) #define SET_ITEM_INT(ATTR) \ SET_ITEM(#ATTR, PyLong_FromLong(config->ATTR)) #define SET_ITEM_UINT(ATTR) \ SET_ITEM(#ATTR, PyLong_FromUnsignedLong(config->ATTR)) #define FROM_WSTRING(STR) \ ((STR != NULL) ? \ PyUnicode_FromWideChar(STR, -1) \ : Py_NewRef(Py_None)) #define SET_ITEM_WSTR(ATTR) \ SET_ITEM(#ATTR, FROM_WSTRING(config->ATTR)) #define SET_ITEM_WSTRLIST(LIST) \ SET_ITEM(#LIST, _PyWideStringList_AsList(&config->LIST)) SET_ITEM_INT(_config_init); SET_ITEM_INT(isolated); SET_ITEM_INT(use_environment); SET_ITEM_INT(dev_mode); SET_ITEM_INT(install_signal_handlers); SET_ITEM_INT(use_hash_seed); SET_ITEM_UINT(hash_seed); SET_ITEM_INT(faulthandler); SET_ITEM_INT(tracemalloc); SET_ITEM_INT(perf_profiling); SET_ITEM_INT(import_time); SET_ITEM_INT(code_debug_ranges); SET_ITEM_INT(show_ref_count); SET_ITEM_INT(dump_refs); SET_ITEM_INT(malloc_stats); SET_ITEM_WSTR(filesystem_encoding); SET_ITEM_WSTR(filesystem_errors); SET_ITEM_WSTR(pycache_prefix); SET_ITEM_WSTR(program_name); SET_ITEM_INT(parse_argv); SET_ITEM_WSTRLIST(argv); SET_ITEM_WSTRLIST(xoptions); SET_ITEM_WSTRLIST(warnoptions); SET_ITEM_WSTR(pythonpath_env); SET_ITEM_WSTR(home); SET_ITEM_INT(module_search_paths_set); SET_ITEM_WSTRLIST(module_search_paths); SET_ITEM_WSTR(stdlib_dir); SET_ITEM_WSTR(executable); SET_ITEM_WSTR(base_executable); SET_ITEM_WSTR(prefix); SET_ITEM_WSTR(base_prefix); SET_ITEM_WSTR(exec_prefix); SET_ITEM_WSTR(base_exec_prefix); SET_ITEM_WSTR(platlibdir); SET_ITEM_INT(site_import); SET_ITEM_INT(bytes_warning); SET_ITEM_INT(warn_default_encoding); SET_ITEM_INT(inspect); SET_ITEM_INT(interactive); SET_ITEM_INT(optimization_level); SET_ITEM_INT(parser_debug); SET_ITEM_INT(write_bytecode); SET_ITEM_INT(verbose); SET_ITEM_INT(quiet); SET_ITEM_INT(user_site_directory); SET_ITEM_INT(configure_c_stdio); SET_ITEM_INT(buffered_stdio); SET_ITEM_WSTR(stdio_encoding); SET_ITEM_WSTR(stdio_errors); #ifdef MS_WINDOWS SET_ITEM_INT(legacy_windows_stdio); #endif SET_ITEM_INT(skip_source_first_line); SET_ITEM_WSTR(run_command); SET_ITEM_WSTR(run_module); SET_ITEM_WSTR(run_filename); SET_ITEM_INT(_install_importlib); SET_ITEM_WSTR(check_hash_pycs_mode); SET_ITEM_INT(pathconfig_warnings); SET_ITEM_INT(_init_main); SET_ITEM_WSTRLIST(orig_argv); SET_ITEM_INT(use_frozen_modules); SET_ITEM_INT(safe_path); SET_ITEM_INT(_is_python_build); SET_ITEM_INT(int_max_str_digits); return dict; fail: Py_DECREF(dict); return NULL; #undef FROM_WSTRING #undef SET_ITEM #undef SET_ITEM_INT #undef SET_ITEM_UINT #undef SET_ITEM_WSTR #undef SET_ITEM_WSTRLIST } static PyObject* config_dict_get(PyObject *dict, const char *name) { PyObject *item = _PyDict_GetItemStringWithError(dict, name); if (item == NULL && !PyErr_Occurred()) { PyErr_Format(PyExc_ValueError, "missing config key: %s", name); return NULL; } return item; } static void config_dict_invalid_value(const char *name) { PyErr_Format(PyExc_ValueError, "invalid config value: %s", name); } static void config_dict_invalid_type(const char *name) { PyErr_Format(PyExc_TypeError, "invalid config type: %s", name); } static int config_dict_get_int(PyObject *dict, const char *name, int *result) { PyObject *item = config_dict_get(dict, name); if (item == NULL) { return -1; } int value = _PyLong_AsInt(item); if (value == -1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_TypeError)) { config_dict_invalid_type(name); } else if (PyErr_ExceptionMatches(PyExc_OverflowError)) { config_dict_invalid_value(name); } return -1; } *result = value; return 0; } static int config_dict_get_ulong(PyObject *dict, const char *name, unsigned long *result) { PyObject *item = config_dict_get(dict, name); if (item == NULL) { return -1; } unsigned long value = PyLong_AsUnsignedLong(item); if (value == (unsigned long)-1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_TypeError)) { config_dict_invalid_type(name); } else if (PyErr_ExceptionMatches(PyExc_OverflowError)) { config_dict_invalid_value(name); } return -1; } *result = value; return 0; } static int config_dict_get_wstr(PyObject *dict, const char *name, PyConfig *config, wchar_t **result) { PyObject *item = config_dict_get(dict, name); if (item == NULL) { return -1; } PyStatus status; if (item == Py_None) { status = PyConfig_SetString(config, result, NULL); } else if (!PyUnicode_Check(item)) { config_dict_invalid_type(name); return -1; } else { wchar_t *wstr = PyUnicode_AsWideCharString(item, NULL); if (wstr == NULL) { return -1; } status = PyConfig_SetString(config, result, wstr); PyMem_Free(wstr); } if (_PyStatus_EXCEPTION(status)) { PyErr_NoMemory(); return -1; } return 0; } static int config_dict_get_wstrlist(PyObject *dict, const char *name, PyConfig *config, PyWideStringList *result) { PyObject *list = config_dict_get(dict, name); if (list == NULL) { return -1; } if (!PyList_CheckExact(list)) { config_dict_invalid_type(name); return -1; } PyWideStringList wstrlist = _PyWideStringList_INIT; for (Py_ssize_t i=0; i < PyList_GET_SIZE(list); i++) { PyObject *item = PyList_GET_ITEM(list, i); if (item == Py_None) { config_dict_invalid_value(name); goto error; } else if (!PyUnicode_Check(item)) { config_dict_invalid_type(name); goto error; } wchar_t *wstr = PyUnicode_AsWideCharString(item, NULL); if (wstr == NULL) { goto error; } PyStatus status = PyWideStringList_Append(&wstrlist, wstr); PyMem_Free(wstr); if (_PyStatus_EXCEPTION(status)) { PyErr_NoMemory(); goto error; } } if (_PyWideStringList_Copy(result, &wstrlist) < 0) { PyErr_NoMemory(); goto error; } _PyWideStringList_Clear(&wstrlist); return 0; error: _PyWideStringList_Clear(&wstrlist); return -1; } int _PyConfig_FromDict(PyConfig *config, PyObject *dict) { if (!PyDict_Check(dict)) { PyErr_SetString(PyExc_TypeError, "dict expected"); return -1; } #define CHECK_VALUE(NAME, TEST) \ if (!(TEST)) { \ config_dict_invalid_value(NAME); \ return -1; \ } #define GET_UINT(KEY) \ do { \ if (config_dict_get_int(dict, #KEY, &config->KEY) < 0) { \ return -1; \ } \ CHECK_VALUE(#KEY, config->KEY >= 0); \ } while (0) #define GET_INT(KEY) \ do { \ if (config_dict_get_int(dict, #KEY, &config->KEY) < 0) { \ return -1; \ } \ } while (0) #define GET_WSTR(KEY) \ do { \ if (config_dict_get_wstr(dict, #KEY, config, &config->KEY) < 0) { \ return -1; \ } \ CHECK_VALUE(#KEY, config->KEY != NULL); \ } while (0) #define GET_WSTR_OPT(KEY) \ do { \ if (config_dict_get_wstr(dict, #KEY, config, &config->KEY) < 0) { \ return -1; \ } \ } while (0) #define GET_WSTRLIST(KEY) \ do { \ if (config_dict_get_wstrlist(dict, #KEY, config, &config->KEY) < 0) { \ return -1; \ } \ } while (0) GET_UINT(_config_init); CHECK_VALUE("_config_init", config->_config_init == _PyConfig_INIT_COMPAT || config->_config_init == _PyConfig_INIT_PYTHON || config->_config_init == _PyConfig_INIT_ISOLATED); GET_UINT(isolated); GET_UINT(use_environment); GET_UINT(dev_mode); GET_UINT(install_signal_handlers); GET_UINT(use_hash_seed); if (config_dict_get_ulong(dict, "hash_seed", &config->hash_seed) < 0) { return -1; } CHECK_VALUE("hash_seed", config->hash_seed <= MAX_HASH_SEED); GET_UINT(faulthandler); GET_UINT(tracemalloc); GET_UINT(perf_profiling); GET_UINT(import_time); GET_UINT(code_debug_ranges); GET_UINT(show_ref_count); GET_UINT(dump_refs); GET_UINT(malloc_stats); GET_WSTR(filesystem_encoding); GET_WSTR(filesystem_errors); GET_WSTR_OPT(pycache_prefix); GET_UINT(parse_argv); GET_WSTRLIST(orig_argv); GET_WSTRLIST(argv); GET_WSTRLIST(xoptions); GET_WSTRLIST(warnoptions); GET_UINT(site_import); GET_UINT(bytes_warning); GET_UINT(warn_default_encoding); GET_UINT(inspect); GET_UINT(interactive); GET_UINT(optimization_level); GET_UINT(parser_debug); GET_UINT(write_bytecode); GET_UINT(verbose); GET_UINT(quiet); GET_UINT(user_site_directory); GET_UINT(configure_c_stdio); GET_UINT(buffered_stdio); GET_WSTR(stdio_encoding); GET_WSTR(stdio_errors); #ifdef MS_WINDOWS GET_UINT(legacy_windows_stdio); #endif GET_WSTR(check_hash_pycs_mode); GET_UINT(pathconfig_warnings); GET_WSTR(program_name); GET_WSTR_OPT(pythonpath_env); GET_WSTR_OPT(home); GET_WSTR(platlibdir); // Path configuration output GET_UINT(module_search_paths_set); GET_WSTRLIST(module_search_paths); GET_WSTR_OPT(stdlib_dir); GET_WSTR_OPT(executable); GET_WSTR_OPT(base_executable); GET_WSTR_OPT(prefix); GET_WSTR_OPT(base_prefix); GET_WSTR_OPT(exec_prefix); GET_WSTR_OPT(base_exec_prefix); GET_UINT(skip_source_first_line); GET_WSTR_OPT(run_command); GET_WSTR_OPT(run_module); GET_WSTR_OPT(run_filename); GET_UINT(_install_importlib); GET_UINT(_init_main); GET_UINT(use_frozen_modules); GET_UINT(safe_path); GET_UINT(_is_python_build); GET_INT(int_max_str_digits); #undef CHECK_VALUE #undef GET_UINT #undef GET_INT #undef GET_WSTR #undef GET_WSTR_OPT return 0; } static const char* config_get_env(const PyConfig *config, const char *name) { return _Py_GetEnv(config->use_environment, name); } /* Get a copy of the environment variable as wchar_t*. Return 0 on success, but *dest can be NULL. Return -1 on memory allocation failure. Return -2 on decoding error. */ static PyStatus config_get_env_dup(PyConfig *config, wchar_t **dest, wchar_t *wname, char *name, const char *decode_err_msg) { assert(*dest == NULL); assert(config->use_environment >= 0); if (!config->use_environment) { *dest = NULL; return _PyStatus_OK(); } #ifdef MS_WINDOWS const wchar_t *var = _wgetenv(wname); if (!var || var[0] == '\0') { *dest = NULL; return _PyStatus_OK(); } return PyConfig_SetString(config, dest, var); #else const char *var = getenv(name); if (!var || var[0] == '\0') { *dest = NULL; return _PyStatus_OK(); } return config_set_bytes_string(config, dest, var, decode_err_msg); #endif } #define CONFIG_GET_ENV_DUP(CONFIG, DEST, WNAME, NAME) \ config_get_env_dup(CONFIG, DEST, WNAME, NAME, "cannot decode " NAME) static void config_get_global_vars(PyConfig *config) { _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS if (config->_config_init != _PyConfig_INIT_COMPAT) { /* Python and Isolated configuration ignore global variables */ return; } #define COPY_FLAG(ATTR, VALUE) \ if (config->ATTR == -1) { \ config->ATTR = VALUE; \ } #define COPY_NOT_FLAG(ATTR, VALUE) \ if (config->ATTR == -1) { \ config->ATTR = !(VALUE); \ } COPY_FLAG(isolated, Py_IsolatedFlag); COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag); COPY_FLAG(bytes_warning, Py_BytesWarningFlag); COPY_FLAG(inspect, Py_InspectFlag); COPY_FLAG(interactive, Py_InteractiveFlag); COPY_FLAG(optimization_level, Py_OptimizeFlag); COPY_FLAG(parser_debug, Py_DebugFlag); COPY_FLAG(verbose, Py_VerboseFlag); COPY_FLAG(quiet, Py_QuietFlag); #ifdef MS_WINDOWS COPY_FLAG(legacy_windows_stdio, Py_LegacyWindowsStdioFlag); #endif COPY_NOT_FLAG(pathconfig_warnings, Py_FrozenFlag); COPY_NOT_FLAG(buffered_stdio, Py_UnbufferedStdioFlag); COPY_NOT_FLAG(site_import, Py_NoSiteFlag); COPY_NOT_FLAG(write_bytecode, Py_DontWriteBytecodeFlag); COPY_NOT_FLAG(user_site_directory, Py_NoUserSiteDirectory); #undef COPY_FLAG #undef COPY_NOT_FLAG _Py_COMP_DIAG_POP } /* Set Py_xxx global configuration variables from 'config' configuration. */ static void config_set_global_vars(const PyConfig *config) { _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS #define COPY_FLAG(ATTR, VAR) \ if (config->ATTR != -1) { \ VAR = config->ATTR; \ } #define COPY_NOT_FLAG(ATTR, VAR) \ if (config->ATTR != -1) { \ VAR = !config->ATTR; \ } COPY_FLAG(isolated, Py_IsolatedFlag); COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag); COPY_FLAG(bytes_warning, Py_BytesWarningFlag); COPY_FLAG(inspect, Py_InspectFlag); COPY_FLAG(interactive, Py_InteractiveFlag); COPY_FLAG(optimization_level, Py_OptimizeFlag); COPY_FLAG(parser_debug, Py_DebugFlag); COPY_FLAG(verbose, Py_VerboseFlag); COPY_FLAG(quiet, Py_QuietFlag); #ifdef MS_WINDOWS COPY_FLAG(legacy_windows_stdio, Py_LegacyWindowsStdioFlag); #endif COPY_NOT_FLAG(pathconfig_warnings, Py_FrozenFlag); COPY_NOT_FLAG(buffered_stdio, Py_UnbufferedStdioFlag); COPY_NOT_FLAG(site_import, Py_NoSiteFlag); COPY_NOT_FLAG(write_bytecode, Py_DontWriteBytecodeFlag); COPY_NOT_FLAG(user_site_directory, Py_NoUserSiteDirectory); /* Random or non-zero hash seed */ Py_HashRandomizationFlag = (config->use_hash_seed == 0 || config->hash_seed != 0); #undef COPY_FLAG #undef COPY_NOT_FLAG _Py_COMP_DIAG_POP } static const wchar_t* config_get_xoption(const PyConfig *config, wchar_t *name) { return _Py_get_xoption(&config->xoptions, name); } static const wchar_t* config_get_xoption_value(const PyConfig *config, wchar_t *name) { const wchar_t *xoption = config_get_xoption(config, name); if (xoption == NULL) { return NULL; } const wchar_t *sep = wcschr(xoption, L'='); return sep ? sep + 1 : L""; } static PyStatus config_init_hash_seed(PyConfig *config) { static_assert(sizeof(_Py_HashSecret_t) == sizeof(_Py_HashSecret.uc), "_Py_HashSecret_t has wrong size"); const char *seed_text = config_get_env(config, "PYTHONHASHSEED"); /* Convert a text seed to a numeric one */ if (seed_text && strcmp(seed_text, "random") != 0) { const char *endptr = seed_text; unsigned long seed; errno = 0; seed = strtoul(seed_text, (char **)&endptr, 10); if (*endptr != '\0' || seed > MAX_HASH_SEED || (errno == ERANGE && seed == ULONG_MAX)) { return _PyStatus_ERR("PYTHONHASHSEED must be \"random\" " "or an integer in range [0; 4294967295]"); } /* Use a specific hash */ config->use_hash_seed = 1; config->hash_seed = seed; } else { /* Use a random hash */ config->use_hash_seed = 0; config->hash_seed = 0; } return _PyStatus_OK(); } static int config_wstr_to_int(const wchar_t *wstr, int *result) { const wchar_t *endptr = wstr; errno = 0; long value = wcstol(wstr, (wchar_t **)&endptr, 10); if (*endptr != '\0' || errno == ERANGE) { return -1; } if (value < INT_MIN || value > INT_MAX) { return -1; } *result = (int)value; return 0; } static PyStatus config_read_env_vars(PyConfig *config) { PyStatus status; int use_env = config->use_environment; /* Get environment variables */ _Py_get_env_flag(use_env, &config->parser_debug, "PYTHONDEBUG"); _Py_get_env_flag(use_env, &config->verbose, "PYTHONVERBOSE"); _Py_get_env_flag(use_env, &config->optimization_level, "PYTHONOPTIMIZE"); _Py_get_env_flag(use_env, &config->inspect, "PYTHONINSPECT"); int dont_write_bytecode = 0; _Py_get_env_flag(use_env, &dont_write_bytecode, "PYTHONDONTWRITEBYTECODE"); if (dont_write_bytecode) { config->write_bytecode = 0; } int no_user_site_directory = 0; _Py_get_env_flag(use_env, &no_user_site_directory, "PYTHONNOUSERSITE"); if (no_user_site_directory) { config->user_site_directory = 0; } int unbuffered_stdio = 0; _Py_get_env_flag(use_env, &unbuffered_stdio, "PYTHONUNBUFFERED"); if (unbuffered_stdio) { config->buffered_stdio = 0; } #ifdef MS_WINDOWS _Py_get_env_flag(use_env, &config->legacy_windows_stdio, "PYTHONLEGACYWINDOWSSTDIO"); #endif if (config_get_env(config, "PYTHONDUMPREFS")) { config->dump_refs = 1; } if (config_get_env(config, "PYTHONMALLOCSTATS")) { config->malloc_stats = 1; } if (config->dump_refs_file == NULL) { status = CONFIG_GET_ENV_DUP(config, &config->dump_refs_file, L"PYTHONDUMPREFSFILE", "PYTHONDUMPREFSFILE"); if (_PyStatus_EXCEPTION(status)) { return status; } } if (config->pythonpath_env == NULL) { status = CONFIG_GET_ENV_DUP(config, &config->pythonpath_env, L"PYTHONPATH", "PYTHONPATH"); if (_PyStatus_EXCEPTION(status)) { return status; } } if(config->platlibdir == NULL) { status = CONFIG_GET_ENV_DUP(config, &config->platlibdir, L"PYTHONPLATLIBDIR", "PYTHONPLATLIBDIR"); if (_PyStatus_EXCEPTION(status)) { return status; } } if (config->use_hash_seed < 0) { status = config_init_hash_seed(config); if (_PyStatus_EXCEPTION(status)) { return status; } } if (config_get_env(config, "PYTHONSAFEPATH")) { config->safe_path = 1; } return _PyStatus_OK(); } static PyStatus config_init_perf_profiling(PyConfig *config) { int active = 0; const char *env = config_get_env(config, "PYTHONPERFSUPPORT"); if (env) { if (_Py_str_to_int(env, &active) != 0) { active = 0; } if (active) { config->perf_profiling = 1; } } const wchar_t *xoption = config_get_xoption(config, L"perf"); if (xoption) { config->perf_profiling = 1; } return _PyStatus_OK(); } static PyStatus config_init_tracemalloc(PyConfig *config) { int nframe; int valid; const char *env = config_get_env(config, "PYTHONTRACEMALLOC"); if (env) { if (!_Py_str_to_int(env, &nframe)) { valid = (nframe >= 0); } else { valid = 0; } if (!valid) { return _PyStatus_ERR("PYTHONTRACEMALLOC: invalid number of frames"); } config->tracemalloc = nframe; } const wchar_t *xoption = config_get_xoption(config, L"tracemalloc"); if (xoption) { const wchar_t *sep = wcschr(xoption, L'='); if (sep) { if (!config_wstr_to_int(sep + 1, &nframe)) { valid = (nframe >= 0); } else { valid = 0; } if (!valid) { return _PyStatus_ERR("-X tracemalloc=NFRAME: " "invalid number of frames"); } } else { /* -X tracemalloc behaves as -X tracemalloc=1 */ nframe = 1; } config->tracemalloc = nframe; } return _PyStatus_OK(); } static PyStatus config_init_int_max_str_digits(PyConfig *config) { int maxdigits; const char *env = config_get_env(config, "PYTHONINTMAXSTRDIGITS"); if (env) { bool valid = 0; if (!_Py_str_to_int(env, &maxdigits)) { valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)); } if (!valid) { #define STRINGIFY(VAL) _STRINGIFY(VAL) #define _STRINGIFY(VAL) #VAL return _PyStatus_ERR( "PYTHONINTMAXSTRDIGITS: invalid limit; must be >= " STRINGIFY(_PY_LONG_MAX_STR_DIGITS_THRESHOLD) " or 0 for unlimited."); } config->int_max_str_digits = maxdigits; } const wchar_t *xoption = config_get_xoption(config, L"int_max_str_digits"); if (xoption) { const wchar_t *sep = wcschr(xoption, L'='); bool valid = 0; if (sep) { if (!config_wstr_to_int(sep + 1, &maxdigits)) { valid = ((maxdigits == 0) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)); } } if (!valid) { return _PyStatus_ERR( "-X int_max_str_digits: invalid limit; must be >= " STRINGIFY(_PY_LONG_MAX_STR_DIGITS_THRESHOLD) " or 0 for unlimited."); #undef _STRINGIFY #undef STRINGIFY } config->int_max_str_digits = maxdigits; } if (config->int_max_str_digits < 0) { config->int_max_str_digits = _PY_LONG_DEFAULT_MAX_STR_DIGITS; } return _PyStatus_OK(); } static PyStatus config_init_pycache_prefix(PyConfig *config) { assert(config->pycache_prefix == NULL); const wchar_t *xoption = config_get_xoption(config, L"pycache_prefix"); if (xoption) { const wchar_t *sep = wcschr(xoption, L'='); if (sep && wcslen(sep) > 1) { config->pycache_prefix = _PyMem_RawWcsdup(sep + 1); if (config->pycache_prefix == NULL) { return _PyStatus_NO_MEMORY(); } } else { // PYTHONPYCACHEPREFIX env var ignored // if "-X pycache_prefix=" option is used config->pycache_prefix = NULL; } return _PyStatus_OK(); } return CONFIG_GET_ENV_DUP(config, &config->pycache_prefix, L"PYTHONPYCACHEPREFIX", "PYTHONPYCACHEPREFIX"); } static PyStatus config_read_complex_options(PyConfig *config) { /* More complex options configured by env var and -X option */ if (config->faulthandler < 0) { if (config_get_env(config, "PYTHONFAULTHANDLER") || config_get_xoption(config, L"faulthandler")) { config->faulthandler = 1; } } if (config_get_env(config, "PYTHONPROFILEIMPORTTIME") || config_get_xoption(config, L"importtime")) { config->import_time = 1; } if (config_get_env(config, "PYTHONNODEBUGRANGES") || config_get_xoption(config, L"no_debug_ranges")) { config->code_debug_ranges = 0; } PyStatus status; if (config->tracemalloc < 0) { status = config_init_tracemalloc(config); if (_PyStatus_EXCEPTION(status)) { return status; } } if (config->perf_profiling < 0) { status = config_init_perf_profiling(config); if (_PyStatus_EXCEPTION(status)) { return status; } } if (config->int_max_str_digits < 0) { status = config_init_int_max_str_digits(config); if (_PyStatus_EXCEPTION(status)) { return status; } } if (config->pycache_prefix == NULL) { status = config_init_pycache_prefix(config); if (_PyStatus_EXCEPTION(status)) { return status; } } return _PyStatus_OK(); } static const wchar_t * config_get_stdio_errors(const PyPreConfig *preconfig) { if (preconfig->utf8_mode) { /* UTF-8 Mode uses UTF-8/surrogateescape */ return L"surrogateescape"; } #ifndef MS_WINDOWS const char *loc = setlocale(LC_CTYPE, NULL); if (loc != NULL) { /* surrogateescape is the default in the legacy C and POSIX locales */ if (strcmp(loc, "C") == 0 || strcmp(loc, "POSIX") == 0) { return L"surrogateescape"; } #ifdef PY_COERCE_C_LOCALE /* surrogateescape is the default in locale coercion target locales */ if (_Py_IsLocaleCoercionTarget(loc)) { return L"surrogateescape"; } #endif } return L"strict"; #else /* On Windows, always use surrogateescape by default */ return L"surrogateescape"; #endif } // See also config_get_fs_encoding() static PyStatus config_get_locale_encoding(PyConfig *config, const PyPreConfig *preconfig, wchar_t **locale_encoding) { wchar_t *encoding; if (preconfig->utf8_mode) { encoding = _PyMem_RawWcsdup(L"utf-8"); } else { encoding = _Py_GetLocaleEncoding(); } if (encoding == NULL) { return _PyStatus_NO_MEMORY(); } PyStatus status = PyConfig_SetString(config, locale_encoding, encoding); PyMem_RawFree(encoding); return status; } static PyStatus config_init_stdio_encoding(PyConfig *config, const PyPreConfig *preconfig) { PyStatus status; // Exit if encoding and errors are defined if (config->stdio_encoding != NULL && config->stdio_errors != NULL) { return _PyStatus_OK(); } /* PYTHONIOENCODING environment variable */ const char *opt = config_get_env(config, "PYTHONIOENCODING"); if (opt) { char *pythonioencoding = _PyMem_RawStrdup(opt); if (pythonioencoding == NULL) { return _PyStatus_NO_MEMORY(); } char *errors = strchr(pythonioencoding, ':'); if (errors) { *errors = '\0'; errors++; if (!errors[0]) { errors = NULL; } } /* Does PYTHONIOENCODING contain an encoding? */ if (pythonioencoding[0]) { if (config->stdio_encoding == NULL) { status = CONFIG_SET_BYTES_STR(config, &config->stdio_encoding, pythonioencoding, "PYTHONIOENCODING environment variable"); if (_PyStatus_EXCEPTION(status)) { PyMem_RawFree(pythonioencoding); return status; } } /* If the encoding is set but not the error handler, use "strict" error handler by default. PYTHONIOENCODING=latin1 behaves as PYTHONIOENCODING=latin1:strict. */ if (!errors) { errors = "strict"; } } if (config->stdio_errors == NULL && errors != NULL) { status = CONFIG_SET_BYTES_STR(config, &config->stdio_errors, errors, "PYTHONIOENCODING environment variable"); if (_PyStatus_EXCEPTION(status)) { PyMem_RawFree(pythonioencoding); return status; } } PyMem_RawFree(pythonioencoding); } /* Choose the default error handler based on the current locale. */ if (config->stdio_encoding == NULL) { status = config_get_locale_encoding(config, preconfig, &config->stdio_encoding); if (_PyStatus_EXCEPTION(status)) { return status; } } if (config->stdio_errors == NULL) { const wchar_t *errors = config_get_stdio_errors(preconfig); assert(errors != NULL); status = PyConfig_SetString(config, &config->stdio_errors, errors); if (_PyStatus_EXCEPTION(status)) { return status; } } return _PyStatus_OK(); } // See also config_get_locale_encoding() static PyStatus config_get_fs_encoding(PyConfig *config, const PyPreConfig *preconfig, wchar_t **fs_encoding) { #ifdef _Py_FORCE_UTF8_FS_ENCODING return PyConfig_SetString(config, fs_encoding, L"utf-8"); #elif defined(MS_WINDOWS) const wchar_t *encoding; if (preconfig->legacy_windows_fs_encoding) { // Legacy Windows filesystem encoding: mbcs/replace encoding = L"mbcs"; } else { // Windows defaults to utf-8/surrogatepass (PEP 529) encoding = L"utf-8"; } return PyConfig_SetString(config, fs_encoding, encoding); #else // !MS_WINDOWS if (preconfig->utf8_mode) { return PyConfig_SetString(config, fs_encoding, L"utf-8"); } if (_Py_GetForceASCII()) { return PyConfig_SetString(config, fs_encoding, L"ascii"); } return config_get_locale_encoding(config, preconfig, fs_encoding); #endif // !MS_WINDOWS } static PyStatus config_init_fs_encoding(PyConfig *config, const PyPreConfig *preconfig) { PyStatus status; if (config->filesystem_encoding == NULL) { status = config_get_fs_encoding(config, preconfig, &config->filesystem_encoding); if (_PyStatus_EXCEPTION(status)) { return status; } } if (config->filesystem_errors == NULL) { const wchar_t *errors; #ifdef MS_WINDOWS if (preconfig->legacy_windows_fs_encoding) { errors = L"replace"; } else { errors = L"surrogatepass"; } #else errors = L"surrogateescape"; #endif status = PyConfig_SetString(config, &config->filesystem_errors, errors); if (_PyStatus_EXCEPTION(status)) { return status; } } return _PyStatus_OK(); } static PyStatus config_init_import(PyConfig *config, int compute_path_config) { PyStatus status; status = _PyConfig_InitPathConfig(config, compute_path_config); if (_PyStatus_EXCEPTION(status)) { return status; } /* -X frozen_modules=[on|off] */ const wchar_t *value = config_get_xoption_value(config, L"frozen_modules"); if (value == NULL) { } else if (wcscmp(value, L"on") == 0) { config->use_frozen_modules = 1; } else if (wcscmp(value, L"off") == 0) { config->use_frozen_modules = 0; } else if (wcslen(value) == 0) { // "-X frozen_modules" and "-X frozen_modules=" both imply "on". config->use_frozen_modules = 1; } else { return PyStatus_Error("bad value for option -X frozen_modules " "(expected \"on\" or \"off\")"); } assert(config->use_frozen_modules >= 0); return _PyStatus_OK(); } PyStatus _PyConfig_InitImportConfig(PyConfig *config) { return config_init_import(config, 1); } static PyStatus config_read(PyConfig *config, int compute_path_config) { PyStatus status; const PyPreConfig *preconfig = &_PyRuntime.preconfig; if (config->use_environment) { status = config_read_env_vars(config); if (_PyStatus_EXCEPTION(status)) { return status; } } /* -X options */ if (config_get_xoption(config, L"showrefcount")) { config->show_ref_count = 1; } #ifdef Py_STATS if (config_get_xoption(config, L"pystats")) { _py_stats = &_py_stats_struct; } #endif status = config_read_complex_options(config); if (_PyStatus_EXCEPTION(status)) { return status; } if (config->_install_importlib) { status = config_init_import(config, compute_path_config); if (_PyStatus_EXCEPTION(status)) { return status; } } /* default values */ if (config->dev_mode) { if (config->faulthandler < 0) { config->faulthandler = 1; } } if (config->faulthandler < 0) { config->faulthandler = 0; } if (config->tracemalloc < 0) { config->tracemalloc = 0; } if (config->perf_profiling < 0) { config->perf_profiling = 0; } if (config->use_hash_seed < 0) { config->use_hash_seed = 0; config->hash_seed = 0; } if (config->filesystem_encoding == NULL || config->filesystem_errors == NULL) { status = config_init_fs_encoding(config, preconfig); if (_PyStatus_EXCEPTION(status)) { return status; } } status = config_init_stdio_encoding(config, preconfig); if (_PyStatus_EXCEPTION(status)) { return status; } if (config->argv.length < 1) { /* Ensure at least one (empty) argument is seen */ status = PyWideStringList_Append(&config->argv, L""); if (_PyStatus_EXCEPTION(status)) { return status; } } if (config->check_hash_pycs_mode == NULL) { status = PyConfig_SetString(config, &config->check_hash_pycs_mode, L"default"); if (_PyStatus_EXCEPTION(status)) { return status; } } if (config->configure_c_stdio < 0) { config->configure_c_stdio = 1; } // Only parse arguments once. if (config->parse_argv == 1) { config->parse_argv = 2; } return _PyStatus_OK(); } static void config_init_stdio(const PyConfig *config) { #if defined(MS_WINDOWS) || defined(__CYGWIN__) /* don't translate newlines (\r\n <=> \n) */ _setmode(fileno(stdin), O_BINARY); _setmode(fileno(stdout), O_BINARY); _setmode(fileno(stderr), O_BINARY); #endif if (!config->buffered_stdio) { #ifdef HAVE_SETVBUF setvbuf(stdin, (char *)NULL, _IONBF, BUFSIZ); setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ); setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ); #else /* !HAVE_SETVBUF */ setbuf(stdin, (char *)NULL); setbuf(stdout, (char *)NULL); setbuf(stderr, (char *)NULL); #endif /* !HAVE_SETVBUF */ } else if (config->interactive) { #ifdef MS_WINDOWS /* Doesn't have to have line-buffered -- use unbuffered */ /* Any set[v]buf(stdin, ...) screws up Tkinter :-( */ setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ); #else /* !MS_WINDOWS */ #ifdef HAVE_SETVBUF setvbuf(stdin, (char *)NULL, _IOLBF, BUFSIZ); setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ); #endif /* HAVE_SETVBUF */ #endif /* !MS_WINDOWS */ /* Leave stderr alone - it should be unbuffered anyway. */ } } /* Write the configuration: - set Py_xxx global configuration variables - initialize C standard streams (stdin, stdout, stderr) */ PyStatus _PyConfig_Write(const PyConfig *config, _PyRuntimeState *runtime) { config_set_global_vars(config); if (config->configure_c_stdio) { config_init_stdio(config); } /* Write the new pre-configuration into _PyRuntime */ PyPreConfig *preconfig = &runtime->preconfig; preconfig->isolated = config->isolated; preconfig->use_environment = config->use_environment; preconfig->dev_mode = config->dev_mode; if (_Py_SetArgcArgv(config->orig_argv.length, config->orig_argv.items) < 0) { return _PyStatus_NO_MEMORY(); } return _PyStatus_OK(); } /* --- PyConfig command line parser -------------------------- */ static void config_usage(int error, const wchar_t* program) { FILE *f = error ? stderr : stdout; fprintf(f, usage_line, program); if (error) fprintf(f, "Try `python -h' for more information.\n"); else { fputs(usage_help, f); } } static void config_envvars_usage(void) { printf(usage_envvars, (wint_t)DELIM, (wint_t)DELIM, PYTHONHOMEHELP); } static void config_xoptions_usage(void) { puts(usage_xoptions); } static void config_complete_usage(const wchar_t* program) { config_usage(0, program); puts("\n"); config_envvars_usage(); puts("\n"); config_xoptions_usage(); } /* Parse the command line arguments */ static PyStatus config_parse_cmdline(PyConfig *config, PyWideStringList *warnoptions, Py_ssize_t *opt_index) { PyStatus status; const PyWideStringList *argv = &config->argv; int print_version = 0; const wchar_t* program = config->program_name; if (!program && argv->length >= 1) { program = argv->items[0]; } _PyOS_ResetGetOpt(); do { int longindex = -1; int c = _PyOS_GetOpt(argv->length, argv->items, &longindex); if (c == EOF) { break; } if (c == 'c') { if (config->run_command == NULL) { /* -c is the last option; following arguments that look like options are left for the command to interpret. */ size_t len = wcslen(_PyOS_optarg) + 1 + 1; wchar_t *command = PyMem_RawMalloc(sizeof(wchar_t) * len); if (command == NULL) { return _PyStatus_NO_MEMORY(); } memcpy(command, _PyOS_optarg, (len - 2) * sizeof(wchar_t)); command[len - 2] = '\n'; command[len - 1] = 0; config->run_command = command; } break; } if (c == 'm') { /* -m is the last option; following arguments that look like options are left for the module to interpret. */ if (config->run_module == NULL) { config->run_module = _PyMem_RawWcsdup(_PyOS_optarg); if (config->run_module == NULL) { return _PyStatus_NO_MEMORY(); } } break; } switch (c) { // Integers represent long options, see Python/getopt.c case 0: // check-hash-based-pycs if (wcscmp(_PyOS_optarg, L"always") == 0 || wcscmp(_PyOS_optarg, L"never") == 0 || wcscmp(_PyOS_optarg, L"default") == 0) { status = PyConfig_SetString(config, &config->check_hash_pycs_mode, _PyOS_optarg); if (_PyStatus_EXCEPTION(status)) { return status; } } else { fprintf(stderr, "--check-hash-based-pycs must be one of " "'default', 'always', or 'never'\n"); config_usage(1, program); return _PyStatus_EXIT(2); } break; case 1: // help-all config_complete_usage(program); return _PyStatus_EXIT(0); case 2: // help-env config_envvars_usage(); return _PyStatus_EXIT(0); case 3: // help-xoptions config_xoptions_usage(); return _PyStatus_EXIT(0); case 'b': config->bytes_warning++; break; case 'd': config->parser_debug++; break; case 'i': config->inspect++; config->interactive++; break; case 'E': case 'I': case 'X': /* option handled by _PyPreCmdline_Read() */ break; /* case 'J': reserved for Jython */ case 'O': config->optimization_level++; break; case 'P': config->safe_path = 1; break; case 'B': config->write_bytecode = 0; break; case 's': config->user_site_directory = 0; break; case 'S': config->site_import = 0; break; case 't': /* ignored for backwards compatibility */ break; case 'u': config->buffered_stdio = 0; break; case 'v': config->verbose++; break; case 'x': config->skip_source_first_line = 1; break; case 'h': case '?': config_usage(0, program); return _PyStatus_EXIT(0); case 'V': print_version++; break; case 'W': status = PyWideStringList_Append(warnoptions, _PyOS_optarg); if (_PyStatus_EXCEPTION(status)) { return status; } break; case 'q': config->quiet++; break; case 'R': config->use_hash_seed = 0; break; /* This space reserved for other options */ default: /* unknown argument: parsing failed */ config_usage(1, program); return _PyStatus_EXIT(2); } } while (1); if (print_version) { printf("Python %s\n", (print_version >= 2) ? Py_GetVersion() : PY_VERSION); return _PyStatus_EXIT(0); } if (config->run_command == NULL && config->run_module == NULL && _PyOS_optind < argv->length && wcscmp(argv->items[_PyOS_optind], L"-") != 0 && config->run_filename == NULL) { config->run_filename = _PyMem_RawWcsdup(argv->items[_PyOS_optind]); if (config->run_filename == NULL) { return _PyStatus_NO_MEMORY(); } } if (config->run_command != NULL || config->run_module != NULL) { /* Backup _PyOS_optind */ _PyOS_optind--; } *opt_index = _PyOS_optind; return _PyStatus_OK(); } #ifdef MS_WINDOWS # define WCSTOK wcstok_s #else # define WCSTOK wcstok #endif /* Get warning options from PYTHONWARNINGS environment variable. */ static PyStatus config_init_env_warnoptions(PyConfig *config, PyWideStringList *warnoptions) { PyStatus status; /* CONFIG_GET_ENV_DUP requires dest to be initialized to NULL */ wchar_t *env = NULL; status = CONFIG_GET_ENV_DUP(config, &env, L"PYTHONWARNINGS", "PYTHONWARNINGS"); if (_PyStatus_EXCEPTION(status)) { return status; } /* env var is not set or is empty */ if (env == NULL) { return _PyStatus_OK(); } wchar_t *warning, *context = NULL; for (warning = WCSTOK(env, L",", &context); warning != NULL; warning = WCSTOK(NULL, L",", &context)) { status = PyWideStringList_Append(warnoptions, warning); if (_PyStatus_EXCEPTION(status)) { PyMem_RawFree(env); return status; } } PyMem_RawFree(env); return _PyStatus_OK(); } static PyStatus warnoptions_append(PyConfig *config, PyWideStringList *options, const wchar_t *option) { /* config_init_warnoptions() add existing config warnoptions at the end: ensure that the new option is not already present in this list to prevent change the options order when config_init_warnoptions() is called twice. */ if (_PyWideStringList_Find(&config->warnoptions, option)) { /* Already present: do nothing */ return _PyStatus_OK(); } if (_PyWideStringList_Find(options, option)) { /* Already present: do nothing */ return _PyStatus_OK(); } return PyWideStringList_Append(options, option); } static PyStatus warnoptions_extend(PyConfig *config, PyWideStringList *options, const PyWideStringList *options2) { const Py_ssize_t len = options2->length; wchar_t *const *items = options2->items; for (Py_ssize_t i = 0; i < len; i++) { PyStatus status = warnoptions_append(config, options, items[i]); if (_PyStatus_EXCEPTION(status)) { return status; } } return _PyStatus_OK(); } static PyStatus config_init_warnoptions(PyConfig *config, const PyWideStringList *cmdline_warnoptions, const PyWideStringList *env_warnoptions, const PyWideStringList *sys_warnoptions) { PyStatus status; PyWideStringList options = _PyWideStringList_INIT; /* Priority of warnings options, lowest to highest: * * - any implicit filters added by _warnings.c/warnings.py * - PyConfig.dev_mode: "default" filter * - PYTHONWARNINGS environment variable * - '-W' command line options * - PyConfig.bytes_warning ('-b' and '-bb' command line options): * "default::BytesWarning" or "error::BytesWarning" filter * - early PySys_AddWarnOption() calls * - PyConfig.warnoptions * * PyConfig.warnoptions is copied to sys.warnoptions. Since the warnings * module works on the basis of "the most recently added filter will be * checked first", we add the lowest precedence entries first so that later * entries override them. */ if (config->dev_mode) { status = warnoptions_append(config, &options, L"default"); if (_PyStatus_EXCEPTION(status)) { goto error; } } status = warnoptions_extend(config, &options, env_warnoptions); if (_PyStatus_EXCEPTION(status)) { goto error; } status = warnoptions_extend(config, &options, cmdline_warnoptions); if (_PyStatus_EXCEPTION(status)) { goto error; } /* If the bytes_warning_flag isn't set, bytesobject.c and bytearrayobject.c * don't even try to emit a warning, so we skip setting the filter in that * case. */ if (config->bytes_warning) { const wchar_t *filter; if (config->bytes_warning> 1) { filter = L"error::BytesWarning"; } else { filter = L"default::BytesWarning"; } status = warnoptions_append(config, &options, filter); if (_PyStatus_EXCEPTION(status)) { goto error; } } status = warnoptions_extend(config, &options, sys_warnoptions); if (_PyStatus_EXCEPTION(status)) { goto error; } /* Always add all PyConfig.warnoptions options */ status = _PyWideStringList_Extend(&options, &config->warnoptions); if (_PyStatus_EXCEPTION(status)) { goto error; } _PyWideStringList_Clear(&config->warnoptions); config->warnoptions = options; return _PyStatus_OK(); error: _PyWideStringList_Clear(&options); return status; } static PyStatus config_update_argv(PyConfig *config, Py_ssize_t opt_index) { const PyWideStringList *cmdline_argv = &config->argv; PyWideStringList config_argv = _PyWideStringList_INIT; /* Copy argv to be able to modify it (to force -c/-m) */ if (cmdline_argv->length <= opt_index) { /* Ensure at least one (empty) argument is seen */ PyStatus status = PyWideStringList_Append(&config_argv, L""); if (_PyStatus_EXCEPTION(status)) { return status; } } else { PyWideStringList slice; slice.length = cmdline_argv->length - opt_index; slice.items = &cmdline_argv->items[opt_index]; if (_PyWideStringList_Copy(&config_argv, &slice) < 0) { return _PyStatus_NO_MEMORY(); } } assert(config_argv.length >= 1); wchar_t *arg0 = NULL; if (config->run_command != NULL) { /* Force sys.argv[0] = '-c' */ arg0 = L"-c"; } else if (config->run_module != NULL) { /* Force sys.argv[0] = '-m'*/ arg0 = L"-m"; } if (arg0 != NULL) { arg0 = _PyMem_RawWcsdup(arg0); if (arg0 == NULL) { _PyWideStringList_Clear(&config_argv); return _PyStatus_NO_MEMORY(); } PyMem_RawFree(config_argv.items[0]); config_argv.items[0] = arg0; } _PyWideStringList_Clear(&config->argv); config->argv = config_argv; return _PyStatus_OK(); } static PyStatus core_read_precmdline(PyConfig *config, _PyPreCmdline *precmdline) { PyStatus status; if (config->parse_argv == 1) { if (_PyWideStringList_Copy(&precmdline->argv, &config->argv) < 0) { return _PyStatus_NO_MEMORY(); } } PyPreConfig preconfig; status = _PyPreConfig_InitFromPreConfig(&preconfig, &_PyRuntime.preconfig); if (_PyStatus_EXCEPTION(status)) { return status; } _PyPreConfig_GetConfig(&preconfig, config); status = _PyPreCmdline_Read(precmdline, &preconfig); if (_PyStatus_EXCEPTION(status)) { return status; } status = _PyPreCmdline_SetConfig(precmdline, config); if (_PyStatus_EXCEPTION(status)) { return status; } return _PyStatus_OK(); } /* Get run_filename absolute path */ static PyStatus config_run_filename_abspath(PyConfig *config) { if (!config->run_filename) { return _PyStatus_OK(); } #ifndef MS_WINDOWS if (_Py_isabs(config->run_filename)) { /* path is already absolute */ return _PyStatus_OK(); } #endif wchar_t *abs_filename; if (_Py_abspath(config->run_filename, &abs_filename) < 0) { /* failed to get the absolute path of the command line filename: ignore the error, keep the relative path */ return _PyStatus_OK(); } if (abs_filename == NULL) { return _PyStatus_NO_MEMORY(); } PyMem_RawFree(config->run_filename); config->run_filename = abs_filename; return _PyStatus_OK(); } static PyStatus config_read_cmdline(PyConfig *config) { PyStatus status; PyWideStringList cmdline_warnoptions = _PyWideStringList_INIT; PyWideStringList env_warnoptions = _PyWideStringList_INIT; PyWideStringList sys_warnoptions = _PyWideStringList_INIT; if (config->parse_argv < 0) { config->parse_argv = 1; } if (config->parse_argv == 1) { Py_ssize_t opt_index; status = config_parse_cmdline(config, &cmdline_warnoptions, &opt_index); if (_PyStatus_EXCEPTION(status)) { goto done; } status = config_run_filename_abspath(config); if (_PyStatus_EXCEPTION(status)) { goto done; } status = config_update_argv(config, opt_index); if (_PyStatus_EXCEPTION(status)) { goto done; } } else { status = config_run_filename_abspath(config); if (_PyStatus_EXCEPTION(status)) { goto done; } } if (config->use_environment) { status = config_init_env_warnoptions(config, &env_warnoptions); if (_PyStatus_EXCEPTION(status)) { goto done; } } /* Handle early PySys_AddWarnOption() calls */ status = _PySys_ReadPreinitWarnOptions(&sys_warnoptions); if (_PyStatus_EXCEPTION(status)) { goto done; } status = config_init_warnoptions(config, &cmdline_warnoptions, &env_warnoptions, &sys_warnoptions); if (_PyStatus_EXCEPTION(status)) { goto done; } status = _PyStatus_OK(); done: _PyWideStringList_Clear(&cmdline_warnoptions); _PyWideStringList_Clear(&env_warnoptions); _PyWideStringList_Clear(&sys_warnoptions); return status; } PyStatus _PyConfig_SetPyArgv(PyConfig *config, const _PyArgv *args) { PyStatus status = _Py_PreInitializeFromConfig(config, args); if (_PyStatus_EXCEPTION(status)) { return status; } return _PyArgv_AsWstrList(args, &config->argv); } /* Set config.argv: decode argv using Py_DecodeLocale(). Pre-initialize Python if needed to ensure that encodings are properly configured. */ PyStatus PyConfig_SetBytesArgv(PyConfig *config, Py_ssize_t argc, char * const *argv) { _PyArgv args = { .argc = argc, .use_bytes_argv = 1, .bytes_argv = argv, .wchar_argv = NULL}; return _PyConfig_SetPyArgv(config, &args); } PyStatus PyConfig_SetArgv(PyConfig *config, Py_ssize_t argc, wchar_t * const *argv) { _PyArgv args = { .argc = argc, .use_bytes_argv = 0, .bytes_argv = NULL, .wchar_argv = argv}; return _PyConfig_SetPyArgv(config, &args); } PyStatus PyConfig_SetWideStringList(PyConfig *config, PyWideStringList *list, Py_ssize_t length, wchar_t **items) { PyStatus status = _Py_PreInitializeFromConfig(config, NULL); if (_PyStatus_EXCEPTION(status)) { return status; } PyWideStringList list2 = {.length = length, .items = items}; if (_PyWideStringList_Copy(list, &list2) < 0) { return _PyStatus_NO_MEMORY(); } return _PyStatus_OK(); } /* Read the configuration into PyConfig from: * Command line arguments * Environment variables * Py_xxx global configuration variables The only side effects are to modify config and to call _Py_SetArgcArgv(). */ PyStatus _PyConfig_Read(PyConfig *config, int compute_path_config) { PyStatus status; status = _Py_PreInitializeFromConfig(config, NULL); if (_PyStatus_EXCEPTION(status)) { return status; } config_get_global_vars(config); if (config->orig_argv.length == 0 && !(config->argv.length == 1 && wcscmp(config->argv.items[0], L"") == 0)) { if (_PyWideStringList_Copy(&config->orig_argv, &config->argv) < 0) { return _PyStatus_NO_MEMORY(); } } _PyPreCmdline precmdline = _PyPreCmdline_INIT; status = core_read_precmdline(config, &precmdline); if (_PyStatus_EXCEPTION(status)) { goto done; } assert(config->isolated >= 0); if (config->isolated) { config->safe_path = 1; config->use_environment = 0; config->user_site_directory = 0; } status = config_read_cmdline(config); if (_PyStatus_EXCEPTION(status)) { goto done; } /* Handle early PySys_AddXOption() calls */ status = _PySys_ReadPreinitXOptions(config); if (_PyStatus_EXCEPTION(status)) { goto done; } status = config_read(config, compute_path_config); if (_PyStatus_EXCEPTION(status)) { goto done; } assert(config_check_consistency(config)); status = _PyStatus_OK(); done: _PyPreCmdline_Clear(&precmdline); return status; } PyStatus PyConfig_Read(PyConfig *config) { return _PyConfig_Read(config, 0); } PyObject* _Py_GetConfigsAsDict(void) { PyObject *result = NULL; PyObject *dict = NULL; result = PyDict_New(); if (result == NULL) { goto error; } /* global result */ dict = _Py_GetGlobalVariablesAsDict(); if (dict == NULL) { goto error; } if (PyDict_SetItemString(result, "global_config", dict) < 0) { goto error; } Py_CLEAR(dict); /* pre config */ PyInterpreterState *interp = _PyInterpreterState_GET(); const PyPreConfig *pre_config = &interp->runtime->preconfig; dict = _PyPreConfig_AsDict(pre_config); if (dict == NULL) { goto error; } if (PyDict_SetItemString(result, "pre_config", dict) < 0) { goto error; } Py_CLEAR(dict); /* core config */ const PyConfig *config = _PyInterpreterState_GetConfig(interp); dict = _PyConfig_AsDict(config); if (dict == NULL) { goto error; } if (PyDict_SetItemString(result, "config", dict) < 0) { goto error; } Py_CLEAR(dict); return result; error: Py_XDECREF(result); Py_XDECREF(dict); return NULL; } static void init_dump_ascii_wstr(const wchar_t *str) { if (str == NULL) { PySys_WriteStderr("(not set)"); return; } PySys_WriteStderr("'"); for (; *str != L'\0'; str++) { unsigned int ch = (unsigned int)*str; if (ch == L'\'') { PySys_WriteStderr("\\'"); } else if (0x20 <= ch && ch < 0x7f) { PySys_WriteStderr("%c", ch); } else if (ch <= 0xff) { PySys_WriteStderr("\\x%02x", ch); } #if SIZEOF_WCHAR_T > 2 else if (ch > 0xffff) { PySys_WriteStderr("\\U%08x", ch); } #endif else { PySys_WriteStderr("\\u%04x", ch); } } PySys_WriteStderr("'"); } /* Dump the Python path configuration into sys.stderr */ void _Py_DumpPathConfig(PyThreadState *tstate) { PyObject *exc = _PyErr_GetRaisedException(tstate); PySys_WriteStderr("Python path configuration:\n"); #define DUMP_CONFIG(NAME, FIELD) \ do { \ PySys_WriteStderr(" " NAME " = "); \ init_dump_ascii_wstr(config->FIELD); \ PySys_WriteStderr("\n"); \ } while (0) const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp); DUMP_CONFIG("PYTHONHOME", home); DUMP_CONFIG("PYTHONPATH", pythonpath_env); DUMP_CONFIG("program name", program_name); PySys_WriteStderr(" isolated = %i\n", config->isolated); PySys_WriteStderr(" environment = %i\n", config->use_environment); PySys_WriteStderr(" user site = %i\n", config->user_site_directory); PySys_WriteStderr(" safe_path = %i\n", config->safe_path); PySys_WriteStderr(" import site = %i\n", config->site_import); PySys_WriteStderr(" is in build tree = %i\n", config->_is_python_build); DUMP_CONFIG("stdlib dir", stdlib_dir); #undef DUMP_CONFIG #define DUMP_SYS(NAME) \ do { \ obj = PySys_GetObject(#NAME); \ PySys_FormatStderr(" sys.%s = ", #NAME); \ if (obj != NULL) { \ PySys_FormatStderr("%A", obj); \ } \ else { \ PySys_WriteStderr("(not set)"); \ } \ PySys_FormatStderr("\n"); \ } while (0) PyObject *obj; DUMP_SYS(_base_executable); DUMP_SYS(base_prefix); DUMP_SYS(base_exec_prefix); DUMP_SYS(platlibdir); DUMP_SYS(executable); DUMP_SYS(prefix); DUMP_SYS(exec_prefix); #undef DUMP_SYS PyObject *sys_path = PySys_GetObject("path"); /* borrowed reference */ if (sys_path != NULL && PyList_Check(sys_path)) { PySys_WriteStderr(" sys.path = [\n"); Py_ssize_t len = PyList_GET_SIZE(sys_path); for (Py_ssize_t i=0; i < len; i++) { PyObject *path = PyList_GET_ITEM(sys_path, i); PySys_FormatStderr(" %A,\n", path); } PySys_WriteStderr(" ]\n"); } _PyErr_SetRaisedException(tstate, exc); } ================================================ FILE: InstruMenTation.c ================================================ #include "Python.h" #include "pycore_call.h" #include "pycore_frame.h" #include "pycore_interp.h" #include "pycore_long.h" #include "pycore_namespace.h" #include "pycore_object.h" #include "pycore_opcode.h" #include "pycore_pyerrors.h" #include "pycore_pystate.h" /* Uncomment this to dump debugging output when assertions fail */ // #define INSTRUMENT_DEBUG 1 PyObject _PyInstrumentation_DISABLE = { .ob_refcnt = _Py_IMMORTAL_REFCNT, .ob_type = &PyBaseObject_Type }; PyObject _PyInstrumentation_MISSING = { .ob_refcnt = _Py_IMMORTAL_REFCNT, .ob_type = &PyBaseObject_Type }; static const int8_t EVENT_FOR_OPCODE[256] = { [RETURN_CONST] = PY_MONITORING_EVENT_PY_RETURN, [INSTRUMENTED_RETURN_CONST] = PY_MONITORING_EVENT_PY_RETURN, [RETURN_VALUE] = PY_MONITORING_EVENT_PY_RETURN, [INSTRUMENTED_RETURN_VALUE] = PY_MONITORING_EVENT_PY_RETURN, [CALL] = PY_MONITORING_EVENT_CALL, [INSTRUMENTED_CALL] = PY_MONITORING_EVENT_CALL, [CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL, [INSTRUMENTED_CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL, [LOAD_SUPER_ATTR] = PY_MONITORING_EVENT_CALL, [INSTRUMENTED_LOAD_SUPER_ATTR] = PY_MONITORING_EVENT_CALL, [RESUME] = -1, [YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD, [INSTRUMENTED_YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD, [JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP, [JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP, [POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH, [POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH, [POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH, [POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH, [INSTRUMENTED_JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP, [INSTRUMENTED_JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP, [INSTRUMENTED_POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH, [INSTRUMENTED_POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH, [INSTRUMENTED_POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH, [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH, [FOR_ITER] = PY_MONITORING_EVENT_BRANCH, [INSTRUMENTED_FOR_ITER] = PY_MONITORING_EVENT_BRANCH, [END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION, [INSTRUMENTED_END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION, [END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION, [INSTRUMENTED_END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION, }; static const uint8_t DE_INSTRUMENT[256] = { [INSTRUMENTED_RESUME] = RESUME, [INSTRUMENTED_RETURN_VALUE] = RETURN_VALUE, [INSTRUMENTED_RETURN_CONST] = RETURN_CONST, [INSTRUMENTED_CALL] = CALL, [INSTRUMENTED_CALL_FUNCTION_EX] = CALL_FUNCTION_EX, [INSTRUMENTED_YIELD_VALUE] = YIELD_VALUE, [INSTRUMENTED_JUMP_FORWARD] = JUMP_FORWARD, [INSTRUMENTED_JUMP_BACKWARD] = JUMP_BACKWARD, [INSTRUMENTED_POP_JUMP_IF_FALSE] = POP_JUMP_IF_FALSE, [INSTRUMENTED_POP_JUMP_IF_TRUE] = POP_JUMP_IF_TRUE, [INSTRUMENTED_POP_JUMP_IF_NONE] = POP_JUMP_IF_NONE, [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = POP_JUMP_IF_NOT_NONE, [INSTRUMENTED_FOR_ITER] = FOR_ITER, [INSTRUMENTED_END_FOR] = END_FOR, [INSTRUMENTED_END_SEND] = END_SEND, [INSTRUMENTED_LOAD_SUPER_ATTR] = LOAD_SUPER_ATTR, }; static const uint8_t INSTRUMENTED_OPCODES[256] = { [RETURN_CONST] = INSTRUMENTED_RETURN_CONST, [INSTRUMENTED_RETURN_CONST] = INSTRUMENTED_RETURN_CONST, [RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE, [INSTRUMENTED_RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE, [CALL] = INSTRUMENTED_CALL, [INSTRUMENTED_CALL] = INSTRUMENTED_CALL, [CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX, [INSTRUMENTED_CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX, [YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE, [INSTRUMENTED_YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE, [RESUME] = INSTRUMENTED_RESUME, [INSTRUMENTED_RESUME] = INSTRUMENTED_RESUME, [JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD, [INSTRUMENTED_JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD, [JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD, [INSTRUMENTED_JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD, [POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE, [INSTRUMENTED_POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE, [POP_JUMP_IF_TRUE] = INSTRUMENTED_POP_JUMP_IF_TRUE, [INSTRUMENTED_POP_JUMP_IF_TRUE] = INSTRUMENTED_POP_JUMP_IF_TRUE, [POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE, [INSTRUMENTED_POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE, [POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE, [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE, [END_FOR] = INSTRUMENTED_END_FOR, [INSTRUMENTED_END_FOR] = INSTRUMENTED_END_FOR, [END_SEND] = INSTRUMENTED_END_SEND, [INSTRUMENTED_END_SEND] = INSTRUMENTED_END_SEND, [FOR_ITER] = INSTRUMENTED_FOR_ITER, [INSTRUMENTED_FOR_ITER] = INSTRUMENTED_FOR_ITER, [LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR, [INSTRUMENTED_LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR, [INSTRUMENTED_LINE] = INSTRUMENTED_LINE, [INSTRUMENTED_INSTRUCTION] = INSTRUMENTED_INSTRUCTION, }; static inline bool opcode_has_event(int opcode) { return ( opcode < INSTRUMENTED_LINE && INSTRUMENTED_OPCODES[opcode] > 0 ); } static inline bool is_instrumented(int opcode) { assert(opcode != 0); assert(opcode != RESERVED); return opcode >= MIN_INSTRUMENTED_OPCODE; } #ifndef NDEBUG static inline bool monitors_equals(_Py_Monitors a, _Py_Monitors b) { for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { if (a.tools[i] != b.tools[i]) { return false; } } return true; } #endif static inline _Py_Monitors monitors_sub(_Py_Monitors a, _Py_Monitors b) { _Py_Monitors res; for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { res.tools[i] = a.tools[i] & ~b.tools[i]; } return res; } #ifndef NDEBUG static inline _Py_Monitors monitors_and(_Py_Monitors a, _Py_Monitors b) { _Py_Monitors res; for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { res.tools[i] = a.tools[i] & b.tools[i]; } return res; } #endif static inline _Py_Monitors monitors_or(_Py_Monitors a, _Py_Monitors b) { _Py_Monitors res; for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { res.tools[i] = a.tools[i] | b.tools[i]; } return res; } static inline bool monitors_are_empty(_Py_Monitors m) { for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { if (m.tools[i]) { return false; } } return true; } static inline bool multiple_tools(_Py_Monitors *m) { for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { if (_Py_popcount32(m->tools[i]) > 1) { return true; } } return false; } static inline _PyMonitoringEventSet get_events(_Py_Monitors *m, int tool_id) { _PyMonitoringEventSet result = 0; for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) { if ((m->tools[e] >> tool_id) & 1) { result |= (1 << e); } } return result; } /* Line delta. * 8 bit value. * if line_delta == -128: * line = None # represented as -1 * elif line_delta == -127: * line = PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT)); * else: * line = first_line + (offset >> OFFSET_SHIFT) + line_delta; */ #define NO_LINE -128 #define COMPUTED_LINE -127 #define OFFSET_SHIFT 4 static int8_t compute_line_delta(PyCodeObject *code, int offset, int line) { if (line < 0) { return NO_LINE; } int delta = line - code->co_firstlineno - (offset >> OFFSET_SHIFT); if (delta <= INT8_MAX && delta > COMPUTED_LINE) { return delta; } return COMPUTED_LINE; } static int compute_line(PyCodeObject *code, int offset, int8_t line_delta) { if (line_delta > COMPUTED_LINE) { return code->co_firstlineno + (offset >> OFFSET_SHIFT) + line_delta; } if (line_delta == NO_LINE) { return -1; } assert(line_delta == COMPUTED_LINE); /* Look it up */ return PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT)); } int _PyInstruction_GetLength(PyCodeObject *code, int offset) { int opcode = _PyCode_CODE(code)[offset].op.code; assert(opcode != 0); assert(opcode != RESERVED); if (opcode == INSTRUMENTED_LINE) { opcode = code->_co_monitoring->lines[offset].original_opcode; } if (opcode == INSTRUMENTED_INSTRUCTION) { opcode = code->_co_monitoring->per_instruction_opcodes[offset]; } int deinstrumented = DE_INSTRUMENT[opcode]; if (deinstrumented) { opcode = deinstrumented; } else { opcode = _PyOpcode_Deopt[opcode]; } assert(opcode != 0); assert(!is_instrumented(opcode)); assert(opcode == _PyOpcode_Deopt[opcode]); return 1 + _PyOpcode_Caches[opcode]; } #ifdef INSTRUMENT_DEBUG static void dump_instrumentation_data_tools(PyCodeObject *code, uint8_t *tools, int i, FILE*out) { if (tools == NULL) { fprintf(out, "tools = NULL"); } else { fprintf(out, "tools = %d", tools[i]); } } static void dump_instrumentation_data_lines(PyCodeObject *code, _PyCoLineInstrumentationData *lines, int i, FILE*out) { if (lines == NULL) { fprintf(out, ", lines = NULL"); } else if (lines[i].original_opcode == 0) { fprintf(out, ", lines = {original_opcode = No LINE (0), line_delta = %d)", lines[i].line_delta); } else { fprintf(out, ", lines = {original_opcode = %s, line_delta = %d)", _PyOpcode_OpName[lines[i].original_opcode], lines[i].line_delta); } } static void dump_instrumentation_data_line_tools(PyCodeObject *code, uint8_t *line_tools, int i, FILE*out) { if (line_tools == NULL) { fprintf(out, ", line_tools = NULL"); } else { fprintf(out, ", line_tools = %d", line_tools[i]); } } static void dump_instrumentation_data_per_instruction(PyCodeObject *code, _PyCoMonitoringData *data, int i, FILE*out) { if (data->per_instruction_opcodes == NULL) { fprintf(out, ", per-inst opcode = NULL"); } else { fprintf(out, ", per-inst opcode = %s", _PyOpcode_OpName[data->per_instruction_opcodes[i]]); } if (data->per_instruction_tools == NULL) { fprintf(out, ", per-inst tools = NULL"); } else { fprintf(out, ", per-inst tools = %d", data->per_instruction_tools[i]); } } static void dump_monitors(const char *prefix, _Py_Monitors monitors, FILE*out) { fprintf(out, "%s monitors:\n", prefix); for (int event = 0; event < PY_MONITORING_UNGROUPED_EVENTS; event++) { fprintf(out, " Event %d: Tools %x\n", event, monitors.tools[event]); } } /* Like _Py_GetBaseOpcode but without asserts. * Does its best to give the right answer, but won't abort * if something is wrong */ static int get_base_opcode_best_attempt(PyCodeObject *code, int offset) { int opcode = _Py_OPCODE(_PyCode_CODE(code)[offset]); if (INSTRUMENTED_OPCODES[opcode] != opcode) { /* Not instrumented */ return _PyOpcode_Deopt[opcode] == 0 ? opcode : _PyOpcode_Deopt[opcode]; } if (opcode == INSTRUMENTED_INSTRUCTION) { if (code->_co_monitoring->per_instruction_opcodes[offset] == 0) { return opcode; } opcode = code->_co_monitoring->per_instruction_opcodes[offset]; } if (opcode == INSTRUMENTED_LINE) { if (code->_co_monitoring->lines[offset].original_opcode == 0) { return opcode; } opcode = code->_co_monitoring->lines[offset].original_opcode; } int deinstrumented = DE_INSTRUMENT[opcode]; if (deinstrumented) { return deinstrumented; } if (_PyOpcode_Deopt[opcode] == 0) { return opcode; } return _PyOpcode_Deopt[opcode]; } /* No error checking -- Don't use this for anything but experimental debugging */ static void dump_instrumentation_data(PyCodeObject *code, int star, FILE*out) { _PyCoMonitoringData *data = code->_co_monitoring; fprintf(out, "\n"); PyObject_Print(code->co_name, out, Py_PRINT_RAW); fprintf(out, "\n"); if (data == NULL) { fprintf(out, "NULL\n"); return; } dump_monitors("Global", PyInterpreterState_Get()->monitors, out); dump_monitors("Code", data->local_monitors, out); dump_monitors("Active", data->active_monitors, out); int code_len = (int)Py_SIZE(code); bool starred = false; for (int i = 0; i < code_len; i += _PyInstruction_GetLength(code, i)) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; int opcode = instr->op.code; if (i == star) { fprintf(out, "** "); starred = true; } fprintf(out, "Offset: %d, line: %d %s: ", i, PyCode_Addr2Line(code, i*2), _PyOpcode_OpName[opcode]); dump_instrumentation_data_tools(code, data->tools, i, out); dump_instrumentation_data_lines(code, data->lines, i, out); dump_instrumentation_data_line_tools(code, data->line_tools, i, out); dump_instrumentation_data_per_instruction(code, data, i, out); fprintf(out, "\n"); ; } if (!starred && star >= 0) { fprintf(out, "Error offset not at valid instruction offset: %d\n", star); fprintf(out, " "); dump_instrumentation_data_tools(code, data->tools, star, out); dump_instrumentation_data_lines(code, data->lines, star, out); dump_instrumentation_data_line_tools(code, data->line_tools, star, out); dump_instrumentation_data_per_instruction(code, data, star, out); fprintf(out, "\n"); } } #define CHECK(test) do { \ if (!(test)) { \ dump_instrumentation_data(code, i, stderr); \ } \ assert(test); \ } while (0) static bool valid_opcode(int opcode) { if (opcode > 0 && opcode != RESERVED && opcode < 255 && _PyOpcode_OpName[opcode] && _PyOpcode_OpName[opcode][0] != '<') { return true; } return false; } static void sanity_check_instrumentation(PyCodeObject *code) { _PyCoMonitoringData *data = code->_co_monitoring; if (data == NULL) { return; } _Py_Monitors active_monitors = PyInterpreterState_Get()->monitors; if (code->_co_monitoring) { _Py_Monitors local_monitors = code->_co_monitoring->local_monitors; active_monitors = monitors_or(active_monitors, local_monitors); } assert(monitors_equals( code->_co_monitoring->active_monitors, active_monitors) ); int code_len = (int)Py_SIZE(code); for (int i = 0; i < code_len;) { int opcode = _PyCode_CODE(code)[i].op.code; int base_opcode = _Py_GetBaseOpcode(code, i); CHECK(valid_opcode(opcode)); CHECK(valid_opcode(base_opcode)); if (opcode == INSTRUMENTED_INSTRUCTION) { opcode = data->per_instruction_opcodes[i]; if (!is_instrumented(opcode)) { CHECK(_PyOpcode_Deopt[opcode] == opcode); } if (data->per_instruction_tools) { uint8_t tools = active_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION]; CHECK((tools & data->per_instruction_tools[i]) == data->per_instruction_tools[i]); } } if (opcode == INSTRUMENTED_LINE) { CHECK(data->lines); CHECK(valid_opcode(data->lines[i].original_opcode)); opcode = data->lines[i].original_opcode; CHECK(opcode != END_FOR); CHECK(opcode != RESUME); CHECK(opcode != INSTRUMENTED_RESUME); if (!is_instrumented(opcode)) { CHECK(_PyOpcode_Deopt[opcode] == opcode); } CHECK(opcode != INSTRUMENTED_LINE); } else if (data->lines && !is_instrumented(opcode)) { CHECK(data->lines[i].original_opcode == 0 || data->lines[i].original_opcode == base_opcode || DE_INSTRUMENT[data->lines[i].original_opcode] == base_opcode); } if (is_instrumented(opcode)) { CHECK(DE_INSTRUMENT[opcode] == base_opcode); int event = EVENT_FOR_OPCODE[DE_INSTRUMENT[opcode]]; if (event < 0) { /* RESUME fixup */ event = _PyCode_CODE(code)[i].op.arg; } CHECK(active_monitors.tools[event] != 0); } if (data->lines && base_opcode != END_FOR) { int line1 = compute_line(code, i, data->lines[i].line_delta); int line2 = PyCode_Addr2Line(code, i*sizeof(_Py_CODEUNIT)); CHECK(line1 == line2); } CHECK(valid_opcode(opcode)); if (data->tools) { uint8_t local_tools = data->tools[i]; if (opcode_has_event(base_opcode)) { int event = EVENT_FOR_OPCODE[base_opcode]; if (event == -1) { /* RESUME fixup */ event = _PyCode_CODE(code)[i].op.arg; } CHECK((active_monitors.tools[event] & local_tools) == local_tools); } else { CHECK(local_tools == 0xff); } } i += _PyInstruction_GetLength(code, i); assert(i <= code_len); } } #else #define CHECK(test) assert(test) #endif /* Get the underlying opcode, stripping instrumentation */ int _Py_GetBaseOpcode(PyCodeObject *code, int i) { int opcode = _PyCode_CODE(code)[i].op.code; if (opcode == INSTRUMENTED_LINE) { opcode = code->_co_monitoring->lines[i].original_opcode; } if (opcode == INSTRUMENTED_INSTRUCTION) { opcode = code->_co_monitoring->per_instruction_opcodes[i]; } CHECK(opcode != INSTRUMENTED_INSTRUCTION); CHECK(opcode != INSTRUMENTED_LINE); int deinstrumented = DE_INSTRUMENT[opcode]; if (deinstrumented) { return deinstrumented; } return _PyOpcode_Deopt[opcode]; } static void de_instrument(PyCodeObject *code, int i, int event) { assert(event != PY_MONITORING_EVENT_INSTRUCTION); assert(event != PY_MONITORING_EVENT_LINE); _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; uint8_t *opcode_ptr = &instr->op.code; int opcode = *opcode_ptr; if (opcode == INSTRUMENTED_LINE) { opcode_ptr = &code->_co_monitoring->lines[i].original_opcode; opcode = *opcode_ptr; } if (opcode == INSTRUMENTED_INSTRUCTION) { opcode_ptr = &code->_co_monitoring->per_instruction_opcodes[i]; opcode = *opcode_ptr; } int deinstrumented = DE_INSTRUMENT[opcode]; if (deinstrumented == 0) { return; } CHECK(_PyOpcode_Deopt[deinstrumented] == deinstrumented); *opcode_ptr = deinstrumented; if (_PyOpcode_Caches[deinstrumented]) { instr[1].cache = adaptive_counter_warmup(); } } static void de_instrument_line(PyCodeObject *code, int i) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; uint8_t *opcode_ptr = &instr->op.code; int opcode =*opcode_ptr; if (opcode != INSTRUMENTED_LINE) { return; } _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; int original_opcode = lines->original_opcode; CHECK(original_opcode != 0); CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]); *opcode_ptr = instr->op.code = original_opcode; if (_PyOpcode_Caches[original_opcode]) { instr[1].cache = adaptive_counter_warmup(); } assert(*opcode_ptr != INSTRUMENTED_LINE); assert(instr->op.code != INSTRUMENTED_LINE); } static void de_instrument_per_instruction(PyCodeObject *code, int i) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; uint8_t *opcode_ptr = &instr->op.code; int opcode =*opcode_ptr; if (opcode == INSTRUMENTED_LINE) { opcode_ptr = &code->_co_monitoring->lines[i].original_opcode; opcode = *opcode_ptr; } if (opcode != INSTRUMENTED_INSTRUCTION) { return; } int original_opcode = code->_co_monitoring->per_instruction_opcodes[i]; CHECK(original_opcode != 0); CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]); instr->op.code = original_opcode; if (_PyOpcode_Caches[original_opcode]) { instr[1].cache = adaptive_counter_warmup(); } assert(instr->op.code != INSTRUMENTED_INSTRUCTION); /* Keep things clean for sanity check */ code->_co_monitoring->per_instruction_opcodes[i] = 0; } static void instrument(PyCodeObject *code, int i) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; uint8_t *opcode_ptr = &instr->op.code; int opcode =*opcode_ptr; if (opcode == INSTRUMENTED_LINE) { _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; opcode_ptr = &lines->original_opcode; opcode = *opcode_ptr; } if (opcode == INSTRUMENTED_INSTRUCTION) { opcode_ptr = &code->_co_monitoring->per_instruction_opcodes[i]; opcode = *opcode_ptr; CHECK(!is_instrumented(opcode)); CHECK(opcode == _PyOpcode_Deopt[opcode]); } CHECK(opcode != 0); if (!is_instrumented(opcode)) { int deopt = _PyOpcode_Deopt[opcode]; int instrumented = INSTRUMENTED_OPCODES[deopt]; assert(instrumented); *opcode_ptr = instrumented; if (_PyOpcode_Caches[deopt]) { instr[1].cache = adaptive_counter_warmup(); } } } static void instrument_line(PyCodeObject *code, int i) { uint8_t *opcode_ptr = &_PyCode_CODE(code)[i].op.code; int opcode =*opcode_ptr; if (opcode == INSTRUMENTED_LINE) { return; } _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; lines->original_opcode = _PyOpcode_Deopt[opcode]; CHECK(lines->original_opcode > 0); *opcode_ptr = INSTRUMENTED_LINE; } static void instrument_per_instruction(PyCodeObject *code, int i) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; uint8_t *opcode_ptr = &instr->op.code; int opcode =*opcode_ptr; if (opcode == INSTRUMENTED_LINE) { _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; opcode_ptr = &lines->original_opcode; opcode = *opcode_ptr; } if (opcode == INSTRUMENTED_INSTRUCTION) { return; } CHECK(opcode != 0); if (is_instrumented(opcode)) { code->_co_monitoring->per_instruction_opcodes[i] = opcode; } else { assert(opcode != 0); assert(_PyOpcode_Deopt[opcode] != 0); assert(_PyOpcode_Deopt[opcode] != RESUME); code->_co_monitoring->per_instruction_opcodes[i] = _PyOpcode_Deopt[opcode]; } assert(code->_co_monitoring->per_instruction_opcodes[i] > 0); *opcode_ptr = INSTRUMENTED_INSTRUCTION; } #ifndef NDEBUG static bool instruction_has_event(PyCodeObject *code, int offset) { _Py_CODEUNIT instr = _PyCode_CODE(code)[offset]; int opcode = instr.op.code; if (opcode == INSTRUMENTED_LINE) { opcode = code->_co_monitoring->lines[offset].original_opcode; } if (opcode == INSTRUMENTED_INSTRUCTION) { opcode = code->_co_monitoring->per_instruction_opcodes[offset]; } return opcode_has_event(opcode); } #endif static void remove_tools(PyCodeObject * code, int offset, int event, int tools) { assert(event != PY_MONITORING_EVENT_LINE); assert(event != PY_MONITORING_EVENT_INSTRUCTION); assert(event < PY_MONITORING_INSTRUMENTED_EVENTS); assert(instruction_has_event(code, offset)); _PyCoMonitoringData *monitoring = code->_co_monitoring; if (monitoring && monitoring->tools) { monitoring->tools[offset] &= ~tools; if (monitoring->tools[offset] == 0) { de_instrument(code, offset, event); } } else { /* Single tool */ uint8_t single_tool = code->_co_monitoring->active_monitors.tools[event]; assert(_Py_popcount32(single_tool) <= 1); if (((single_tool & tools) == single_tool)) { de_instrument(code, offset, event); } } } #ifndef NDEBUG static bool tools_is_subset_for_event(PyCodeObject * code, int event, int tools) { int global_tools = PyInterpreterState_Get()->monitors.tools[event]; int local_tools = code->_co_monitoring->local_monitors.tools[event]; return tools == ((global_tools | local_tools) & tools); } #endif static void remove_line_tools(PyCodeObject * code, int offset, int tools) { assert(code->_co_monitoring); if (code->_co_monitoring->line_tools) { uint8_t *toolsptr = &code->_co_monitoring->line_tools[offset]; *toolsptr &= ~tools; if (*toolsptr == 0 ) { de_instrument_line(code, offset); } } else { /* Single tool */ uint8_t single_tool = code->_co_monitoring->active_monitors.tools[PY_MONITORING_EVENT_LINE]; assert(_Py_popcount32(single_tool) <= 1); if (((single_tool & tools) == single_tool)) { de_instrument_line(code, offset); } } } static void add_tools(PyCodeObject * code, int offset, int event, int tools) { assert(event != PY_MONITORING_EVENT_LINE); assert(event != PY_MONITORING_EVENT_INSTRUCTION); assert(event < PY_MONITORING_INSTRUMENTED_EVENTS); assert(code->_co_monitoring); if (code->_co_monitoring && code->_co_monitoring->tools ) { code->_co_monitoring->tools[offset] |= tools; } else { /* Single tool */ assert(_Py_popcount32(tools) == 1); assert(tools_is_subset_for_event(code, event, tools)); } instrument(code, offset); } static void add_line_tools(PyCodeObject * code, int offset, int tools) { assert(tools_is_subset_for_event(code, PY_MONITORING_EVENT_LINE, tools)); assert(code->_co_monitoring); if (code->_co_monitoring->line_tools) { code->_co_monitoring->line_tools[offset] |= tools; } else { /* Single tool */ assert(_Py_popcount32(tools) == 1); } instrument_line(code, offset); } static void add_per_instruction_tools(PyCodeObject * code, int offset, int tools) { assert(tools_is_subset_for_event(code, PY_MONITORING_EVENT_INSTRUCTION, tools)); assert(code->_co_monitoring); if (code->_co_monitoring->per_instruction_tools) { code->_co_monitoring->per_instruction_tools[offset] |= tools; } else { /* Single tool */ assert(_Py_popcount32(tools) == 1); } instrument_per_instruction(code, offset); } static void remove_per_instruction_tools(PyCodeObject * code, int offset, int tools) { assert(code->_co_monitoring); if (code->_co_monitoring->per_instruction_tools) { uint8_t *toolsptr = &code->_co_monitoring->per_instruction_tools[offset]; *toolsptr &= ~tools; if (*toolsptr == 0) { de_instrument_per_instruction(code, offset); } } else { /* Single tool */ uint8_t single_tool = code->_co_monitoring->active_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION]; assert(_Py_popcount32(single_tool) <= 1); if (((single_tool & tools) == single_tool)) { de_instrument_per_instruction(code, offset); } } } /* Return 1 if DISABLE returned, -1 if error, 0 otherwise */ static int call_one_instrument( PyInterpreterState *interp, PyThreadState *tstate, PyObject **args, Py_ssize_t nargsf, int8_t tool, int event) { assert(0 <= tool && tool < 8); assert(tstate->tracing == 0); PyObject *instrument = interp->monitoring_callables[tool][event]; if (instrument == NULL) { return 0; } int old_what = tstate->what_event; tstate->what_event = event; tstate->tracing++; PyObject *res = _PyObject_VectorcallTstate(tstate, instrument, args, nargsf, NULL); tstate->tracing--; tstate->what_event = old_what; if (res == NULL) { return -1; } Py_DECREF(res); return (res == &_PyInstrumentation_DISABLE); } static const int8_t MOST_SIGNIFICANT_BITS[16] = { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, }; /* We could use _Py_bit_length here, but that is designed for larger (32/64) * bit ints, and can perform relatively poorly on platforms without the * necessary intrinsics. */ static inline int most_significant_bit(uint8_t bits) { assert(bits != 0); if (bits > 15) { return MOST_SIGNIFICANT_BITS[bits>>4]+4; } return MOST_SIGNIFICANT_BITS[bits]; } static bool is_version_up_to_date(PyCodeObject *code, PyInterpreterState *interp) { return interp->monitoring_version == code->_co_instrumentation_version; } #ifndef NDEBUG static bool instrumentation_cross_checks(PyInterpreterState *interp, PyCodeObject *code) { _Py_Monitors expected = monitors_or( interp->monitors, code->_co_monitoring->local_monitors); return monitors_equals(code->_co_monitoring->active_monitors, expected); } #endif static inline uint8_t get_tools_for_instruction(PyCodeObject * code, int i, int event) { uint8_t tools; assert(event != PY_MONITORING_EVENT_LINE); assert(event != PY_MONITORING_EVENT_INSTRUCTION); assert(instrumentation_cross_checks(PyThreadState_GET()->interp, code)); _PyCoMonitoringData *monitoring = code->_co_monitoring; if (event >= PY_MONITORING_UNGROUPED_EVENTS) { assert(event == PY_MONITORING_EVENT_C_RAISE || event == PY_MONITORING_EVENT_C_RETURN); event = PY_MONITORING_EVENT_CALL; } if (event < PY_MONITORING_INSTRUMENTED_EVENTS && monitoring->tools) { tools = monitoring->tools[i]; } else { tools = code->_co_monitoring->active_monitors.tools[event]; } CHECK(tools_is_subset_for_event(code, event, tools)); CHECK((tools & code->_co_monitoring->active_monitors.tools[event]) == tools); return tools; } static int call_instrumentation_vector( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, Py_ssize_t nargs, PyObject *args[]) { if (tstate->tracing) { return 0; } assert(!_PyErr_Occurred(tstate)); assert(args[0] == NULL); PyCodeObject *code = frame->f_code; assert(code->_co_instrumentation_version == tstate->interp->monitoring_version); assert(is_version_up_to_date(code, tstate->interp)); assert(instrumentation_cross_checks(tstate->interp, code)); assert(args[1] == NULL); args[1] = (PyObject *)code; int offset = (int)(instr - _PyCode_CODE(code)); /* Offset visible to user should be the offset in bytes, as that is the * convention for APIs involving code offsets. */ int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT); PyObject *offset_obj = PyLong_FromSsize_t(bytes_offset); if (offset_obj == NULL) { return -1; } assert(args[2] == NULL); args[2] = offset_obj; uint8_t tools = get_tools_for_instruction(code, offset, event); Py_ssize_t nargsf = nargs | PY_VECTORCALL_ARGUMENTS_OFFSET; PyObject **callargs = &args[1]; int err = 0; PyInterpreterState *interp = tstate->interp; while (tools) { int tool = most_significant_bit(tools); assert(tool >= 0 && tool < 8); assert(tools & (1 << tool)); tools ^= (1 << tool); int res = call_one_instrument(interp, tstate, callargs, nargsf, tool, event); if (res == 0) { /* Nothing to do */ } else if (res < 0) { /* error */ err = -1; break; } else { /* DISABLE */ remove_tools(code, offset, event, 1 << tool); } } Py_DECREF(offset_obj); return err; } int _Py_call_instrumentation( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) { PyObject *args[3] = { NULL, NULL, NULL }; return call_instrumentation_vector(tstate, event, frame, instr, 2, args); } int _Py_call_instrumentation_arg( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg) { PyObject *args[4] = { NULL, NULL, NULL, arg }; return call_instrumentation_vector(tstate, event, frame, instr, 3, args); } int _Py_call_instrumentation_2args( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1) { PyObject *args[5] = { NULL, NULL, NULL, arg0, arg1 }; return call_instrumentation_vector(tstate, event, frame, instr, 4, args); } _Py_CODEUNIT * _Py_call_instrumentation_jump( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target) { assert(event == PY_MONITORING_EVENT_JUMP || event == PY_MONITORING_EVENT_BRANCH); assert(frame->prev_instr == instr); /* Event should occur after the jump */ frame->prev_instr = target; PyCodeObject *code = frame->f_code; int to = (int)(target - _PyCode_CODE(code)); PyObject *to_obj = PyLong_FromLong(to * (int)sizeof(_Py_CODEUNIT)); if (to_obj == NULL) { return NULL; } PyObject *args[4] = { NULL, NULL, NULL, to_obj }; int err = call_instrumentation_vector(tstate, event, frame, instr, 3, args); Py_DECREF(to_obj); if (err) { return NULL; } if (frame->prev_instr != target) { /* The callback has caused a jump (by setting the line number) */ return frame->prev_instr; } /* Reset prev_instr for INSTRUMENTED_LINE */ frame->prev_instr = instr; return target; } static void call_instrumentation_vector_protected( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, Py_ssize_t nargs, PyObject *args[]) { assert(_PyErr_Occurred(tstate)); PyObject *exc = _PyErr_GetRaisedException(tstate); int err = call_instrumentation_vector(tstate, event, frame, instr, nargs, args); if (err) { Py_XDECREF(exc); } else { _PyErr_SetRaisedException(tstate, exc); } assert(_PyErr_Occurred(tstate)); } void _Py_call_instrumentation_exc0( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) { assert(_PyErr_Occurred(tstate)); PyObject *args[3] = { NULL, NULL, NULL }; call_instrumentation_vector_protected(tstate, event, frame, instr, 2, args); } void _Py_call_instrumentation_exc2( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1) { assert(_PyErr_Occurred(tstate)); PyObject *args[5] = { NULL, NULL, NULL, arg0, arg1 }; call_instrumentation_vector_protected(tstate, event, frame, instr, 4, args); } int _Py_Instrumentation_GetLine(PyCodeObject *code, int index) { _PyCoMonitoringData *monitoring = code->_co_monitoring; assert(monitoring != NULL); assert(monitoring->lines != NULL); assert(index >= code->_co_firsttraceable); assert(index < Py_SIZE(code)); _PyCoLineInstrumentationData *line_data = &monitoring->lines[index]; int8_t line_delta = line_data->line_delta; int line = compute_line(code, index, line_delta); return line; } int _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev) { frame->prev_instr = instr; PyCodeObject *code = frame->f_code; assert(is_version_up_to_date(code, tstate->interp)); assert(instrumentation_cross_checks(tstate->interp, code)); int i = (int)(instr - _PyCode_CODE(code)); _PyCoMonitoringData *monitoring = code->_co_monitoring; _PyCoLineInstrumentationData *line_data = &monitoring->lines[i]; uint8_t original_opcode = line_data->original_opcode; if (tstate->tracing) { goto done; } PyInterpreterState *interp = tstate->interp; int8_t line_delta = line_data->line_delta; int line = compute_line(code, i, line_delta); assert(line >= 0); int prev_index = (int)(prev - _PyCode_CODE(code)); int prev_line = _Py_Instrumentation_GetLine(code, prev_index); if (prev_line == line) { int prev_opcode = _PyCode_CODE(code)[prev_index].op.code; /* RESUME and INSTRUMENTED_RESUME are needed for the operation of * instrumentation, so must never be hidden by an INSTRUMENTED_LINE. */ if (prev_opcode != RESUME && prev_opcode != INSTRUMENTED_RESUME) { goto done; } } uint8_t tools = code->_co_monitoring->line_tools != NULL ? code->_co_monitoring->line_tools[i] : (interp->monitors.tools[PY_MONITORING_EVENT_LINE] | code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_LINE] ); PyObject *line_obj = PyLong_FromSsize_t(line); if (line_obj == NULL) { return -1; } PyObject *args[3] = { NULL, (PyObject *)code, line_obj }; while (tools) { int tool = most_significant_bit(tools); assert(tool >= 0 && tool < 8); assert(tools & (1 << tool)); tools &= ~(1 << tool); int res = call_one_instrument(interp, tstate, &args[1], 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, tool, PY_MONITORING_EVENT_LINE); if (res == 0) { /* Nothing to do */ } else if (res < 0) { /* error */ Py_DECREF(line_obj); return -1; } else { /* DISABLE */ remove_line_tools(code, i, 1 << tool); } } Py_DECREF(line_obj); done: assert(original_opcode != 0); assert(original_opcode < INSTRUMENTED_LINE); assert(_PyOpcode_Deopt[original_opcode] == original_opcode); return original_opcode; } int _Py_call_instrumentation_instruction(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr) { PyCodeObject *code = frame->f_code; assert(is_version_up_to_date(code, tstate->interp)); assert(instrumentation_cross_checks(tstate->interp, code)); int offset = (int)(instr - _PyCode_CODE(code)); _PyCoMonitoringData *instrumentation_data = code->_co_monitoring; assert(instrumentation_data->per_instruction_opcodes); int next_opcode = instrumentation_data->per_instruction_opcodes[offset]; if (tstate->tracing) { return next_opcode; } PyInterpreterState *interp = tstate->interp; uint8_t tools = instrumentation_data->per_instruction_tools != NULL ? instrumentation_data->per_instruction_tools[offset] : (interp->monitors.tools[PY_MONITORING_EVENT_INSTRUCTION] | code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION] ); int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT); PyObject *offset_obj = PyLong_FromSsize_t(bytes_offset); if (offset_obj == NULL) { return -1; } PyObject *args[3] = { NULL, (PyObject *)code, offset_obj }; while (tools) { int tool = most_significant_bit(tools); assert(tool >= 0 && tool < 8); assert(tools & (1 << tool)); tools &= ~(1 << tool); int res = call_one_instrument(interp, tstate, &args[1], 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, tool, PY_MONITORING_EVENT_INSTRUCTION); if (res == 0) { /* Nothing to do */ } else if (res < 0) { /* error */ Py_DECREF(offset_obj); return -1; } else { /* DISABLE */ remove_per_instruction_tools(code, offset, 1 << tool); } } Py_DECREF(offset_obj); assert(next_opcode != 0); return next_opcode; } PyObject * _PyMonitoring_RegisterCallback(int tool_id, int event_id, PyObject *obj) { PyInterpreterState *is = _PyInterpreterState_Get(); assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); assert(0 <= event_id && event_id < PY_MONITORING_EVENTS); PyObject *callback = is->monitoring_callables[tool_id][event_id]; is->monitoring_callables[tool_id][event_id] = Py_XNewRef(obj); return callback; } static void initialize_tools(PyCodeObject *code) { uint8_t* tools = code->_co_monitoring->tools; assert(tools != NULL); int code_len = (int)Py_SIZE(code); for (int i = 0; i < code_len; i++) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; int opcode = instr->op.code; if (opcode == INSTRUMENTED_LINE) { opcode = code->_co_monitoring->lines[i].original_opcode; } bool instrumented = is_instrumented(opcode); if (instrumented) { opcode = DE_INSTRUMENT[opcode]; assert(opcode != 0); } opcode = _PyOpcode_Deopt[opcode]; if (opcode_has_event(opcode)) { if (instrumented) { int8_t event; if (opcode == RESUME) { event = instr->op.arg != 0; } else { event = EVENT_FOR_OPCODE[opcode]; assert(event > 0); } assert(event >= 0); assert(event < PY_MONITORING_INSTRUMENTED_EVENTS); tools[i] = code->_co_monitoring->active_monitors.tools[event]; CHECK(tools[i] != 0); } else { tools[i] = 0; } } #ifdef Py_DEBUG /* Initialize tools for invalid locations to all ones to try to catch errors */ else { tools[i] = 0xff; } for (int j = 1; j <= _PyOpcode_Caches[opcode]; j++) { tools[i+j] = 0xff; } #endif i += _PyOpcode_Caches[opcode]; } } #define NO_LINE -128 static void initialize_lines(PyCodeObject *code) { _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; assert(line_data != NULL); int code_len = (int)Py_SIZE(code); PyCodeAddressRange range; _PyCode_InitAddressRange(code, &range); for (int i = 0; i < code->_co_firsttraceable && i < code_len; i++) { line_data[i].original_opcode = 0; line_data[i].line_delta = -127; } int current_line = -1; for (int i = code->_co_firsttraceable; i < code_len; ) { int opcode = _Py_GetBaseOpcode(code, i); int line = _PyCode_CheckLineNumber(i*(int)sizeof(_Py_CODEUNIT), &range); line_data[i].line_delta = compute_line_delta(code, i, line); int length = _PyInstruction_GetLength(code, i); switch (opcode) { case END_ASYNC_FOR: case END_FOR: case END_SEND: case RESUME: /* END_FOR cannot start a line, as it is skipped by FOR_ITER * END_SEND cannot start a line, as it is skipped by SEND * RESUME must not be instrumented with INSTRUMENT_LINE */ line_data[i].original_opcode = 0; break; default: /* Set original_opcode to the opcode iff the instruction * starts a line, and thus should be instrumented. * This saves having to perform this check every time the * we turn instrumentation on or off, and serves as a sanity * check when debugging. */ if (line != current_line && line >= 0) { line_data[i].original_opcode = opcode; } else { line_data[i].original_opcode = 0; } current_line = line; } for (int j = 1; j < length; j++) { line_data[i+j].original_opcode = 0; line_data[i+j].line_delta = NO_LINE; } i += length; } for (int i = code->_co_firsttraceable; i < code_len; ) { int opcode = _Py_GetBaseOpcode(code, i); int oparg = 0; while (opcode == EXTENDED_ARG) { oparg = (oparg << 8) | _PyCode_CODE(code)[i].op.arg; i++; opcode = _Py_GetBaseOpcode(code, i); } oparg = (oparg << 8) | _PyCode_CODE(code)[i].op.arg; i += _PyInstruction_GetLength(code, i); int target = -1; switch (opcode) { case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: case POP_JUMP_IF_NONE: case POP_JUMP_IF_NOT_NONE: case JUMP_FORWARD: { target = i + oparg; break; } case FOR_ITER: case SEND: { /* Skip over END_FOR/END_SEND */ target = i + oparg + 1; break; } case JUMP_BACKWARD: case JUMP_BACKWARD_NO_INTERRUPT: { target = i - oparg; break; } default: continue; } assert(target >= 0); if (line_data[target].line_delta != NO_LINE) { line_data[target].original_opcode = _Py_GetBaseOpcode(code, target); } } /* Scan exception table */ unsigned char *start = (unsigned char *)PyBytes_AS_STRING(code->co_exceptiontable); unsigned char *end = start + PyBytes_GET_SIZE(code->co_exceptiontable); unsigned char *scan = start; while (scan < end) { int start_offset, size, handler; scan = parse_varint(scan, &start_offset); assert(start_offset >= 0 && start_offset < code_len); scan = parse_varint(scan, &size); assert(size >= 0 && start_offset+size <= code_len); scan = parse_varint(scan, &handler); assert(handler >= 0 && handler < code_len); int depth_and_lasti; scan = parse_varint(scan, &depth_and_lasti); int original_opcode = _Py_GetBaseOpcode(code, handler); /* Skip if not the start of a line. * END_ASYNC_FOR is a bit special as it marks the end of * an `async for` loop, which should not generate its own * line event. */ if (line_data[handler].line_delta != NO_LINE && original_opcode != END_ASYNC_FOR) { line_data[handler].original_opcode = original_opcode; } } } static void initialize_line_tools(PyCodeObject *code, _Py_Monitors *all_events) { uint8_t *line_tools = code->_co_monitoring->line_tools; assert(line_tools != NULL); int code_len = (int)Py_SIZE(code); for (int i = 0; i < code_len; i++) { line_tools[i] = all_events->tools[PY_MONITORING_EVENT_LINE]; } } static int allocate_instrumentation_data(PyCodeObject *code) { if (code->_co_monitoring == NULL) { code->_co_monitoring = PyMem_Malloc(sizeof(_PyCoMonitoringData)); if (code->_co_monitoring == NULL) { PyErr_NoMemory(); return -1; } code->_co_monitoring->local_monitors = (_Py_Monitors){ 0 }; code->_co_monitoring->active_monitors = (_Py_Monitors){ 0 }; code->_co_monitoring->tools = NULL; code->_co_monitoring->lines = NULL; code->_co_monitoring->line_tools = NULL; code->_co_monitoring->per_instruction_opcodes = NULL; code->_co_monitoring->per_instruction_tools = NULL; } return 0; } static int update_instrumentation_data(PyCodeObject *code, PyInterpreterState *interp) { int code_len = (int)Py_SIZE(code); if (allocate_instrumentation_data(code)) { return -1; } _Py_Monitors all_events = monitors_or( interp->monitors, code->_co_monitoring->local_monitors); bool multitools = multiple_tools(&all_events); if (code->_co_monitoring->tools == NULL && multitools) { code->_co_monitoring->tools = PyMem_Malloc(code_len); if (code->_co_monitoring->tools == NULL) { PyErr_NoMemory(); return -1; } initialize_tools(code); } if (all_events.tools[PY_MONITORING_EVENT_LINE]) { if (code->_co_monitoring->lines == NULL) { code->_co_monitoring->lines = PyMem_Malloc(code_len * sizeof(_PyCoLineInstrumentationData)); if (code->_co_monitoring->lines == NULL) { PyErr_NoMemory(); return -1; } initialize_lines(code); } if (multitools && code->_co_monitoring->line_tools == NULL) { code->_co_monitoring->line_tools = PyMem_Malloc(code_len); if (code->_co_monitoring->line_tools == NULL) { PyErr_NoMemory(); return -1; } initialize_line_tools(code, &all_events); } } if (all_events.tools[PY_MONITORING_EVENT_INSTRUCTION]) { if (code->_co_monitoring->per_instruction_opcodes == NULL) { code->_co_monitoring->per_instruction_opcodes = PyMem_Malloc(code_len * sizeof(_PyCoLineInstrumentationData)); if (code->_co_monitoring->per_instruction_opcodes == NULL) { PyErr_NoMemory(); return -1; } /* This may not be necessary, as we can initialize this memory lazily, but it helps catch errors. */ for (int i = 0; i < code_len; i++) { code->_co_monitoring->per_instruction_opcodes[i] = 0; } } if (multitools && code->_co_monitoring->per_instruction_tools == NULL) { code->_co_monitoring->per_instruction_tools = PyMem_Malloc(code_len); if (code->_co_monitoring->per_instruction_tools == NULL) { PyErr_NoMemory(); return -1; } /* This may not be necessary, as we can initialize this memory lazily, but it helps catch errors. */ for (int i = 0; i < code_len; i++) { code->_co_monitoring->per_instruction_tools[i] = 0; } } } return 0; } static const uint8_t super_instructions[256] = { [LOAD_FAST__LOAD_CONST] = 1, [LOAD_CONST__LOAD_FAST] = 1, }; /* Should use instruction metadata for this */ static bool is_super_instruction(uint8_t opcode) { return super_instructions[opcode] != 0; } int _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp) { if (is_version_up_to_date(code, interp)) { assert( interp->monitoring_version == 0 || instrumentation_cross_checks(interp, code) ); return 0; } int code_len = (int)Py_SIZE(code); if (update_instrumentation_data(code, interp)) { return -1; } _Py_Monitors active_events = monitors_or( interp->monitors, code->_co_monitoring->local_monitors); _Py_Monitors new_events; _Py_Monitors removed_events; bool restarted = interp->last_restart_version > code->_co_instrumentation_version; if (restarted) { removed_events = code->_co_monitoring->active_monitors; new_events = active_events; } else { removed_events = monitors_sub(code->_co_monitoring->active_monitors, active_events); new_events = monitors_sub(active_events, code->_co_monitoring->active_monitors); assert(monitors_are_empty(monitors_and(new_events, removed_events))); } code->_co_monitoring->active_monitors = active_events; code->_co_instrumentation_version = interp->monitoring_version; if (monitors_are_empty(new_events) && monitors_are_empty(removed_events)) { #ifdef INSTRUMENT_DEBUG sanity_check_instrumentation(code); #endif return 0; } /* Insert instrumentation */ for (int i = 0; i < code_len; i+= _PyInstruction_GetLength(code, i)) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; if (is_super_instruction(instr->op.code)) { instr->op.code = _PyOpcode_Deopt[instr->op.code]; } CHECK(instr->op.code != 0); int base_opcode = _Py_GetBaseOpcode(code, i); if (opcode_has_event(base_opcode)) { int8_t event; if (base_opcode == RESUME) { event = instr->op.arg > 0; } else { event = EVENT_FOR_OPCODE[base_opcode]; assert(event > 0); } uint8_t removed_tools = removed_events.tools[event]; if (removed_tools) { remove_tools(code, i, event, removed_tools); } uint8_t new_tools = new_events.tools[event]; if (new_tools) { add_tools(code, i, event, new_tools); } } } // GH-103845: We need to remove both the line and instruction instrumentation before // adding new ones, otherwise we may remove the newly added instrumentation. uint8_t removed_line_tools = removed_events.tools[PY_MONITORING_EVENT_LINE]; uint8_t removed_per_instruction_tools = removed_events.tools[PY_MONITORING_EVENT_INSTRUCTION]; if (removed_line_tools) { _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; for (int i = code->_co_firsttraceable; i < code_len;) { if (line_data[i].original_opcode) { if (removed_line_tools) { remove_line_tools(code, i, removed_line_tools); } } i += _PyInstruction_GetLength(code, i); } } if (removed_per_instruction_tools) { for (int i = code->_co_firsttraceable; i < code_len;) { int opcode = _Py_GetBaseOpcode(code, i); if (opcode == RESUME || opcode == END_FOR) { i += _PyInstruction_GetLength(code, i); continue; } if (removed_per_instruction_tools) { remove_per_instruction_tools(code, i, removed_per_instruction_tools); } i += _PyInstruction_GetLength(code, i); } } uint8_t new_line_tools = new_events.tools[PY_MONITORING_EVENT_LINE]; uint8_t new_per_instruction_tools = new_events.tools[PY_MONITORING_EVENT_INSTRUCTION]; if (new_line_tools) { _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; for (int i = code->_co_firsttraceable; i < code_len;) { if (line_data[i].original_opcode) { if (new_line_tools) { add_line_tools(code, i, new_line_tools); } } i += _PyInstruction_GetLength(code, i); } } if (new_per_instruction_tools) { for (int i = code->_co_firsttraceable; i < code_len;) { int opcode = _Py_GetBaseOpcode(code, i); if (opcode == RESUME || opcode == END_FOR) { i += _PyInstruction_GetLength(code, i); continue; } if (new_per_instruction_tools) { add_per_instruction_tools(code, i, new_per_instruction_tools); } i += _PyInstruction_GetLength(code, i); } } #ifdef INSTRUMENT_DEBUG sanity_check_instrumentation(code); #endif return 0; } #define C_RETURN_EVENTS \ ((1 << PY_MONITORING_EVENT_C_RETURN) | \ (1 << PY_MONITORING_EVENT_C_RAISE)) #define C_CALL_EVENTS \ (C_RETURN_EVENTS | (1 << PY_MONITORING_EVENT_CALL)) static int instrument_all_executing_code_objects(PyInterpreterState *interp) { _PyRuntimeState *runtime = &_PyRuntime; HEAD_LOCK(runtime); PyThreadState* ts = PyInterpreterState_ThreadHead(interp); HEAD_UNLOCK(runtime); while (ts) { _PyInterpreterFrame *frame = ts->cframe->current_frame; while (frame) { if (frame->owner != FRAME_OWNED_BY_CSTACK) { if (_Py_Instrument(frame->f_code, interp)) { return -1; } } frame = frame->previous; } HEAD_LOCK(runtime); ts = PyThreadState_Next(ts); HEAD_UNLOCK(runtime); } return 0; } static void set_events(_Py_Monitors *m, int tool_id, _PyMonitoringEventSet events) { assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) { uint8_t *tools = &m->tools[e]; int val = (events >> e) & 1; *tools &= ~(1 << tool_id); *tools |= (val << tool_id); } } static int check_tool(PyInterpreterState *interp, int tool_id) { if (tool_id < PY_MONITORING_SYS_PROFILE_ID && interp->monitoring_tool_names[tool_id] == NULL) { PyErr_Format(PyExc_ValueError, "tool %d is not in use", tool_id); return -1; } return 0; } int _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events) { assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); PyInterpreterState *interp = _PyInterpreterState_Get(); assert(events < (1 << PY_MONITORING_UNGROUPED_EVENTS)); if (check_tool(interp, tool_id)) { return -1; } uint32_t existing_events = get_events(&interp->monitors, tool_id); if (existing_events == events) { return 0; } set_events(&interp->monitors, tool_id, events); interp->monitoring_version++; return instrument_all_executing_code_objects(interp); } int _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet events) { assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); PyInterpreterState *interp = _PyInterpreterState_Get(); assert(events < (1 << PY_MONITORING_UNGROUPED_EVENTS)); if (check_tool(interp, tool_id)) { return -1; } if (allocate_instrumentation_data(code)) { return -1; } _Py_Monitors *local = &code->_co_monitoring->local_monitors; uint32_t existing_events = get_events(local, tool_id); if (existing_events == events) { return 0; } set_events(local, tool_id, events); if (is_version_up_to_date(code, interp)) { /* Force instrumentation update */ code->_co_instrumentation_version = UINT64_MAX; } if (_Py_Instrument(code, interp)) { return -1; } return 0; } /*[clinic input] module monitoring [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=37257f5987a360cf]*/ /*[clinic end generated code]*/ #include "clinic/instrumentation.c.h" static int check_valid_tool(int tool_id) { if (tool_id < 0 || tool_id >= PY_MONITORING_SYS_PROFILE_ID) { PyErr_Format(PyExc_ValueError, "invalid tool %d (must be between 0 and 5)", tool_id); return -1; } return 0; } /*[clinic input] monitoring.use_tool_id tool_id: int name: object / [clinic start generated code]*/ static PyObject * monitoring_use_tool_id_impl(PyObject *module, int tool_id, PyObject *name) /*[clinic end generated code: output=30d76dc92b7cd653 input=ebc453761c621be1]*/ { if (check_valid_tool(tool_id)) { return NULL; } if (!PyUnicode_Check(name)) { PyErr_SetString(PyExc_ValueError, "tool name must be a str"); return NULL; } PyInterpreterState *interp = _PyInterpreterState_Get(); if (interp->monitoring_tool_names[tool_id] != NULL) { PyErr_Format(PyExc_ValueError, "tool %d is already in use", tool_id); return NULL; } interp->monitoring_tool_names[tool_id] = Py_NewRef(name); Py_RETURN_NONE; } /*[clinic input] monitoring.free_tool_id tool_id: int / [clinic start generated code]*/ static PyObject * monitoring_free_tool_id_impl(PyObject *module, int tool_id) /*[clinic end generated code: output=86c2d2a1219a8591 input=a23fb6be3a8618e9]*/ { if (check_valid_tool(tool_id)) { return NULL; } PyInterpreterState *interp = _PyInterpreterState_Get(); Py_CLEAR(interp->monitoring_tool_names[tool_id]); Py_RETURN_NONE; } /*[clinic input] monitoring.get_tool tool_id: int / [clinic start generated code]*/ static PyObject * monitoring_get_tool_impl(PyObject *module, int tool_id) /*[clinic end generated code: output=1c05a98b404a9a16 input=eeee9bebd0bcae9d]*/ /*[clinic end generated code]*/ { if (check_valid_tool(tool_id)) { return NULL; } PyInterpreterState *interp = _PyInterpreterState_Get(); PyObject *name = interp->monitoring_tool_names[tool_id]; if (name == NULL) { Py_RETURN_NONE; } return Py_NewRef(name); } /*[clinic input] monitoring.register_callback tool_id: int event: int func: object / [clinic start generated code]*/ static PyObject * monitoring_register_callback_impl(PyObject *module, int tool_id, int event, PyObject *func) /*[clinic end generated code: output=e64daa363004030c input=df6d70ea4cf81007]*/ { if (check_valid_tool(tool_id)) { return NULL; } if (_Py_popcount32(event) != 1) { PyErr_SetString(PyExc_ValueError, "The callback can only be set for one event at a time"); return NULL; } int event_id = _Py_bit_length(event)-1; if (event_id < 0 || event_id >= PY_MONITORING_EVENTS) { PyErr_Format(PyExc_ValueError, "invalid event %d", event); return NULL; } if (func == Py_None) { func = NULL; } func = _PyMonitoring_RegisterCallback(tool_id, event_id, func); if (func == NULL) { Py_RETURN_NONE; } return func; } /*[clinic input] monitoring.get_events -> int tool_id: int / [clinic start generated code]*/ static int monitoring_get_events_impl(PyObject *module, int tool_id) /*[clinic end generated code: output=4450cc13f826c8c0 input=a64b238f76c4b2f7]*/ { if (check_valid_tool(tool_id)) { return -1; } _Py_Monitors *m = &_PyInterpreterState_Get()->monitors; _PyMonitoringEventSet event_set = get_events(m, tool_id); return event_set; } /*[clinic input] monitoring.set_events tool_id: int event_set: int / [clinic start generated code]*/ static PyObject * monitoring_set_events_impl(PyObject *module, int tool_id, int event_set) /*[clinic end generated code: output=1916c1e49cfb5bdb input=a77ba729a242142b]*/ { if (check_valid_tool(tool_id)) { return NULL; } if (event_set < 0 || event_set >= (1 << PY_MONITORING_EVENTS)) { PyErr_Format(PyExc_ValueError, "invalid event set 0x%x", event_set); return NULL; } if ((event_set & C_RETURN_EVENTS) && (event_set & C_CALL_EVENTS) != C_CALL_EVENTS) { PyErr_Format(PyExc_ValueError, "cannot set C_RETURN or C_RAISE events independently"); return NULL; } event_set &= ~C_RETURN_EVENTS; if (_PyMonitoring_SetEvents(tool_id, event_set)) { return NULL; } Py_RETURN_NONE; } /*[clinic input] monitoring.get_local_events -> int tool_id: int code: object / [clinic start generated code]*/ static int monitoring_get_local_events_impl(PyObject *module, int tool_id, PyObject *code) /*[clinic end generated code: output=d3e92c1c9c1de8f9 input=bb0f927530386a94]*/ { if (!PyCode_Check(code)) { PyErr_Format( PyExc_TypeError, "code must be a code object" ); return -1; } if (check_valid_tool(tool_id)) { return -1; } _PyMonitoringEventSet event_set = 0; _PyCoMonitoringData *data = ((PyCodeObject *)code)->_co_monitoring; if (data != NULL) { for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) { if ((data->local_monitors.tools[e] >> tool_id) & 1) { event_set |= (1 << e); } } } return event_set; } /*[clinic input] monitoring.set_local_events tool_id: int code: object event_set: int / [clinic start generated code]*/ static PyObject * monitoring_set_local_events_impl(PyObject *module, int tool_id, PyObject *code, int event_set) /*[clinic end generated code: output=68cc755a65dfea99 input=5655ecd78d937a29]*/ { if (!PyCode_Check(code)) { PyErr_Format( PyExc_TypeError, "code must be a code object" ); return NULL; } if (check_valid_tool(tool_id)) { return NULL; } if (event_set < 0 || event_set >= (1 << PY_MONITORING_EVENTS)) { PyErr_Format(PyExc_ValueError, "invalid event set 0x%x", event_set); return NULL; } if ((event_set & C_RETURN_EVENTS) && (event_set & C_CALL_EVENTS) != C_CALL_EVENTS) { PyErr_Format(PyExc_ValueError, "cannot set C_RETURN or C_RAISE events independently"); return NULL; } event_set &= ~C_RETURN_EVENTS; if (_PyMonitoring_SetLocalEvents((PyCodeObject*)code, tool_id, event_set)) { return NULL; } Py_RETURN_NONE; } /*[clinic input] monitoring.restart_events [clinic start generated code]*/ static PyObject * monitoring_restart_events_impl(PyObject *module) /*[clinic end generated code: output=e025dd5ba33314c4 input=add8a855063c8008]*/ { /* We want to ensure that: * last restart version > instrumented version for all code objects * last restart version < current version */ PyInterpreterState *interp = _PyInterpreterState_Get(); interp->last_restart_version = interp->monitoring_version + 1; interp->monitoring_version = interp->last_restart_version + 1; if (instrument_all_executing_code_objects(interp)) { return NULL; } Py_RETURN_NONE; } static int add_power2_constant(PyObject *obj, const char *name, int i) { PyObject *val = PyLong_FromLong(1<monitors.tools[e]; if (tools == 0) { continue; } PyObject *tools_obj = PyLong_FromLong(tools); assert(tools_obj != NULL); int err = PyDict_SetItemString(res, event_names[e], tools_obj); Py_DECREF(tools_obj); if (err < 0) { Py_DECREF(res); return NULL; } } return res; } static PyMethodDef methods[] = { MONITORING_USE_TOOL_ID_METHODDEF MONITORING_FREE_TOOL_ID_METHODDEF MONITORING_GET_TOOL_METHODDEF MONITORING_REGISTER_CALLBACK_METHODDEF MONITORING_GET_EVENTS_METHODDEF MONITORING_SET_EVENTS_METHODDEF MONITORING_GET_LOCAL_EVENTS_METHODDEF MONITORING_SET_LOCAL_EVENTS_METHODDEF MONITORING_RESTART_EVENTS_METHODDEF MONITORING__ALL_EVENTS_METHODDEF {NULL, NULL} // sentinel }; static struct PyModuleDef monitoring_module = { PyModuleDef_HEAD_INIT, .m_name = "sys.monitoring", .m_size = -1, /* multiple "initialization" just copies the module dict. */ .m_methods = methods, }; PyObject *_Py_CreateMonitoringObject(void) { PyObject *mod = _PyModule_CreateInitialized(&monitoring_module, PYTHON_API_VERSION); if (mod == NULL) { return NULL; } if (PyObject_SetAttrString(mod, "DISABLE", &_PyInstrumentation_DISABLE)) { goto error; } if (PyObject_SetAttrString(mod, "MISSING", &_PyInstrumentation_MISSING)) { goto error; } PyObject *events = _PyNamespace_New(NULL); if (events == NULL) { goto error; } int err = PyObject_SetAttrString(mod, "events", events); Py_DECREF(events); if (err) { goto error; } for (int i = 0; i < PY_MONITORING_EVENTS; i++) { if (add_power2_constant(events, event_names[i], i)) { goto error; } } err = PyObject_SetAttrString(events, "NO_EVENTS", _PyLong_GetZero()); if (err) goto error; PyObject *val = PyLong_FromLong(PY_MONITORING_DEBUGGER_ID); err = PyObject_SetAttrString(mod, "DEBUGGER_ID", val); Py_DECREF(val); if (err) goto error; val = PyLong_FromLong(PY_MONITORING_COVERAGE_ID); err = PyObject_SetAttrString(mod, "COVERAGE_ID", val); Py_DECREF(val); if (err) goto error; val = PyLong_FromLong(PY_MONITORING_PROFILER_ID); err = PyObject_SetAttrString(mod, "PROFILER_ID", val); Py_DECREF(val); if (err) goto error; val = PyLong_FromLong(PY_MONITORING_OPTIMIZER_ID); err = PyObject_SetAttrString(mod, "OPTIMIZER_ID", val); Py_DECREF(val); if (err) goto error; return mod; error: Py_DECREF(mod); return NULL; } ================================================ FILE: InstruMentation.c ================================================ #include "Python.h" #include "pycore_call.h" #include "pycore_frame.h" #include "pycore_interp.h" #include "pycore_long.h" #include "pycore_namespace.h" #include "pycore_object.h" #include "pycore_opcode.h" #include "pycore_pyerrors.h" #include "pycore_pystate.h" /* Uncomment this to dump debugging output when assertions fail */ // #define INSTRUMENT_DEBUG 1 PyObject _PyInstrumentation_DISABLE = { .ob_refcnt = _Py_IMMORTAL_REFCNT, .ob_type = &PyBaseObject_Type }; PyObject _PyInstrumentation_MISSING = { .ob_refcnt = _Py_IMMORTAL_REFCNT, .ob_type = &PyBaseObject_Type }; static const int8_t EVENT_FOR_OPCODE[256] = { [RETURN_CONST] = PY_MONITORING_EVENT_PY_RETURN, [INSTRUMENTED_RETURN_CONST] = PY_MONITORING_EVENT_PY_RETURN, [RETURN_VALUE] = PY_MONITORING_EVENT_PY_RETURN, [INSTRUMENTED_RETURN_VALUE] = PY_MONITORING_EVENT_PY_RETURN, [CALL] = PY_MONITORING_EVENT_CALL, [INSTRUMENTED_CALL] = PY_MONITORING_EVENT_CALL, [CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL, [INSTRUMENTED_CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL, [LOAD_SUPER_ATTR] = PY_MONITORING_EVENT_CALL, [INSTRUMENTED_LOAD_SUPER_ATTR] = PY_MONITORING_EVENT_CALL, [RESUME] = -1, [YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD, [INSTRUMENTED_YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD, [JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP, [JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP, [POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH, [POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH, [POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH, [POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH, [INSTRUMENTED_JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP, [INSTRUMENTED_JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP, [INSTRUMENTED_POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH, [INSTRUMENTED_POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH, [INSTRUMENTED_POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH, [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH, [FOR_ITER] = PY_MONITORING_EVENT_BRANCH, [INSTRUMENTED_FOR_ITER] = PY_MONITORING_EVENT_BRANCH, [END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION, [INSTRUMENTED_END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION, [END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION, [INSTRUMENTED_END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION, }; static const uint8_t DE_INSTRUMENT[256] = { [INSTRUMENTED_RESUME] = RESUME, [INSTRUMENTED_RETURN_VALUE] = RETURN_VALUE, [INSTRUMENTED_RETURN_CONST] = RETURN_CONST, [INSTRUMENTED_CALL] = CALL, [INSTRUMENTED_CALL_FUNCTION_EX] = CALL_FUNCTION_EX, [INSTRUMENTED_YIELD_VALUE] = YIELD_VALUE, [INSTRUMENTED_JUMP_FORWARD] = JUMP_FORWARD, [INSTRUMENTED_JUMP_BACKWARD] = JUMP_BACKWARD, [INSTRUMENTED_POP_JUMP_IF_FALSE] = POP_JUMP_IF_FALSE, [INSTRUMENTED_POP_JUMP_IF_TRUE] = POP_JUMP_IF_TRUE, [INSTRUMENTED_POP_JUMP_IF_NONE] = POP_JUMP_IF_NONE, [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = POP_JUMP_IF_NOT_NONE, [INSTRUMENTED_FOR_ITER] = FOR_ITER, [INSTRUMENTED_END_FOR] = END_FOR, [INSTRUMENTED_END_SEND] = END_SEND, [INSTRUMENTED_LOAD_SUPER_ATTR] = LOAD_SUPER_ATTR, }; static const uint8_t INSTRUMENTED_OPCODES[256] = { [RETURN_CONST] = INSTRUMENTED_RETURN_CONST, [INSTRUMENTED_RETURN_CONST] = INSTRUMENTED_RETURN_CONST, [RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE, [INSTRUMENTED_RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE, [CALL] = INSTRUMENTED_CALL, [INSTRUMENTED_CALL] = INSTRUMENTED_CALL, [CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX, [INSTRUMENTED_CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX, [YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE, [INSTRUMENTED_YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE, [RESUME] = INSTRUMENTED_RESUME, [INSTRUMENTED_RESUME] = INSTRUMENTED_RESUME, [JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD, [INSTRUMENTED_JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD, [JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD, [INSTRUMENTED_JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD, [POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE, [INSTRUMENTED_POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE, [POP_JUMP_IF_TRUE] = INSTRUMENTED_POP_JUMP_IF_TRUE, [INSTRUMENTED_POP_JUMP_IF_TRUE] = INSTRUMENTED_POP_JUMP_IF_TRUE, [POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE, [INSTRUMENTED_POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE, [POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE, [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE, [END_FOR] = INSTRUMENTED_END_FOR, [INSTRUMENTED_END_FOR] = INSTRUMENTED_END_FOR, [END_SEND] = INSTRUMENTED_END_SEND, [INSTRUMENTED_END_SEND] = INSTRUMENTED_END_SEND, [FOR_ITER] = INSTRUMENTED_FOR_ITER, [INSTRUMENTED_FOR_ITER] = INSTRUMENTED_FOR_ITER, [LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR, [INSTRUMENTED_LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR, [INSTRUMENTED_LINE] = INSTRUMENTED_LINE, [INSTRUMENTED_INSTRUCTION] = INSTRUMENTED_INSTRUCTION, }; static inline bool opcode_has_event(int opcode) { return ( opcode < INSTRUMENTED_LINE && INSTRUMENTED_OPCODES[opcode] > 0 ); } static inline bool is_instrumented(int opcode) { assert(opcode != 0); assert(opcode != RESERVED); return opcode >= MIN_INSTRUMENTED_OPCODE; } #ifndef NDEBUG static inline bool monitors_equals(_Py_Monitors a, _Py_Monitors b) { for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { if (a.tools[i] != b.tools[i]) { return false; } } return true; } #endif static inline _Py_Monitors monitors_sub(_Py_Monitors a, _Py_Monitors b) { _Py_Monitors res; for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { res.tools[i] = a.tools[i] & ~b.tools[i]; } return res; } #ifndef NDEBUG static inline _Py_Monitors monitors_and(_Py_Monitors a, _Py_Monitors b) { _Py_Monitors res; for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { res.tools[i] = a.tools[i] & b.tools[i]; } return res; } #endif static inline _Py_Monitors monitors_or(_Py_Monitors a, _Py_Monitors b) { _Py_Monitors res; for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { res.tools[i] = a.tools[i] | b.tools[i]; } return res; } static inline bool monitors_are_empty(_Py_Monitors m) { for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { if (m.tools[i]) { return false; } } return true; } static inline bool multiple_tools(_Py_Monitors *m) { for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { if (_Py_popcount32(m->tools[i]) > 1) { return true; } } return false; } static inline _PyMonitoringEventSet get_events(_Py_Monitors *m, int tool_id) { _PyMonitoringEventSet result = 0; for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) { if ((m->tools[e] >> tool_id) & 1) { result |= (1 << e); } } return result; } /* Line delta. * 8 bit value. * if line_delta == -128: * line = None # represented as -1 * elif line_delta == -127: * line = PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT)); * else: * line = first_line + (offset >> OFFSET_SHIFT) + line_delta; */ #define NO_LINE -128 #define COMPUTED_LINE -127 #define OFFSET_SHIFT 4 static int8_t compute_line_delta(PyCodeObject *code, int offset, int line) { if (line < 0) { return NO_LINE; } int delta = line - code->co_firstlineno - (offset >> OFFSET_SHIFT); if (delta <= INT8_MAX && delta > COMPUTED_LINE) { return delta; } return COMPUTED_LINE; } static int compute_line(PyCodeObject *code, int offset, int8_t line_delta) { if (line_delta > COMPUTED_LINE) { return code->co_firstlineno + (offset >> OFFSET_SHIFT) + line_delta; } if (line_delta == NO_LINE) { return -1; } assert(line_delta == COMPUTED_LINE); /* Look it up */ return PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT)); } int _PyInstruction_GetLength(PyCodeObject *code, int offset) { int opcode = _PyCode_CODE(code)[offset].op.code; assert(opcode != 0); assert(opcode != RESERVED); if (opcode == INSTRUMENTED_LINE) { opcode = code->_co_monitoring->lines[offset].original_opcode; } if (opcode == INSTRUMENTED_INSTRUCTION) { opcode = code->_co_monitoring->per_instruction_opcodes[offset]; } int deinstrumented = DE_INSTRUMENT[opcode]; if (deinstrumented) { opcode = deinstrumented; } else { opcode = _PyOpcode_Deopt[opcode]; } assert(opcode != 0); assert(!is_instrumented(opcode)); assert(opcode == _PyOpcode_Deopt[opcode]); return 1 + _PyOpcode_Caches[opcode]; } #ifdef INSTRUMENT_DEBUG static void dump_instrumentation_data_tools(PyCodeObject *code, uint8_t *tools, int i, FILE*out) { if (tools == NULL) { fprintf(out, "tools = NULL"); } else { fprintf(out, "tools = %d", tools[i]); } } static void dump_instrumentation_data_lines(PyCodeObject *code, _PyCoLineInstrumentationData *lines, int i, FILE*out) { if (lines == NULL) { fprintf(out, ", lines = NULL"); } else if (lines[i].original_opcode == 0) { fprintf(out, ", lines = {original_opcode = No LINE (0), line_delta = %d)", lines[i].line_delta); } else { fprintf(out, ", lines = {original_opcode = %s, line_delta = %d)", _PyOpcode_OpName[lines[i].original_opcode], lines[i].line_delta); } } static void dump_instrumentation_data_line_tools(PyCodeObject *code, uint8_t *line_tools, int i, FILE*out) { if (line_tools == NULL) { fprintf(out, ", line_tools = NULL"); } else { fprintf(out, ", line_tools = %d", line_tools[i]); } } static void dump_instrumentation_data_per_instruction(PyCodeObject *code, _PyCoMonitoringData *data, int i, FILE*out) { if (data->per_instruction_opcodes == NULL) { fprintf(out, ", per-inst opcode = NULL"); } else { fprintf(out, ", per-inst opcode = %s", _PyOpcode_OpName[data->per_instruction_opcodes[i]]); } if (data->per_instruction_tools == NULL) { fprintf(out, ", per-inst tools = NULL"); } else { fprintf(out, ", per-inst tools = %d", data->per_instruction_tools[i]); } } static void dump_monitors(const char *prefix, _Py_Monitors monitors, FILE*out) { fprintf(out, "%s monitors:\n", prefix); for (int event = 0; event < PY_MONITORING_UNGROUPED_EVENTS; event++) { fprintf(out, " Event %d: Tools %x\n", event, monitors.tools[event]); } } /* Like _Py_GetBaseOpcode but without asserts. * Does its best to give the right answer, but won't abort * if something is wrong */ static int get_base_opcode_best_attempt(PyCodeObject *code, int offset) { int opcode = _Py_OPCODE(_PyCode_CODE(code)[offset]); if (INSTRUMENTED_OPCODES[opcode] != opcode) { /* Not instrumented */ return _PyOpcode_Deopt[opcode] == 0 ? opcode : _PyOpcode_Deopt[opcode]; } if (opcode == INSTRUMENTED_INSTRUCTION) { if (code->_co_monitoring->per_instruction_opcodes[offset] == 0) { return opcode; } opcode = code->_co_monitoring->per_instruction_opcodes[offset]; } if (opcode == INSTRUMENTED_LINE) { if (code->_co_monitoring->lines[offset].original_opcode == 0) { return opcode; } opcode = code->_co_monitoring->lines[offset].original_opcode; } int deinstrumented = DE_INSTRUMENT[opcode]; if (deinstrumented) { return deinstrumented; } if (_PyOpcode_Deopt[opcode] == 0) { return opcode; } return _PyOpcode_Deopt[opcode]; } /* No error checking -- Don't use this for anything but experimental debugging */ static void dump_instrumentation_data(PyCodeObject *code, int star, FILE*out) { _PyCoMonitoringData *data = code->_co_monitoring; fprintf(out, "\n"); PyObject_Print(code->co_name, out, Py_PRINT_RAW); fprintf(out, "\n"); if (data == NULL) { fprintf(out, "NULL\n"); return; } dump_monitors("Global", PyInterpreterState_Get()->monitors, out); dump_monitors("Code", data->local_monitors, out); dump_monitors("Active", data->active_monitors, out); int code_len = (int)Py_SIZE(code); bool starred = false; for (int i = 0; i < code_len; i += _PyInstruction_GetLength(code, i)) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; int opcode = instr->op.code; if (i == star) { fprintf(out, "** "); starred = true; } fprintf(out, "Offset: %d, line: %d %s: ", i, PyCode_Addr2Line(code, i*2), _PyOpcode_OpName[opcode]); dump_instrumentation_data_tools(code, data->tools, i, out); dump_instrumentation_data_lines(code, data->lines, i, out); dump_instrumentation_data_line_tools(code, data->line_tools, i, out); dump_instrumentation_data_per_instruction(code, data, i, out); fprintf(out, "\n"); ; } if (!starred && star >= 0) { fprintf(out, "Error offset not at valid instruction offset: %d\n", star); fprintf(out, " "); dump_instrumentation_data_tools(code, data->tools, star, out); dump_instrumentation_data_lines(code, data->lines, star, out); dump_instrumentation_data_line_tools(code, data->line_tools, star, out); dump_instrumentation_data_per_instruction(code, data, star, out); fprintf(out, "\n"); } } #define CHECK(test) do { \ if (!(test)) { \ dump_instrumentation_data(code, i, stderr); \ } \ assert(test); \ } while (0) static bool valid_opcode(int opcode) { if (opcode > 0 && opcode != RESERVED && opcode < 255 && _PyOpcode_OpName[opcode] && _PyOpcode_OpName[opcode][0] != '<') { return true; } return false; } static void sanity_check_instrumentation(PyCodeObject *code) { _PyCoMonitoringData *data = code->_co_monitoring; if (data == NULL) { return; } _Py_Monitors active_monitors = PyInterpreterState_Get()->monitors; if (code->_co_monitoring) { _Py_Monitors local_monitors = code->_co_monitoring->local_monitors; active_monitors = monitors_or(active_monitors, local_monitors); } assert(monitors_equals( code->_co_monitoring->active_monitors, active_monitors) ); int code_len = (int)Py_SIZE(code); for (int i = 0; i < code_len;) { int opcode = _PyCode_CODE(code)[i].op.code; int base_opcode = _Py_GetBaseOpcode(code, i); CHECK(valid_opcode(opcode)); CHECK(valid_opcode(base_opcode)); if (opcode == INSTRUMENTED_INSTRUCTION) { opcode = data->per_instruction_opcodes[i]; if (!is_instrumented(opcode)) { CHECK(_PyOpcode_Deopt[opcode] == opcode); } if (data->per_instruction_tools) { uint8_t tools = active_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION]; CHECK((tools & data->per_instruction_tools[i]) == data->per_instruction_tools[i]); } } if (opcode == INSTRUMENTED_LINE) { CHECK(data->lines); CHECK(valid_opcode(data->lines[i].original_opcode)); opcode = data->lines[i].original_opcode; CHECK(opcode != END_FOR); CHECK(opcode != RESUME); CHECK(opcode != INSTRUMENTED_RESUME); if (!is_instrumented(opcode)) { CHECK(_PyOpcode_Deopt[opcode] == opcode); } CHECK(opcode != INSTRUMENTED_LINE); } else if (data->lines && !is_instrumented(opcode)) { CHECK(data->lines[i].original_opcode == 0 || data->lines[i].original_opcode == base_opcode || DE_INSTRUMENT[data->lines[i].original_opcode] == base_opcode); } if (is_instrumented(opcode)) { CHECK(DE_INSTRUMENT[opcode] == base_opcode); int event = EVENT_FOR_OPCODE[DE_INSTRUMENT[opcode]]; if (event < 0) { /* RESUME fixup */ event = _PyCode_CODE(code)[i].op.arg; } CHECK(active_monitors.tools[event] != 0); } if (data->lines && base_opcode != END_FOR) { int line1 = compute_line(code, i, data->lines[i].line_delta); int line2 = PyCode_Addr2Line(code, i*sizeof(_Py_CODEUNIT)); CHECK(line1 == line2); } CHECK(valid_opcode(opcode)); if (data->tools) { uint8_t local_tools = data->tools[i]; if (opcode_has_event(base_opcode)) { int event = EVENT_FOR_OPCODE[base_opcode]; if (event == -1) { /* RESUME fixup */ event = _PyCode_CODE(code)[i].op.arg; } CHECK((active_monitors.tools[event] & local_tools) == local_tools); } else { CHECK(local_tools == 0xff); } } i += _PyInstruction_GetLength(code, i); assert(i <= code_len); } } #else #define CHECK(test) assert(test) #endif /* Get the underlying opcode, stripping instrumentation */ int _Py_GetBaseOpcode(PyCodeObject *code, int i) { int opcode = _PyCode_CODE(code)[i].op.code; if (opcode == INSTRUMENTED_LINE) { opcode = code->_co_monitoring->lines[i].original_opcode; } if (opcode == INSTRUMENTED_INSTRUCTION) { opcode = code->_co_monitoring->per_instruction_opcodes[i]; } CHECK(opcode != INSTRUMENTED_INSTRUCTION); CHECK(opcode != INSTRUMENTED_LINE); int deinstrumented = DE_INSTRUMENT[opcode]; if (deinstrumented) { return deinstrumented; } return _PyOpcode_Deopt[opcode]; } static void de_instrument(PyCodeObject *code, int i, int event) { assert(event != PY_MONITORING_EVENT_INSTRUCTION); assert(event != PY_MONITORING_EVENT_LINE); _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; uint8_t *opcode_ptr = &instr->op.code; int opcode = *opcode_ptr; if (opcode == INSTRUMENTED_LINE) { opcode_ptr = &code->_co_monitoring->lines[i].original_opcode; opcode = *opcode_ptr; } if (opcode == INSTRUMENTED_INSTRUCTION) { opcode_ptr = &code->_co_monitoring->per_instruction_opcodes[i]; opcode = *opcode_ptr; } int deinstrumented = DE_INSTRUMENT[opcode]; if (deinstrumented == 0) { return; } CHECK(_PyOpcode_Deopt[deinstrumented] == deinstrumented); *opcode_ptr = deinstrumented; if (_PyOpcode_Caches[deinstrumented]) { instr[1].cache = adaptive_counter_warmup(); } } static void de_instrument_line(PyCodeObject *code, int i) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; uint8_t *opcode_ptr = &instr->op.code; int opcode =*opcode_ptr; if (opcode != INSTRUMENTED_LINE) { return; } _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; int original_opcode = lines->original_opcode; CHECK(original_opcode != 0); CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]); *opcode_ptr = instr->op.code = original_opcode; if (_PyOpcode_Caches[original_opcode]) { instr[1].cache = adaptive_counter_warmup(); } assert(*opcode_ptr != INSTRUMENTED_LINE); assert(instr->op.code != INSTRUMENTED_LINE); } static void de_instrument_per_instruction(PyCodeObject *code, int i) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; uint8_t *opcode_ptr = &instr->op.code; int opcode =*opcode_ptr; if (opcode == INSTRUMENTED_LINE) { opcode_ptr = &code->_co_monitoring->lines[i].original_opcode; opcode = *opcode_ptr; } if (opcode != INSTRUMENTED_INSTRUCTION) { return; } int original_opcode = code->_co_monitoring->per_instruction_opcodes[i]; CHECK(original_opcode != 0); CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]); instr->op.code = original_opcode; if (_PyOpcode_Caches[original_opcode]) { instr[1].cache = adaptive_counter_warmup(); } assert(instr->op.code != INSTRUMENTED_INSTRUCTION); /* Keep things clean for sanity check */ code->_co_monitoring->per_instruction_opcodes[i] = 0; } static void instrument(PyCodeObject *code, int i) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; uint8_t *opcode_ptr = &instr->op.code; int opcode =*opcode_ptr; if (opcode == INSTRUMENTED_LINE) { _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; opcode_ptr = &lines->original_opcode; opcode = *opcode_ptr; } if (opcode == INSTRUMENTED_INSTRUCTION) { opcode_ptr = &code->_co_monitoring->per_instruction_opcodes[i]; opcode = *opcode_ptr; CHECK(!is_instrumented(opcode)); CHECK(opcode == _PyOpcode_Deopt[opcode]); } CHECK(opcode != 0); if (!is_instrumented(opcode)) { int deopt = _PyOpcode_Deopt[opcode]; int instrumented = INSTRUMENTED_OPCODES[deopt]; assert(instrumented); *opcode_ptr = instrumented; if (_PyOpcode_Caches[deopt]) { instr[1].cache = adaptive_counter_warmup(); } } } static void instrument_line(PyCodeObject *code, int i) { uint8_t *opcode_ptr = &_PyCode_CODE(code)[i].op.code; int opcode =*opcode_ptr; if (opcode == INSTRUMENTED_LINE) { return; } _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; lines->original_opcode = _PyOpcode_Deopt[opcode]; CHECK(lines->original_opcode > 0); *opcode_ptr = INSTRUMENTED_LINE; } static void instrument_per_instruction(PyCodeObject *code, int i) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; uint8_t *opcode_ptr = &instr->op.code; int opcode =*opcode_ptr; if (opcode == INSTRUMENTED_LINE) { _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; opcode_ptr = &lines->original_opcode; opcode = *opcode_ptr; } if (opcode == INSTRUMENTED_INSTRUCTION) { return; } CHECK(opcode != 0); if (is_instrumented(opcode)) { code->_co_monitoring->per_instruction_opcodes[i] = opcode; } else { assert(opcode != 0); assert(_PyOpcode_Deopt[opcode] != 0); assert(_PyOpcode_Deopt[opcode] != RESUME); code->_co_monitoring->per_instruction_opcodes[i] = _PyOpcode_Deopt[opcode]; } assert(code->_co_monitoring->per_instruction_opcodes[i] > 0); *opcode_ptr = INSTRUMENTED_INSTRUCTION; } #ifndef NDEBUG static bool instruction_has_event(PyCodeObject *code, int offset) { _Py_CODEUNIT instr = _PyCode_CODE(code)[offset]; int opcode = instr.op.code; if (opcode == INSTRUMENTED_LINE) { opcode = code->_co_monitoring->lines[offset].original_opcode; } if (opcode == INSTRUMENTED_INSTRUCTION) { opcode = code->_co_monitoring->per_instruction_opcodes[offset]; } return opcode_has_event(opcode); } #endif static void remove_tools(PyCodeObject * code, int offset, int event, int tools) { assert(event != PY_MONITORING_EVENT_LINE); assert(event != PY_MONITORING_EVENT_INSTRUCTION); assert(event < PY_MONITORING_INSTRUMENTED_EVENTS); assert(instruction_has_event(code, offset)); _PyCoMonitoringData *monitoring = code->_co_monitoring; if (monitoring && monitoring->tools) { monitoring->tools[offset] &= ~tools; if (monitoring->tools[offset] == 0) { de_instrument(code, offset, event); } } else { /* Single tool */ uint8_t single_tool = code->_co_monitoring->active_monitors.tools[event]; assert(_Py_popcount32(single_tool) <= 1); if (((single_tool & tools) == single_tool)) { de_instrument(code, offset, event); } } } #ifndef NDEBUG static bool tools_is_subset_for_event(PyCodeObject * code, int event, int tools) { int global_tools = PyInterpreterState_Get()->monitors.tools[event]; int local_tools = code->_co_monitoring->local_monitors.tools[event]; return tools == ((global_tools | local_tools) & tools); } #endif static void remove_line_tools(PyCodeObject * code, int offset, int tools) { assert(code->_co_monitoring); if (code->_co_monitoring->line_tools) { uint8_t *toolsptr = &code->_co_monitoring->line_tools[offset]; *toolsptr &= ~tools; if (*toolsptr == 0 ) { de_instrument_line(code, offset); } } else { /* Single tool */ uint8_t single_tool = code->_co_monitoring->active_monitors.tools[PY_MONITORING_EVENT_LINE]; assert(_Py_popcount32(single_tool) <= 1); if (((single_tool & tools) == single_tool)) { de_instrument_line(code, offset); } } } static void add_tools(PyCodeObject * code, int offset, int event, int tools) { assert(event != PY_MONITORING_EVENT_LINE); assert(event != PY_MONITORING_EVENT_INSTRUCTION); assert(event < PY_MONITORING_INSTRUMENTED_EVENTS); assert(code->_co_monitoring); if (code->_co_monitoring && code->_co_monitoring->tools ) { code->_co_monitoring->tools[offset] |= tools; } else { /* Single tool */ assert(_Py_popcount32(tools) == 1); assert(tools_is_subset_for_event(code, event, tools)); } instrument(code, offset); } static void add_line_tools(PyCodeObject * code, int offset, int tools) { assert(tools_is_subset_for_event(code, PY_MONITORING_EVENT_LINE, tools)); assert(code->_co_monitoring); if (code->_co_monitoring->line_tools) { code->_co_monitoring->line_tools[offset] |= tools; } else { /* Single tool */ assert(_Py_popcount32(tools) == 1); } instrument_line(code, offset); } static void add_per_instruction_tools(PyCodeObject * code, int offset, int tools) { assert(tools_is_subset_for_event(code, PY_MONITORING_EVENT_INSTRUCTION, tools)); assert(code->_co_monitoring); if (code->_co_monitoring->per_instruction_tools) { code->_co_monitoring->per_instruction_tools[offset] |= tools; } else { /* Single tool */ assert(_Py_popcount32(tools) == 1); } instrument_per_instruction(code, offset); } static void remove_per_instruction_tools(PyCodeObject * code, int offset, int tools) { assert(code->_co_monitoring); if (code->_co_monitoring->per_instruction_tools) { uint8_t *toolsptr = &code->_co_monitoring->per_instruction_tools[offset]; *toolsptr &= ~tools; if (*toolsptr == 0) { de_instrument_per_instruction(code, offset); } } else { /* Single tool */ uint8_t single_tool = code->_co_monitoring->active_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION]; assert(_Py_popcount32(single_tool) <= 1); if (((single_tool & tools) == single_tool)) { de_instrument_per_instruction(code, offset); } } } /* Return 1 if DISABLE returned, -1 if error, 0 otherwise */ static int call_one_instrument( PyInterpreterState *interp, PyThreadState *tstate, PyObject **args, Py_ssize_t nargsf, int8_t tool, int event) { assert(0 <= tool && tool < 8); assert(tstate->tracing == 0); PyObject *instrument = interp->monitoring_callables[tool][event]; if (instrument == NULL) { return 0; } int old_what = tstate->what_event; tstate->what_event = event; tstate->tracing++; PyObject *res = _PyObject_VectorcallTstate(tstate, instrument, args, nargsf, NULL); tstate->tracing--; tstate->what_event = old_what; if (res == NULL) { return -1; } Py_DECREF(res); return (res == &_PyInstrumentation_DISABLE); } static const int8_t MOST_SIGNIFICANT_BITS[16] = { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, }; /* We could use _Py_bit_length here, but that is designed for larger (32/64) * bit ints, and can perform relatively poorly on platforms without the * necessary intrinsics. */ static inline int most_significant_bit(uint8_t bits) { assert(bits != 0); if (bits > 15) { return MOST_SIGNIFICANT_BITS[bits>>4]+4; } return MOST_SIGNIFICANT_BITS[bits]; } static bool is_version_up_to_date(PyCodeObject *code, PyInterpreterState *interp) { return interp->monitoring_version == code->_co_instrumentation_version; } #ifndef NDEBUG static bool instrumentation_cross_checks(PyInterpreterState *interp, PyCodeObject *code) { _Py_Monitors expected = monitors_or( interp->monitors, code->_co_monitoring->local_monitors); return monitors_equals(code->_co_monitoring->active_monitors, expected); } #endif static inline uint8_t get_tools_for_instruction(PyCodeObject * code, int i, int event) { uint8_t tools; assert(event != PY_MONITORING_EVENT_LINE); assert(event != PY_MONITORING_EVENT_INSTRUCTION); assert(instrumentation_cross_checks(PyThreadState_GET()->interp, code)); _PyCoMonitoringData *monitoring = code->_co_monitoring; if (event >= PY_MONITORING_UNGROUPED_EVENTS) { assert(event == PY_MONITORING_EVENT_C_RAISE || event == PY_MONITORING_EVENT_C_RETURN); event = PY_MONITORING_EVENT_CALL; } if (event < PY_MONITORING_INSTRUMENTED_EVENTS && monitoring->tools) { tools = monitoring->tools[i]; } else { tools = code->_co_monitoring->active_monitors.tools[event]; } CHECK(tools_is_subset_for_event(code, event, tools)); CHECK((tools & code->_co_monitoring->active_monitors.tools[event]) == tools); return tools; } static int call_instrumentation_vector( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, Py_ssize_t nargs, PyObject *args[]) { if (tstate->tracing) { return 0; } assert(!_PyErr_Occurred(tstate)); assert(args[0] == NULL); PyCodeObject *code = frame->f_code; assert(code->_co_instrumentation_version == tstate->interp->monitoring_version); assert(is_version_up_to_date(code, tstate->interp)); assert(instrumentation_cross_checks(tstate->interp, code)); assert(args[1] == NULL); args[1] = (PyObject *)code; int offset = (int)(instr - _PyCode_CODE(code)); /* Offset visible to user should be the offset in bytes, as that is the * convention for APIs involving code offsets. */ int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT); PyObject *offset_obj = PyLong_FromSsize_t(bytes_offset); if (offset_obj == NULL) { return -1; } assert(args[2] == NULL); args[2] = offset_obj; uint8_t tools = get_tools_for_instruction(code, offset, event); Py_ssize_t nargsf = nargs | PY_VECTORCALL_ARGUMENTS_OFFSET; PyObject **callargs = &args[1]; int err = 0; PyInterpreterState *interp = tstate->interp; while (tools) { int tool = most_significant_bit(tools); assert(tool >= 0 && tool < 8); assert(tools & (1 << tool)); tools ^= (1 << tool); int res = call_one_instrument(interp, tstate, callargs, nargsf, tool, event); if (res == 0) { /* Nothing to do */ } else if (res < 0) { /* error */ err = -1; break; } else { /* DISABLE */ remove_tools(code, offset, event, 1 << tool); } } Py_DECREF(offset_obj); return err; } int _Py_call_instrumentation( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) { PyObject *args[3] = { NULL, NULL, NULL }; return call_instrumentation_vector(tstate, event, frame, instr, 2, args); } int _Py_call_instrumentation_arg( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg) { PyObject *args[4] = { NULL, NULL, NULL, arg }; return call_instrumentation_vector(tstate, event, frame, instr, 3, args); } int _Py_call_instrumentation_2args( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1) { PyObject *args[5] = { NULL, NULL, NULL, arg0, arg1 }; return call_instrumentation_vector(tstate, event, frame, instr, 4, args); } _Py_CODEUNIT * _Py_call_instrumentation_jump( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target) { assert(event == PY_MONITORING_EVENT_JUMP || event == PY_MONITORING_EVENT_BRANCH); assert(frame->prev_instr == instr); /* Event should occur after the jump */ frame->prev_instr = target; PyCodeObject *code = frame->f_code; int to = (int)(target - _PyCode_CODE(code)); PyObject *to_obj = PyLong_FromLong(to * (int)sizeof(_Py_CODEUNIT)); if (to_obj == NULL) { return NULL; } PyObject *args[4] = { NULL, NULL, NULL, to_obj }; int err = call_instrumentation_vector(tstate, event, frame, instr, 3, args); Py_DECREF(to_obj); if (err) { return NULL; } if (frame->prev_instr != target) { /* The callback has caused a jump (by setting the line number) */ return frame->prev_instr; } /* Reset prev_instr for INSTRUMENTED_LINE */ frame->prev_instr = instr; return target; } static void call_instrumentation_vector_protected( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, Py_ssize_t nargs, PyObject *args[]) { assert(_PyErr_Occurred(tstate)); PyObject *exc = _PyErr_GetRaisedException(tstate); int err = call_instrumentation_vector(tstate, event, frame, instr, nargs, args); if (err) { Py_XDECREF(exc); } else { _PyErr_SetRaisedException(tstate, exc); } assert(_PyErr_Occurred(tstate)); } void _Py_call_instrumentation_exc0( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) { assert(_PyErr_Occurred(tstate)); PyObject *args[3] = { NULL, NULL, NULL }; call_instrumentation_vector_protected(tstate, event, frame, instr, 2, args); } void _Py_call_instrumentation_exc2( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1) { assert(_PyErr_Occurred(tstate)); PyObject *args[5] = { NULL, NULL, NULL, arg0, arg1 }; call_instrumentation_vector_protected(tstate, event, frame, instr, 4, args); } int _Py_Instrumentation_GetLine(PyCodeObject *code, int index) { _PyCoMonitoringData *monitoring = code->_co_monitoring; assert(monitoring != NULL); assert(monitoring->lines != NULL); assert(index >= code->_co_firsttraceable); assert(index < Py_SIZE(code)); _PyCoLineInstrumentationData *line_data = &monitoring->lines[index]; int8_t line_delta = line_data->line_delta; int line = compute_line(code, index, line_delta); return line; } int _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev) { frame->prev_instr = instr; PyCodeObject *code = frame->f_code; assert(is_version_up_to_date(code, tstate->interp)); assert(instrumentation_cross_checks(tstate->interp, code)); int i = (int)(instr - _PyCode_CODE(code)); _PyCoMonitoringData *monitoring = code->_co_monitoring; _PyCoLineInstrumentationData *line_data = &monitoring->lines[i]; uint8_t original_opcode = line_data->original_opcode; if (tstate->tracing) { goto done; } PyInterpreterState *interp = tstate->interp; int8_t line_delta = line_data->line_delta; int line = compute_line(code, i, line_delta); assert(line >= 0); int prev_index = (int)(prev - _PyCode_CODE(code)); int prev_line = _Py_Instrumentation_GetLine(code, prev_index); if (prev_line == line) { int prev_opcode = _PyCode_CODE(code)[prev_index].op.code; /* RESUME and INSTRUMENTED_RESUME are needed for the operation of * instrumentation, so must never be hidden by an INSTRUMENTED_LINE. */ if (prev_opcode != RESUME && prev_opcode != INSTRUMENTED_RESUME) { goto done; } } uint8_t tools = code->_co_monitoring->line_tools != NULL ? code->_co_monitoring->line_tools[i] : (interp->monitors.tools[PY_MONITORING_EVENT_LINE] | code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_LINE] ); PyObject *line_obj = PyLong_FromSsize_t(line); if (line_obj == NULL) { return -1; } PyObject *args[3] = { NULL, (PyObject *)code, line_obj }; while (tools) { int tool = most_significant_bit(tools); assert(tool >= 0 && tool < 8); assert(tools & (1 << tool)); tools &= ~(1 << tool); int res = call_one_instrument(interp, tstate, &args[1], 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, tool, PY_MONITORING_EVENT_LINE); if (res == 0) { /* Nothing to do */ } else if (res < 0) { /* error */ Py_DECREF(line_obj); return -1; } else { /* DISABLE */ remove_line_tools(code, i, 1 << tool); } } Py_DECREF(line_obj); done: assert(original_opcode != 0); assert(original_opcode < INSTRUMENTED_LINE); assert(_PyOpcode_Deopt[original_opcode] == original_opcode); return original_opcode; } int _Py_call_instrumentation_instruction(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr) { PyCodeObject *code = frame->f_code; assert(is_version_up_to_date(code, tstate->interp)); assert(instrumentation_cross_checks(tstate->interp, code)); int offset = (int)(instr - _PyCode_CODE(code)); _PyCoMonitoringData *instrumentation_data = code->_co_monitoring; assert(instrumentation_data->per_instruction_opcodes); int next_opcode = instrumentation_data->per_instruction_opcodes[offset]; if (tstate->tracing) { return next_opcode; } PyInterpreterState *interp = tstate->interp; uint8_t tools = instrumentation_data->per_instruction_tools != NULL ? instrumentation_data->per_instruction_tools[offset] : (interp->monitors.tools[PY_MONITORING_EVENT_INSTRUCTION] | code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION] ); int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT); PyObject *offset_obj = PyLong_FromSsize_t(bytes_offset); if (offset_obj == NULL) { return -1; } PyObject *args[3] = { NULL, (PyObject *)code, offset_obj }; while (tools) { int tool = most_significant_bit(tools); assert(tool >= 0 && tool < 8); assert(tools & (1 << tool)); tools &= ~(1 << tool); int res = call_one_instrument(interp, tstate, &args[1], 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, tool, PY_MONITORING_EVENT_INSTRUCTION); if (res == 0) { /* Nothing to do */ } else if (res < 0) { /* error */ Py_DECREF(offset_obj); return -1; } else { /* DISABLE */ remove_per_instruction_tools(code, offset, 1 << tool); } } Py_DECREF(offset_obj); assert(next_opcode != 0); return next_opcode; } PyObject * _PyMonitoring_RegisterCallback(int tool_id, int event_id, PyObject *obj) { PyInterpreterState *is = _PyInterpreterState_Get(); assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); assert(0 <= event_id && event_id < PY_MONITORING_EVENTS); PyObject *callback = is->monitoring_callables[tool_id][event_id]; is->monitoring_callables[tool_id][event_id] = Py_XNewRef(obj); return callback; } static void initialize_tools(PyCodeObject *code) { uint8_t* tools = code->_co_monitoring->tools; assert(tools != NULL); int code_len = (int)Py_SIZE(code); for (int i = 0; i < code_len; i++) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; int opcode = instr->op.code; if (opcode == INSTRUMENTED_LINE) { opcode = code->_co_monitoring->lines[i].original_opcode; } bool instrumented = is_instrumented(opcode); if (instrumented) { opcode = DE_INSTRUMENT[opcode]; assert(opcode != 0); } opcode = _PyOpcode_Deopt[opcode]; if (opcode_has_event(opcode)) { if (instrumented) { int8_t event; if (opcode == RESUME) { event = instr->op.arg != 0; } else { event = EVENT_FOR_OPCODE[opcode]; assert(event > 0); } assert(event >= 0); assert(event < PY_MONITORING_INSTRUMENTED_EVENTS); tools[i] = code->_co_monitoring->active_monitors.tools[event]; CHECK(tools[i] != 0); } else { tools[i] = 0; } } #ifdef Py_DEBUG /* Initialize tools for invalid locations to all ones to try to catch errors */ else { tools[i] = 0xff; } for (int j = 1; j <= _PyOpcode_Caches[opcode]; j++) { tools[i+j] = 0xff; } #endif i += _PyOpcode_Caches[opcode]; } } #define NO_LINE -128 static void initialize_lines(PyCodeObject *code) { _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; assert(line_data != NULL); int code_len = (int)Py_SIZE(code); PyCodeAddressRange range; _PyCode_InitAddressRange(code, &range); for (int i = 0; i < code->_co_firsttraceable && i < code_len; i++) { line_data[i].original_opcode = 0; line_data[i].line_delta = -127; } int current_line = -1; for (int i = code->_co_firsttraceable; i < code_len; ) { int opcode = _Py_GetBaseOpcode(code, i); int line = _PyCode_CheckLineNumber(i*(int)sizeof(_Py_CODEUNIT), &range); line_data[i].line_delta = compute_line_delta(code, i, line); int length = _PyInstruction_GetLength(code, i); switch (opcode) { case END_ASYNC_FOR: case END_FOR: case END_SEND: case RESUME: /* END_FOR cannot start a line, as it is skipped by FOR_ITER * END_SEND cannot start a line, as it is skipped by SEND * RESUME must not be instrumented with INSTRUMENT_LINE */ line_data[i].original_opcode = 0; break; default: /* Set original_opcode to the opcode iff the instruction * starts a line, and thus should be instrumented. * This saves having to perform this check every time the * we turn instrumentation on or off, and serves as a sanity * check when debugging. */ if (line != current_line && line >= 0) { line_data[i].original_opcode = opcode; } else { line_data[i].original_opcode = 0; } current_line = line; } for (int j = 1; j < length; j++) { line_data[i+j].original_opcode = 0; line_data[i+j].line_delta = NO_LINE; } i += length; } for (int i = code->_co_firsttraceable; i < code_len; ) { int opcode = _Py_GetBaseOpcode(code, i); int oparg = 0; while (opcode == EXTENDED_ARG) { oparg = (oparg << 8) | _PyCode_CODE(code)[i].op.arg; i++; opcode = _Py_GetBaseOpcode(code, i); } oparg = (oparg << 8) | _PyCode_CODE(code)[i].op.arg; i += _PyInstruction_GetLength(code, i); int target = -1; switch (opcode) { case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: case POP_JUMP_IF_NONE: case POP_JUMP_IF_NOT_NONE: case JUMP_FORWARD: { target = i + oparg; break; } case FOR_ITER: case SEND: { /* Skip over END_FOR/END_SEND */ target = i + oparg + 1; break; } case JUMP_BACKWARD: case JUMP_BACKWARD_NO_INTERRUPT: { target = i - oparg; break; } default: continue; } assert(target >= 0); if (line_data[target].line_delta != NO_LINE) { line_data[target].original_opcode = _Py_GetBaseOpcode(code, target); } } /* Scan exception table */ unsigned char *start = (unsigned char *)PyBytes_AS_STRING(code->co_exceptiontable); unsigned char *end = start + PyBytes_GET_SIZE(code->co_exceptiontable); unsigned char *scan = start; while (scan < end) { int start_offset, size, handler; scan = parse_varint(scan, &start_offset); assert(start_offset >= 0 && start_offset < code_len); scan = parse_varint(scan, &size); assert(size >= 0 && start_offset+size <= code_len); scan = parse_varint(scan, &handler); assert(handler >= 0 && handler < code_len); int depth_and_lasti; scan = parse_varint(scan, &depth_and_lasti); int original_opcode = _Py_GetBaseOpcode(code, handler); /* Skip if not the start of a line. * END_ASYNC_FOR is a bit special as it marks the end of * an `async for` loop, which should not generate its own * line event. */ if (line_data[handler].line_delta != NO_LINE && original_opcode != END_ASYNC_FOR) { line_data[handler].original_opcode = original_opcode; } } } static void initialize_line_tools(PyCodeObject *code, _Py_Monitors *all_events) { uint8_t *line_tools = code->_co_monitoring->line_tools; assert(line_tools != NULL); int code_len = (int)Py_SIZE(code); for (int i = 0; i < code_len; i++) { line_tools[i] = all_events->tools[PY_MONITORING_EVENT_LINE]; } } static int allocate_instrumentation_data(PyCodeObject *code) { if (code->_co_monitoring == NULL) { code->_co_monitoring = PyMem_Malloc(sizeof(_PyCoMonitoringData)); if (code->_co_monitoring == NULL) { PyErr_NoMemory(); return -1; } code->_co_monitoring->local_monitors = (_Py_Monitors){ 0 }; code->_co_monitoring->active_monitors = (_Py_Monitors){ 0 }; code->_co_monitoring->tools = NULL; code->_co_monitoring->lines = NULL; code->_co_monitoring->line_tools = NULL; code->_co_monitoring->per_instruction_opcodes = NULL; code->_co_monitoring->per_instruction_tools = NULL; } return 0; } static int update_instrumentation_data(PyCodeObject *code, PyInterpreterState *interp) { int code_len = (int)Py_SIZE(code); if (allocate_instrumentation_data(code)) { return -1; } _Py_Monitors all_events = monitors_or( interp->monitors, code->_co_monitoring->local_monitors); bool multitools = multiple_tools(&all_events); if (code->_co_monitoring->tools == NULL && multitools) { code->_co_monitoring->tools = PyMem_Malloc(code_len); if (code->_co_monitoring->tools == NULL) { PyErr_NoMemory(); return -1; } initialize_tools(code); } if (all_events.tools[PY_MONITORING_EVENT_LINE]) { if (code->_co_monitoring->lines == NULL) { code->_co_monitoring->lines = PyMem_Malloc(code_len * sizeof(_PyCoLineInstrumentationData)); if (code->_co_monitoring->lines == NULL) { PyErr_NoMemory(); return -1; } initialize_lines(code); } if (multitools && code->_co_monitoring->line_tools == NULL) { code->_co_monitoring->line_tools = PyMem_Malloc(code_len); if (code->_co_monitoring->line_tools == NULL) { PyErr_NoMemory(); return -1; } initialize_line_tools(code, &all_events); } } if (all_events.tools[PY_MONITORING_EVENT_INSTRUCTION]) { if (code->_co_monitoring->per_instruction_opcodes == NULL) { code->_co_monitoring->per_instruction_opcodes = PyMem_Malloc(code_len * sizeof(_PyCoLineInstrumentationData)); if (code->_co_monitoring->per_instruction_opcodes == NULL) { PyErr_NoMemory(); return -1; } /* This may not be necessary, as we can initialize this memory lazily, but it helps catch errors. */ for (int i = 0; i < code_len; i++) { code->_co_monitoring->per_instruction_opcodes[i] = 0; } } if (multitools && code->_co_monitoring->per_instruction_tools == NULL) { code->_co_monitoring->per_instruction_tools = PyMem_Malloc(code_len); if (code->_co_monitoring->per_instruction_tools == NULL) { PyErr_NoMemory(); return -1; } /* This may not be necessary, as we can initialize this memory lazily, but it helps catch errors. */ for (int i = 0; i < code_len; i++) { code->_co_monitoring->per_instruction_tools[i] = 0; } } } return 0; } static const uint8_t super_instructions[256] = { [LOAD_FAST__LOAD_CONST] = 1, [LOAD_CONST__LOAD_FAST] = 1, }; /* Should use instruction metadata for this */ static bool is_super_instruction(uint8_t opcode) { return super_instructions[opcode] != 0; } int _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp) { if (is_version_up_to_date(code, interp)) { assert( interp->monitoring_version == 0 || instrumentation_cross_checks(interp, code) ); return 0; } int code_len = (int)Py_SIZE(code); if (update_instrumentation_data(code, interp)) { return -1; } _Py_Monitors active_events = monitors_or( interp->monitors, code->_co_monitoring->local_monitors); _Py_Monitors new_events; _Py_Monitors removed_events; bool restarted = interp->last_restart_version > code->_co_instrumentation_version; if (restarted) { removed_events = code->_co_monitoring->active_monitors; new_events = active_events; } else { removed_events = monitors_sub(code->_co_monitoring->active_monitors, active_events); new_events = monitors_sub(active_events, code->_co_monitoring->active_monitors); assert(monitors_are_empty(monitors_and(new_events, removed_events))); } code->_co_monitoring->active_monitors = active_events; code->_co_instrumentation_version = interp->monitoring_version; if (monitors_are_empty(new_events) && monitors_are_empty(removed_events)) { #ifdef INSTRUMENT_DEBUG sanity_check_instrumentation(code); #endif return 0; } /* Insert instrumentation */ for (int i = 0; i < code_len; i+= _PyInstruction_GetLength(code, i)) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; if (is_super_instruction(instr->op.code)) { instr->op.code = _PyOpcode_Deopt[instr->op.code]; } CHECK(instr->op.code != 0); int base_opcode = _Py_GetBaseOpcode(code, i); if (opcode_has_event(base_opcode)) { int8_t event; if (base_opcode == RESUME) { event = instr->op.arg > 0; } else { event = EVENT_FOR_OPCODE[base_opcode]; assert(event > 0); } uint8_t removed_tools = removed_events.tools[event]; if (removed_tools) { remove_tools(code, i, event, removed_tools); } uint8_t new_tools = new_events.tools[event]; if (new_tools) { add_tools(code, i, event, new_tools); } } } // GH-103845: We need to remove both the line and instruction instrumentation before // adding new ones, otherwise we may remove the newly added instrumentation. uint8_t removed_line_tools = removed_events.tools[PY_MONITORING_EVENT_LINE]; uint8_t removed_per_instruction_tools = removed_events.tools[PY_MONITORING_EVENT_INSTRUCTION]; if (removed_line_tools) { _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; for (int i = code->_co_firsttraceable; i < code_len;) { if (line_data[i].original_opcode) { if (removed_line_tools) { remove_line_tools(code, i, removed_line_tools); } } i += _PyInstruction_GetLength(code, i); } } if (removed_per_instruction_tools) { for (int i = code->_co_firsttraceable; i < code_len;) { int opcode = _Py_GetBaseOpcode(code, i); if (opcode == RESUME || opcode == END_FOR) { i += _PyInstruction_GetLength(code, i); continue; } if (removed_per_instruction_tools) { remove_per_instruction_tools(code, i, removed_per_instruction_tools); } i += _PyInstruction_GetLength(code, i); } } uint8_t new_line_tools = new_events.tools[PY_MONITORING_EVENT_LINE]; uint8_t new_per_instruction_tools = new_events.tools[PY_MONITORING_EVENT_INSTRUCTION]; if (new_line_tools) { _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; for (int i = code->_co_firsttraceable; i < code_len;) { if (line_data[i].original_opcode) { if (new_line_tools) { add_line_tools(code, i, new_line_tools); } } i += _PyInstruction_GetLength(code, i); } } if (new_per_instruction_tools) { for (int i = code->_co_firsttraceable; i < code_len;) { int opcode = _Py_GetBaseOpcode(code, i); if (opcode == RESUME || opcode == END_FOR) { i += _PyInstruction_GetLength(code, i); continue; } if (new_per_instruction_tools) { add_per_instruction_tools(code, i, new_per_instruction_tools); } i += _PyInstruction_GetLength(code, i); } } #ifdef INSTRUMENT_DEBUG sanity_check_instrumentation(code); #endif return 0; } #define C_RETURN_EVENTS \ ((1 << PY_MONITORING_EVENT_C_RETURN) | \ (1 << PY_MONITORING_EVENT_C_RAISE)) #define C_CALL_EVENTS \ (C_RETURN_EVENTS | (1 << PY_MONITORING_EVENT_CALL)) static int instrument_all_executing_code_objects(PyInterpreterState *interp) { _PyRuntimeState *runtime = &_PyRuntime; HEAD_LOCK(runtime); PyThreadState* ts = PyInterpreterState_ThreadHead(interp); HEAD_UNLOCK(runtime); while (ts) { _PyInterpreterFrame *frame = ts->cframe->current_frame; while (frame) { if (frame->owner != FRAME_OWNED_BY_CSTACK) { if (_Py_Instrument(frame->f_code, interp)) { return -1; } } frame = frame->previous; } HEAD_LOCK(runtime); ts = PyThreadState_Next(ts); HEAD_UNLOCK(runtime); } return 0; } static void set_events(_Py_Monitors *m, int tool_id, _PyMonitoringEventSet events) { assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) { uint8_t *tools = &m->tools[e]; int val = (events >> e) & 1; *tools &= ~(1 << tool_id); *tools |= (val << tool_id); } } static int check_tool(PyInterpreterState *interp, int tool_id) { if (tool_id < PY_MONITORING_SYS_PROFILE_ID && interp->monitoring_tool_names[tool_id] == NULL) { PyErr_Format(PyExc_ValueError, "tool %d is not in use", tool_id); return -1; } return 0; } int _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events) { assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); PyInterpreterState *interp = _PyInterpreterState_Get(); assert(events < (1 << PY_MONITORING_UNGROUPED_EVENTS)); if (check_tool(interp, tool_id)) { return -1; } uint32_t existing_events = get_events(&interp->monitors, tool_id); if (existing_events == events) { return 0; } set_events(&interp->monitors, tool_id, events); interp->monitoring_version++; return instrument_all_executing_code_objects(interp); } int _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet events) { assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); PyInterpreterState *interp = _PyInterpreterState_Get(); assert(events < (1 << PY_MONITORING_UNGROUPED_EVENTS)); if (check_tool(interp, tool_id)) { return -1; } if (allocate_instrumentation_data(code)) { return -1; } _Py_Monitors *local = &code->_co_monitoring->local_monitors; uint32_t existing_events = get_events(local, tool_id); if (existing_events == events) { return 0; } set_events(local, tool_id, events); if (is_version_up_to_date(code, interp)) { /* Force instrumentation update */ code->_co_instrumentation_version = UINT64_MAX; } if (_Py_Instrument(code, interp)) { return -1; } return 0; } /*[clinic input] module monitoring [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=37257f5987a360cf]*/ /*[clinic end generated code]*/ #include "clinic/instrumentation.c.h" static int check_valid_tool(int tool_id) { if (tool_id < 0 || tool_id >= PY_MONITORING_SYS_PROFILE_ID) { PyErr_Format(PyExc_ValueError, "invalid tool %d (must be between 0 and 5)", tool_id); return -1; } return 0; } /*[clinic input] monitoring.use_tool_id tool_id: int name: object / [clinic start generated code]*/ static PyObject * monitoring_use_tool_id_impl(PyObject *module, int tool_id, PyObject *name) /*[clinic end generated code: output=30d76dc92b7cd653 input=ebc453761c621be1]*/ { if (check_valid_tool(tool_id)) { return NULL; } if (!PyUnicode_Check(name)) { PyErr_SetString(PyExc_ValueError, "tool name must be a str"); return NULL; } PyInterpreterState *interp = _PyInterpreterState_Get(); if (interp->monitoring_tool_names[tool_id] != NULL) { PyErr_Format(PyExc_ValueError, "tool %d is already in use", tool_id); return NULL; } interp->monitoring_tool_names[tool_id] = Py_NewRef(name); Py_RETURN_NONE; } /*[clinic input] monitoring.free_tool_id tool_id: int / [clinic start generated code]*/ static PyObject * monitoring_free_tool_id_impl(PyObject *module, int tool_id) /*[clinic end generated code: output=86c2d2a1219a8591 input=a23fb6be3a8618e9]*/ { if (check_valid_tool(tool_id)) { return NULL; } PyInterpreterState *interp = _PyInterpreterState_Get(); Py_CLEAR(interp->monitoring_tool_names[tool_id]); Py_RETURN_NONE; } /*[clinic input] monitoring.get_tool tool_id: int / [clinic start generated code]*/ static PyObject * monitoring_get_tool_impl(PyObject *module, int tool_id) /*[clinic end generated code: output=1c05a98b404a9a16 input=eeee9bebd0bcae9d]*/ /*[clinic end generated code]*/ { if (check_valid_tool(tool_id)) { return NULL; } PyInterpreterState *interp = _PyInterpreterState_Get(); PyObject *name = interp->monitoring_tool_names[tool_id]; if (name == NULL) { Py_RETURN_NONE; } return Py_NewRef(name); } /*[clinic input] monitoring.register_callback tool_id: int event: int func: object / [clinic start generated code]*/ static PyObject * monitoring_register_callback_impl(PyObject *module, int tool_id, int event, PyObject *func) /*[clinic end generated code: output=e64daa363004030c input=df6d70ea4cf81007]*/ { if (check_valid_tool(tool_id)) { return NULL; } if (_Py_popcount32(event) != 1) { PyErr_SetString(PyExc_ValueError, "The callback can only be set for one event at a time"); return NULL; } int event_id = _Py_bit_length(event)-1; if (event_id < 0 || event_id >= PY_MONITORING_EVENTS) { PyErr_Format(PyExc_ValueError, "invalid event %d", event); return NULL; } if (func == Py_None) { func = NULL; } func = _PyMonitoring_RegisterCallback(tool_id, event_id, func); if (func == NULL) { Py_RETURN_NONE; } return func; } /*[clinic input] monitoring.get_events -> int tool_id: int / [clinic start generated code]*/ static int monitoring_get_events_impl(PyObject *module, int tool_id) /*[clinic end generated code: output=4450cc13f826c8c0 input=a64b238f76c4b2f7]*/ { if (check_valid_tool(tool_id)) { return -1; } _Py_Monitors *m = &_PyInterpreterState_Get()->monitors; _PyMonitoringEventSet event_set = get_events(m, tool_id); return event_set; } /*[clinic input] monitoring.set_events tool_id: int event_set: int / [clinic start generated code]*/ static PyObject * monitoring_set_events_impl(PyObject *module, int tool_id, int event_set) /*[clinic end generated code: output=1916c1e49cfb5bdb input=a77ba729a242142b]*/ { if (check_valid_tool(tool_id)) { return NULL; } if (event_set < 0 || event_set >= (1 << PY_MONITORING_EVENTS)) { PyErr_Format(PyExc_ValueError, "invalid event set 0x%x", event_set); return NULL; } if ((event_set & C_RETURN_EVENTS) && (event_set & C_CALL_EVENTS) != C_CALL_EVENTS) { PyErr_Format(PyExc_ValueError, "cannot set C_RETURN or C_RAISE events independently"); return NULL; } event_set &= ~C_RETURN_EVENTS; if (_PyMonitoring_SetEvents(tool_id, event_set)) { return NULL; } Py_RETURN_NONE; } /*[clinic input] monitoring.get_local_events -> int tool_id: int code: object / [clinic start generated code]*/ static int monitoring_get_local_events_impl(PyObject *module, int tool_id, PyObject *code) /*[clinic end generated code: output=d3e92c1c9c1de8f9 input=bb0f927530386a94]*/ { if (!PyCode_Check(code)) { PyErr_Format( PyExc_TypeError, "code must be a code object" ); return -1; } if (check_valid_tool(tool_id)) { return -1; } _PyMonitoringEventSet event_set = 0; _PyCoMonitoringData *data = ((PyCodeObject *)code)->_co_monitoring; if (data != NULL) { for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) { if ((data->local_monitors.tools[e] >> tool_id) & 1) { event_set |= (1 << e); } } } return event_set; } /*[clinic input] monitoring.set_local_events tool_id: int code: object event_set: int / [clinic start generated code]*/ static PyObject * monitoring_set_local_events_impl(PyObject *module, int tool_id, PyObject *code, int event_set) /*[clinic end generated code: output=68cc755a65dfea99 input=5655ecd78d937a29]*/ { if (!PyCode_Check(code)) { PyErr_Format( PyExc_TypeError, "code must be a code object" ); return NULL; } if (check_valid_tool(tool_id)) { return NULL; } if (event_set < 0 || event_set >= (1 << PY_MONITORING_EVENTS)) { PyErr_Format(PyExc_ValueError, "invalid event set 0x%x", event_set); return NULL; } if ((event_set & C_RETURN_EVENTS) && (event_set & C_CALL_EVENTS) != C_CALL_EVENTS) { PyErr_Format(PyExc_ValueError, "cannot set C_RETURN or C_RAISE events independently"); return NULL; } event_set &= ~C_RETURN_EVENTS; if (_PyMonitoring_SetLocalEvents((PyCodeObject*)code, tool_id, event_set)) { return NULL; } Py_RETURN_NONE; } /*[clinic input] monitoring.restart_events [clinic start generated code]*/ static PyObject * monitoring_restart_events_impl(PyObject *module) /*[clinic end generated code: output=e025dd5ba33314c4 input=add8a855063c8008]*/ { /* We want to ensure that: * last restart version > instrumented version for all code objects * last restart version < current version */ PyInterpreterState *interp = _PyInterpreterState_Get(); interp->last_restart_version = interp->monitoring_version + 1; interp->monitoring_version = interp->last_restart_version + 1; if (instrument_all_executing_code_objects(interp)) { return NULL; } Py_RETURN_NONE; } static int add_power2_constant(PyObject *obj, const char *name, int i) { PyObject *val = PyLong_FromLong(1<monitors.tools[e]; if (tools == 0) { continue; } PyObject *tools_obj = PyLong_FromLong(tools); assert(tools_obj != NULL); int err = PyDict_SetItemString(res, event_names[e], tools_obj); Py_DECREF(tools_obj); if (err < 0) { Py_DECREF(res); return NULL; } } return res; } static PyMethodDef methods[] = { MONITORING_USE_TOOL_ID_METHODDEF MONITORING_FREE_TOOL_ID_METHODDEF MONITORING_GET_TOOL_METHODDEF MONITORING_REGISTER_CALLBACK_METHODDEF MONITORING_GET_EVENTS_METHODDEF MONITORING_SET_EVENTS_METHODDEF MONITORING_GET_LOCAL_EVENTS_METHODDEF MONITORING_SET_LOCAL_EVENTS_METHODDEF MONITORING_RESTART_EVENTS_METHODDEF MONITORING__ALL_EVENTS_METHODDEF {NULL, NULL} // sentinel }; static struct PyModuleDef monitoring_module = { PyModuleDef_HEAD_INIT, .m_name = "sys.monitoring", .m_size = -1, /* multiple "initialization" just copies the module dict. */ .m_methods = methods, }; PyObject *_Py_CreateMonitoringObject(void) { PyObject *mod = _PyModule_CreateInitialized(&monitoring_module, PYTHON_API_VERSION); if (mod == NULL) { return NULL; } if (PyObject_SetAttrString(mod, "DISABLE", &_PyInstrumentation_DISABLE)) { goto error; } if (PyObject_SetAttrString(mod, "MISSING", &_PyInstrumentation_MISSING)) { goto error; } PyObject *events = _PyNamespace_New(NULL); if (events == NULL) { goto error; } int err = PyObject_SetAttrString(mod, "events", events); Py_DECREF(events); if (err) { goto error; } for (int i = 0; i < PY_MONITORING_EVENTS; i++) { if (add_power2_constant(events, event_names[i], i)) { goto error; } } err = PyObject_SetAttrString(events, "NO_EVENTS", _PyLong_GetZero()); if (err) goto error; PyObject *val = PyLong_FromLong(PY_MONITORING_DEBUGGER_ID); err = PyObject_SetAttrString(mod, "DEBUGGER_ID", val); Py_DECREF(val); if (err) goto error; val = PyLong_FromLong(PY_MONITORING_COVERAGE_ID); err = PyObject_SetAttrString(mod, "COVERAGE_ID", val); Py_DECREF(val); if (err) goto error; val = PyLong_FromLong(PY_MONITORING_PROFILER_ID); err = PyObject_SetAttrString(mod, "PROFILER_ID", val); Py_DECREF(val); if (err) goto error; val = PyLong_FromLong(PY_MONITORING_OPTIMIZER_ID); err = PyObject_SetAttrString(mod, "OPTIMIZER_ID", val); Py_DECREF(val); if (err) goto error; return mod; error: Py_DECREF(mod); return NULL; } ================================================ FILE: Legacy_Tracing.c ================================================ /* Support for legacy tracing on top of PEP 669 instrumentation * Provides callables to forward PEP 669 events to legacy events. */ #include #include "Python.h" #include "opcode.h" #include "pycore_ceval.h" #include "pycore_object.h" #include "pycore_sysmodule.h" typedef struct _PyLegacyEventHandler { PyObject_HEAD vectorcallfunc vectorcall; int event; } _PyLegacyEventHandler; /* The Py_tracefunc function expects the following arguments: * obj: the trace object (PyObject *) * frame: the current frame (PyFrameObject *) * kind: the kind of event, see PyTrace_XXX #defines (int) * arg: The arg (a PyObject *) */ static PyObject * call_profile_func(_PyLegacyEventHandler *self, PyObject *arg) { PyThreadState *tstate = _PyThreadState_GET(); if (tstate->c_profilefunc == NULL) { Py_RETURN_NONE; } PyFrameObject *frame = PyEval_GetFrame(); if (frame == NULL) { PyErr_SetString(PyExc_SystemError, "Missing frame when calling profile function."); return NULL; } Py_INCREF(frame); int err = tstate->c_profilefunc(tstate->c_profileobj, frame, self->event, arg); Py_DECREF(frame); if (err) { return NULL; } Py_RETURN_NONE; } static PyObject * sys_profile_func2( _PyLegacyEventHandler *self, PyObject *const *args, size_t nargsf, PyObject *kwnames ) { assert(kwnames == NULL); assert(PyVectorcall_NARGS(nargsf) == 2); return call_profile_func(self, Py_None); } static PyObject * sys_profile_func3( _PyLegacyEventHandler *self, PyObject *const *args, size_t nargsf, PyObject *kwnames ) { assert(kwnames == NULL); assert(PyVectorcall_NARGS(nargsf) == 3); return call_profile_func(self, args[2]); } static PyObject * sys_profile_call_or_return( _PyLegacyEventHandler *self, PyObject *const *args, size_t nargsf, PyObject *kwnames ) { assert(kwnames == NULL); assert(PyVectorcall_NARGS(nargsf) == 4); PyObject *callable = args[2]; if (PyCFunction_Check(callable)) { return call_profile_func(self, callable); } if (Py_TYPE(callable) == &PyMethodDescr_Type) { PyObject *self_arg = args[3]; /* For backwards compatibility need to * convert to builtin method */ /* If no arg, skip */ if (self_arg == &_PyInstrumentation_MISSING) { Py_RETURN_NONE; } PyObject *meth = Py_TYPE(callable)->tp_descr_get( callable, self_arg, (PyObject*)Py_TYPE(self_arg)); if (meth == NULL) { return NULL; } PyObject *res = call_profile_func(self, meth); Py_DECREF(meth); return res; } Py_RETURN_NONE; } static PyObject * call_trace_func(_PyLegacyEventHandler *self, PyObject *arg) { PyThreadState *tstate = _PyThreadState_GET(); if (tstate->c_tracefunc == NULL) { Py_RETURN_NONE; } PyFrameObject *frame = PyEval_GetFrame(); if (frame == NULL) { PyErr_SetString(PyExc_SystemError, "Missing frame when calling trace function."); return NULL; } Py_INCREF(frame); int err = tstate->c_tracefunc(tstate->c_traceobj, frame, self->event, arg); Py_DECREF(frame); if (err) { return NULL; } Py_RETURN_NONE; } static PyObject * sys_trace_exception_func( _PyLegacyEventHandler *self, PyObject *const *args, size_t nargsf, PyObject *kwnames ) { assert(kwnames == NULL); assert(PyVectorcall_NARGS(nargsf) == 3); PyObject *exc = args[2]; assert(PyExceptionInstance_Check(exc)); PyObject *type = (PyObject *)Py_TYPE(exc); PyObject *tb = PyException_GetTraceback(exc); if (tb == NULL) { tb = Py_NewRef(Py_None); } PyObject *tuple = PyTuple_Pack(3, type, exc, tb); Py_DECREF(tb); if (tuple == NULL) { return NULL; } PyObject *res = call_trace_func(self, tuple); Py_DECREF(tuple); return res; } static PyObject * sys_trace_func2( _PyLegacyEventHandler *self, PyObject *const *args, size_t nargsf, PyObject *kwnames ) { assert(kwnames == NULL); assert(PyVectorcall_NARGS(nargsf) == 2); return call_trace_func(self, Py_None); } static PyObject * sys_trace_return( _PyLegacyEventHandler *self, PyObject *const *args, size_t nargsf, PyObject *kwnames ) { assert(!PyErr_Occurred()); assert(kwnames == NULL); assert(PyVectorcall_NARGS(nargsf) == 3); assert(PyCode_Check(args[0])); PyObject *val = args[2]; PyObject *res = call_trace_func(self, val); return res; } static PyObject * sys_trace_yield( _PyLegacyEventHandler *self, PyObject *const *args, size_t nargsf, PyObject *kwnames ) { assert(kwnames == NULL); assert(PyVectorcall_NARGS(nargsf) == 3); return call_trace_func(self, args[2]); } static PyObject * sys_trace_instruction_func( _PyLegacyEventHandler *self, PyObject *const *args, size_t nargsf, PyObject *kwnames ) { assert(kwnames == NULL); assert(PyVectorcall_NARGS(nargsf) == 2); PyFrameObject *frame = PyEval_GetFrame(); if (frame == NULL) { PyErr_SetString(PyExc_SystemError, "Missing frame when calling trace function."); return NULL; } if (!frame->f_trace_opcodes) { Py_RETURN_NONE; } Py_INCREF(frame); PyThreadState *tstate = _PyThreadState_GET(); int err = tstate->c_tracefunc(tstate->c_traceobj, frame, self->event, Py_None); frame->f_lineno = 0; Py_DECREF(frame); if (err) { return NULL; } Py_RETURN_NONE; } static PyObject * trace_line( PyThreadState *tstate, _PyLegacyEventHandler *self, PyFrameObject *frame, int line ) { if (!frame->f_trace_lines) { Py_RETURN_NONE; } if (line < 0) { Py_RETURN_NONE; } Py_INCREF(frame); frame->f_lineno = line; int err = tstate->c_tracefunc(tstate->c_traceobj, frame, self->event, Py_None); frame->f_lineno = 0; Py_DECREF(frame); if (err) { return NULL; } Py_RETURN_NONE; } static PyObject * sys_trace_line_func( _PyLegacyEventHandler *self, PyObject *const *args, size_t nargsf, PyObject *kwnames ) { assert(kwnames == NULL); PyThreadState *tstate = _PyThreadState_GET(); if (tstate->c_tracefunc == NULL) { Py_RETURN_NONE; } assert(PyVectorcall_NARGS(nargsf) == 2); int line = _PyLong_AsInt(args[1]); assert(line >= 0); PyFrameObject *frame = PyEval_GetFrame(); if (frame == NULL) { PyErr_SetString(PyExc_SystemError, "Missing frame when calling trace function."); return NULL; } assert(args[0] == (PyObject *)frame->f_frame->f_code); return trace_line(tstate, self, frame, line); } /* sys.settrace generates line events for all backward * edges, even if on the same line. * Handle that case here */ static PyObject * sys_trace_jump_func( _PyLegacyEventHandler *self, PyObject *const *args, size_t nargsf, PyObject *kwnames ) { assert(kwnames == NULL); PyThreadState *tstate = _PyThreadState_GET(); if (tstate->c_tracefunc == NULL) { Py_RETURN_NONE; } assert(PyVectorcall_NARGS(nargsf) == 3); int from = _PyLong_AsInt(args[1])/sizeof(_Py_CODEUNIT); assert(from >= 0); int to = _PyLong_AsInt(args[2])/sizeof(_Py_CODEUNIT); assert(to >= 0); if (to > from) { /* Forward jump */ return &_PyInstrumentation_DISABLE; } PyCodeObject *code = (PyCodeObject *)args[0]; assert(PyCode_Check(code)); /* We can call _Py_Instrumentation_GetLine because we always set * line events for tracing */ int to_line = _Py_Instrumentation_GetLine(code, to); int from_line = _Py_Instrumentation_GetLine(code, from); if (to_line != from_line) { /* Will be handled by target INSTRUMENTED_LINE */ return &_PyInstrumentation_DISABLE; } PyFrameObject *frame = PyEval_GetFrame(); if (frame == NULL) { PyErr_SetString(PyExc_SystemError, "Missing frame when calling trace function."); return NULL; } assert(code == frame->f_frame->f_code); if (!frame->f_trace_lines) { Py_RETURN_NONE; } return trace_line(tstate, self, frame, to_line); } PyTypeObject _PyLegacyEventHandler_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "sys.legacy_event_handler", sizeof(_PyLegacyEventHandler), .tp_dealloc = (destructor)PyObject_Free, .tp_vectorcall_offset = offsetof(_PyLegacyEventHandler, vectorcall), .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_DISALLOW_INSTANTIATION, .tp_call = PyVectorcall_Call, }; static int set_callbacks(int tool, vectorcallfunc vectorcall, int legacy_event, int event1, int event2) { _PyLegacyEventHandler *callback = PyObject_NEW(_PyLegacyEventHandler, &_PyLegacyEventHandler_Type); if (callback == NULL) { return -1; } callback->vectorcall = vectorcall; callback->event = legacy_event; Py_XDECREF(_PyMonitoring_RegisterCallback(tool, event1, (PyObject *)callback)); if (event2 >= 0) { Py_XDECREF(_PyMonitoring_RegisterCallback(tool, event2, (PyObject *)callback)); } Py_DECREF(callback); return 0; } #ifndef NDEBUG /* Ensure that tstate is valid: sanity check for PyEval_AcquireThread() and PyEval_RestoreThread(). Detect if tstate memory was freed. It can happen when a thread continues to run after Python finalization, especially daemon threads. */ static int is_tstate_valid(PyThreadState *tstate) { assert(!_PyMem_IsPtrFreed(tstate)); assert(!_PyMem_IsPtrFreed(tstate->interp)); return 1; } #endif int _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) { assert(is_tstate_valid(tstate)); /* The caller must hold the GIL */ assert(PyGILState_Check()); /* Call _PySys_Audit() in the context of the current thread state, even if tstate is not the current thread state. */ PyThreadState *current_tstate = _PyThreadState_GET(); if (_PySys_Audit(current_tstate, "sys.setprofile", NULL) < 0) { return -1; } /* Setup PEP 669 monitoring callbacks and events. */ if (!tstate->interp->sys_profile_initialized) { tstate->interp->sys_profile_initialized = true; if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, (vectorcallfunc)sys_profile_func2, PyTrace_CALL, PY_MONITORING_EVENT_PY_START, PY_MONITORING_EVENT_PY_RESUME)) { return -1; } if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, (vectorcallfunc)sys_profile_func3, PyTrace_RETURN, PY_MONITORING_EVENT_PY_RETURN, PY_MONITORING_EVENT_PY_YIELD)) { return -1; } if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, (vectorcallfunc)sys_profile_func2, PyTrace_RETURN, PY_MONITORING_EVENT_PY_UNWIND, -1)) { return -1; } if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, (vectorcallfunc)sys_profile_call_or_return, PyTrace_C_CALL, PY_MONITORING_EVENT_CALL, -1)) { return -1; } if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, (vectorcallfunc)sys_profile_call_or_return, PyTrace_C_RETURN, PY_MONITORING_EVENT_C_RETURN, -1)) { return -1; } if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, (vectorcallfunc)sys_profile_call_or_return, PyTrace_C_EXCEPTION, PY_MONITORING_EVENT_C_RAISE, -1)) { return -1; } } int delta = (func != NULL) - (tstate->c_profilefunc != NULL); tstate->c_profilefunc = func; PyObject *old_profileobj = tstate->c_profileobj; tstate->c_profileobj = Py_XNewRef(arg); Py_XDECREF(old_profileobj); tstate->interp->sys_profiling_threads += delta; assert(tstate->interp->sys_profiling_threads >= 0); uint32_t events = 0; if (tstate->interp->sys_profiling_threads) { events = (1 << PY_MONITORING_EVENT_PY_START) | (1 << PY_MONITORING_EVENT_PY_RESUME) | (1 << PY_MONITORING_EVENT_PY_RETURN) | (1 << PY_MONITORING_EVENT_PY_YIELD) | (1 << PY_MONITORING_EVENT_CALL) | (1 << PY_MONITORING_EVENT_PY_UNWIND); } return _PyMonitoring_SetEvents(PY_MONITORING_SYS_PROFILE_ID, events); } int _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) { assert(is_tstate_valid(tstate)); /* The caller must hold the GIL */ assert(PyGILState_Check()); /* Call _PySys_Audit() in the context of the current thread state, even if tstate is not the current thread state. */ PyThreadState *current_tstate = _PyThreadState_GET(); if (_PySys_Audit(current_tstate, "sys.settrace", NULL) < 0) { return -1; } assert(tstate->interp->sys_tracing_threads >= 0); /* Setup PEP 669 monitoring callbacks and events. */ if (!tstate->interp->sys_trace_initialized) { tstate->interp->sys_trace_initialized = true; if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, (vectorcallfunc)sys_trace_func2, PyTrace_CALL, PY_MONITORING_EVENT_PY_START, PY_MONITORING_EVENT_PY_RESUME)) { return -1; } if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, (vectorcallfunc)sys_trace_func2, PyTrace_CALL, PY_MONITORING_EVENT_PY_THROW, -1)) { return -1; } if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, (vectorcallfunc)sys_trace_return, PyTrace_RETURN, PY_MONITORING_EVENT_PY_RETURN, -1)) { return -1; } if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, (vectorcallfunc)sys_trace_yield, PyTrace_RETURN, PY_MONITORING_EVENT_PY_YIELD, -1)) { return -1; } if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, (vectorcallfunc)sys_trace_exception_func, PyTrace_EXCEPTION, PY_MONITORING_EVENT_RAISE, PY_MONITORING_EVENT_STOP_ITERATION)) { return -1; } if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, (vectorcallfunc)sys_trace_line_func, PyTrace_LINE, PY_MONITORING_EVENT_LINE, -1)) { return -1; } if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, (vectorcallfunc)sys_trace_func2, PyTrace_RETURN, PY_MONITORING_EVENT_PY_UNWIND, -1)) { return -1; } if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, (vectorcallfunc)sys_trace_jump_func, PyTrace_LINE, PY_MONITORING_EVENT_JUMP, -1)) { return -1; } if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, (vectorcallfunc)sys_trace_instruction_func, PyTrace_OPCODE, PY_MONITORING_EVENT_INSTRUCTION, -1)) { return -1; } } int delta = (func != NULL) - (tstate->c_tracefunc != NULL); tstate->c_tracefunc = func; PyObject *old_traceobj = tstate->c_traceobj; tstate->c_traceobj = Py_XNewRef(arg); Py_XDECREF(old_traceobj); tstate->interp->sys_tracing_threads += delta; assert(tstate->interp->sys_tracing_threads >= 0); uint32_t events = 0; if (tstate->interp->sys_tracing_threads) { events = (1 << PY_MONITORING_EVENT_PY_START) | (1 << PY_MONITORING_EVENT_PY_RESUME) | (1 << PY_MONITORING_EVENT_PY_RETURN) | (1 << PY_MONITORING_EVENT_PY_YIELD) | (1 << PY_MONITORING_EVENT_RAISE) | (1 << PY_MONITORING_EVENT_LINE) | (1 << PY_MONITORING_EVENT_JUMP) | (1 << PY_MONITORING_EVENT_BRANCH) | (1 << PY_MONITORING_EVENT_PY_UNWIND) | (1 << PY_MONITORING_EVENT_PY_THROW) | (1 << PY_MONITORING_EVENT_STOP_ITERATION) | (1 << PY_MONITORING_EVENT_EXCEPTION_HANDLED); if (tstate->interp->f_opcode_trace_set) { events |= (1 << PY_MONITORING_EVENT_INSTRUCTION); } } return _PyMonitoring_SetEvents(PY_MONITORING_SYS_TRACE_ID, events); } ================================================ FILE: MakeOpCodeTargets.py ================================================ #! /usr/bin/env python """Generate C code for the jump table of the threaded code interpreter (for compilers supporting computed gotos or "labels-as-values", such as gcc). """ import os import sys # 2023-04-27(warsaw): Pre-Python 3.12, this would catch ImportErrors and try to # import imp, and then use imp.load_module(). The imp module was removed in # Python 3.12 (and long deprecated before that), and it's unclear under what # conditions this import will now fail, so the fallback was simply removed. from importlib.machinery import SourceFileLoader def find_module(modname): """Finds and returns a module in the local dist/checkout. """ modpath = os.path.join( os.path.dirname(os.path.dirname(__file__)), "Lib", modname + ".py") return SourceFileLoader(modname, modpath).load_module() def write_contents(f): """Write C code contents to the target file object. """ opcode = find_module('opcode') targets = ['_unknown_opcode'] * 256 for opname, op in opcode.opmap.items(): if not opcode.is_pseudo(op): targets[op] = "TARGET_%s" % opname next_op = 1 for opname in opcode._specialized_instructions: while targets[next_op] != '_unknown_opcode': next_op += 1 targets[next_op] = "TARGET_%s" % opname f.write("static void *opcode_targets[256] = {\n") f.write(",\n".join([" &&%s" % s for s in targets])) f.write("\n};\n") def main(): if len(sys.argv) >= 3: sys.exit("Too many arguments") if len(sys.argv) == 2: target = sys.argv[1] else: target = "Python/opcode_targets.h" with open(target, "w") as f: write_contents(f) print("Jump table written into %s" % target) if __name__ == "__main__": main() ================================================ FILE: MarShal.c ================================================ /* Write Python objects to files and read them back. This is primarily intended for writing and reading compiled Python code, even though dicts, lists, sets and frozensets, not commonly seen in code objects, are supported. Version 3 of this protocol properly supports circular links and sharing. */ #define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_code.h" // _PyCode_New() #include "pycore_long.h" // _PyLong_DigitCount #include "pycore_hashtable.h" // _Py_hashtable_t #include "marshal.h" // Py_MARSHAL_VERSION /*[clinic input] module marshal [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=c982b7930dee17db]*/ #include "clinic/marshal.c.h" /* High water mark to determine when the marshalled object is dangerously deep * and risks coring the interpreter. When the object stack gets this deep, * raise an exception instead of continuing. * On Windows debug builds, reduce this value. * * BUG: https://bugs.python.org/issue33720 * On Windows PGO builds, the r_object function overallocates its stack and * can cause a stack overflow. We reduce the maximum depth for all Windows * releases to protect against this. * #if defined(MS_WINDOWS) && defined(_DEBUG) */ #if defined(MS_WINDOWS) #define MAX_MARSHAL_STACK_DEPTH 1000 #elif defined(__wasi__) #define MAX_MARSHAL_STACK_DEPTH 1500 #else #define MAX_MARSHAL_STACK_DEPTH 2000 #endif #define TYPE_NULL '0' #define TYPE_NONE 'N' #define TYPE_FALSE 'F' #define TYPE_TRUE 'T' #define TYPE_STOPITER 'S' #define TYPE_ELLIPSIS '.' #define TYPE_INT 'i' /* TYPE_INT64 is not generated anymore. Supported for backward compatibility only. */ #define TYPE_INT64 'I' #define TYPE_FLOAT 'f' #define TYPE_BINARY_FLOAT 'g' #define TYPE_COMPLEX 'x' #define TYPE_BINARY_COMPLEX 'y' #define TYPE_LONG 'l' #define TYPE_STRING 's' #define TYPE_INTERNED 't' #define TYPE_REF 'r' #define TYPE_TUPLE '(' #define TYPE_LIST '[' #define TYPE_DICT '{' #define TYPE_CODE 'c' #define TYPE_UNICODE 'u' #define TYPE_UNKNOWN '?' #define TYPE_SET '<' #define TYPE_FROZENSET '>' #define FLAG_REF '\x80' /* with a type, add obj to index */ #define TYPE_ASCII 'a' #define TYPE_ASCII_INTERNED 'A' #define TYPE_SMALL_TUPLE ')' #define TYPE_SHORT_ASCII 'z' #define TYPE_SHORT_ASCII_INTERNED 'Z' #define WFERR_OK 0 #define WFERR_UNMARSHALLABLE 1 #define WFERR_NESTEDTOODEEP 2 #define WFERR_NOMEMORY 3 typedef struct { FILE *fp; int error; /* see WFERR_* values */ int depth; PyObject *str; char *ptr; const char *end; char *buf; _Py_hashtable_t *hashtable; int version; } WFILE; #define w_byte(c, p) do { \ if ((p)->ptr != (p)->end || w_reserve((p), 1)) \ *(p)->ptr++ = (c); \ } while(0) static void w_flush(WFILE *p) { assert(p->fp != NULL); fwrite(p->buf, 1, p->ptr - p->buf, p->fp); p->ptr = p->buf; } static int w_reserve(WFILE *p, Py_ssize_t needed) { Py_ssize_t pos, size, delta; if (p->ptr == NULL) return 0; /* An error already occurred */ if (p->fp != NULL) { w_flush(p); return needed <= p->end - p->ptr; } assert(p->str != NULL); pos = p->ptr - p->buf; size = PyBytes_GET_SIZE(p->str); if (size > 16*1024*1024) delta = (size >> 3); /* 12.5% overallocation */ else delta = size + 1024; delta = Py_MAX(delta, needed); if (delta > PY_SSIZE_T_MAX - size) { p->error = WFERR_NOMEMORY; return 0; } size += delta; if (_PyBytes_Resize(&p->str, size) != 0) { p->end = p->ptr = p->buf = NULL; return 0; } else { p->buf = PyBytes_AS_STRING(p->str); p->ptr = p->buf + pos; p->end = p->buf + size; return 1; } } static void w_string(const void *s, Py_ssize_t n, WFILE *p) { Py_ssize_t m; if (!n || p->ptr == NULL) return; m = p->end - p->ptr; if (p->fp != NULL) { if (n <= m) { memcpy(p->ptr, s, n); p->ptr += n; } else { w_flush(p); fwrite(s, 1, n, p->fp); } } else { if (n <= m || w_reserve(p, n - m)) { memcpy(p->ptr, s, n); p->ptr += n; } } } static void w_short(int x, WFILE *p) { w_byte((char)( x & 0xff), p); w_byte((char)((x>> 8) & 0xff), p); } static void w_long(long x, WFILE *p) { w_byte((char)( x & 0xff), p); w_byte((char)((x>> 8) & 0xff), p); w_byte((char)((x>>16) & 0xff), p); w_byte((char)((x>>24) & 0xff), p); } #define SIZE32_MAX 0x7FFFFFFF #if SIZEOF_SIZE_T > 4 # define W_SIZE(n, p) do { \ if ((n) > SIZE32_MAX) { \ (p)->depth--; \ (p)->error = WFERR_UNMARSHALLABLE; \ return; \ } \ w_long((long)(n), p); \ } while(0) #else # define W_SIZE w_long #endif static void w_pstring(const void *s, Py_ssize_t n, WFILE *p) { W_SIZE(n, p); w_string(s, n, p); } static void w_short_pstring(const void *s, Py_ssize_t n, WFILE *p) { w_byte(Py_SAFE_DOWNCAST(n, Py_ssize_t, unsigned char), p); w_string(s, n, p); } /* We assume that Python ints are stored internally in base some power of 2**15; for the sake of portability we'll always read and write them in base exactly 2**15. */ #define PyLong_MARSHAL_SHIFT 15 #define PyLong_MARSHAL_BASE ((short)1 << PyLong_MARSHAL_SHIFT) #define PyLong_MARSHAL_MASK (PyLong_MARSHAL_BASE - 1) #if PyLong_SHIFT % PyLong_MARSHAL_SHIFT != 0 #error "PyLong_SHIFT must be a multiple of PyLong_MARSHAL_SHIFT" #endif #define PyLong_MARSHAL_RATIO (PyLong_SHIFT / PyLong_MARSHAL_SHIFT) #define W_TYPE(t, p) do { \ w_byte((t) | flag, (p)); \ } while(0) static void w_PyLong(const PyLongObject *ob, char flag, WFILE *p) { Py_ssize_t i, j, n, l; digit d; W_TYPE(TYPE_LONG, p); if (_PyLong_IsZero(ob)) { w_long((long)0, p); return; } /* set l to number of base PyLong_MARSHAL_BASE digits */ n = _PyLong_DigitCount(ob); l = (n-1) * PyLong_MARSHAL_RATIO; d = ob->long_value.ob_digit[n-1]; assert(d != 0); /* a PyLong is always normalized */ do { d >>= PyLong_MARSHAL_SHIFT; l++; } while (d != 0); if (l > SIZE32_MAX) { p->depth--; p->error = WFERR_UNMARSHALLABLE; return; } w_long((long)(_PyLong_IsNegative(ob) ? -l : l), p); for (i=0; i < n-1; i++) { d = ob->long_value.ob_digit[i]; for (j=0; j < PyLong_MARSHAL_RATIO; j++) { w_short(d & PyLong_MARSHAL_MASK, p); d >>= PyLong_MARSHAL_SHIFT; } assert (d == 0); } d = ob->long_value.ob_digit[n-1]; do { w_short(d & PyLong_MARSHAL_MASK, p); d >>= PyLong_MARSHAL_SHIFT; } while (d != 0); } static void w_float_bin(double v, WFILE *p) { char buf[8]; if (PyFloat_Pack8(v, buf, 1) < 0) { p->error = WFERR_UNMARSHALLABLE; return; } w_string(buf, 8, p); } static void w_float_str(double v, WFILE *p) { char *buf = PyOS_double_to_string(v, 'g', 17, 0, NULL); if (!buf) { p->error = WFERR_NOMEMORY; return; } w_short_pstring(buf, strlen(buf), p); PyMem_Free(buf); } static int w_ref(PyObject *v, char *flag, WFILE *p) { _Py_hashtable_entry_t *entry; int w; if (p->version < 3 || p->hashtable == NULL) return 0; /* not writing object references */ /* If it has only one reference, it definitely isn't shared. * But we use TYPE_REF always for interned string, to PYC file stable * as possible. */ if (Py_REFCNT(v) == 1 && !(PyUnicode_CheckExact(v) && PyUnicode_CHECK_INTERNED(v))) { return 0; } entry = _Py_hashtable_get_entry(p->hashtable, v); if (entry != NULL) { /* write the reference index to the stream */ w = (int)(uintptr_t)entry->value; /* we don't store "long" indices in the dict */ assert(0 <= w && w <= 0x7fffffff); w_byte(TYPE_REF, p); w_long(w, p); return 1; } else { size_t s = p->hashtable->nentries; /* we don't support long indices */ if (s >= 0x7fffffff) { PyErr_SetString(PyExc_ValueError, "too many objects"); goto err; } w = (int)s; if (_Py_hashtable_set(p->hashtable, Py_NewRef(v), (void *)(uintptr_t)w) < 0) { Py_DECREF(v); goto err; } *flag |= FLAG_REF; return 0; } err: p->error = WFERR_UNMARSHALLABLE; return 1; } static void w_complex_object(PyObject *v, char flag, WFILE *p); static void w_object(PyObject *v, WFILE *p) { char flag = '\0'; p->depth++; if (p->depth > MAX_MARSHAL_STACK_DEPTH) { p->error = WFERR_NESTEDTOODEEP; } else if (v == NULL) { w_byte(TYPE_NULL, p); } else if (v == Py_None) { w_byte(TYPE_NONE, p); } else if (v == PyExc_StopIteration) { w_byte(TYPE_STOPITER, p); } else if (v == Py_Ellipsis) { w_byte(TYPE_ELLIPSIS, p); } else if (v == Py_False) { w_byte(TYPE_FALSE, p); } else if (v == Py_True) { w_byte(TYPE_TRUE, p); } else if (!w_ref(v, &flag, p)) w_complex_object(v, flag, p); p->depth--; } static void w_complex_object(PyObject *v, char flag, WFILE *p) { Py_ssize_t i, n; if (PyLong_CheckExact(v)) { int overflow; long x = PyLong_AsLongAndOverflow(v, &overflow); if (overflow) { w_PyLong((PyLongObject *)v, flag, p); } else { #if SIZEOF_LONG > 4 long y = Py_ARITHMETIC_RIGHT_SHIFT(long, x, 31); if (y && y != -1) { /* Too large for TYPE_INT */ w_PyLong((PyLongObject*)v, flag, p); } else #endif { W_TYPE(TYPE_INT, p); w_long(x, p); } } } else if (PyFloat_CheckExact(v)) { if (p->version > 1) { W_TYPE(TYPE_BINARY_FLOAT, p); w_float_bin(PyFloat_AS_DOUBLE(v), p); } else { W_TYPE(TYPE_FLOAT, p); w_float_str(PyFloat_AS_DOUBLE(v), p); } } else if (PyComplex_CheckExact(v)) { if (p->version > 1) { W_TYPE(TYPE_BINARY_COMPLEX, p); w_float_bin(PyComplex_RealAsDouble(v), p); w_float_bin(PyComplex_ImagAsDouble(v), p); } else { W_TYPE(TYPE_COMPLEX, p); w_float_str(PyComplex_RealAsDouble(v), p); w_float_str(PyComplex_ImagAsDouble(v), p); } } else if (PyBytes_CheckExact(v)) { W_TYPE(TYPE_STRING, p); w_pstring(PyBytes_AS_STRING(v), PyBytes_GET_SIZE(v), p); } else if (PyUnicode_CheckExact(v)) { if (p->version >= 4 && PyUnicode_IS_ASCII(v)) { int is_short = PyUnicode_GET_LENGTH(v) < 256; if (is_short) { if (PyUnicode_CHECK_INTERNED(v)) W_TYPE(TYPE_SHORT_ASCII_INTERNED, p); else W_TYPE(TYPE_SHORT_ASCII, p); w_short_pstring(PyUnicode_1BYTE_DATA(v), PyUnicode_GET_LENGTH(v), p); } else { if (PyUnicode_CHECK_INTERNED(v)) W_TYPE(TYPE_ASCII_INTERNED, p); else W_TYPE(TYPE_ASCII, p); w_pstring(PyUnicode_1BYTE_DATA(v), PyUnicode_GET_LENGTH(v), p); } } else { PyObject *utf8; utf8 = PyUnicode_AsEncodedString(v, "utf8", "surrogatepass"); if (utf8 == NULL) { p->depth--; p->error = WFERR_UNMARSHALLABLE; return; } if (p->version >= 3 && PyUnicode_CHECK_INTERNED(v)) W_TYPE(TYPE_INTERNED, p); else W_TYPE(TYPE_UNICODE, p); w_pstring(PyBytes_AS_STRING(utf8), PyBytes_GET_SIZE(utf8), p); Py_DECREF(utf8); } } else if (PyTuple_CheckExact(v)) { n = PyTuple_GET_SIZE(v); if (p->version >= 4 && n < 256) { W_TYPE(TYPE_SMALL_TUPLE, p); w_byte((unsigned char)n, p); } else { W_TYPE(TYPE_TUPLE, p); W_SIZE(n, p); } for (i = 0; i < n; i++) { w_object(PyTuple_GET_ITEM(v, i), p); } } else if (PyList_CheckExact(v)) { W_TYPE(TYPE_LIST, p); n = PyList_GET_SIZE(v); W_SIZE(n, p); for (i = 0; i < n; i++) { w_object(PyList_GET_ITEM(v, i), p); } } else if (PyDict_CheckExact(v)) { Py_ssize_t pos; PyObject *key, *value; W_TYPE(TYPE_DICT, p); /* This one is NULL object terminated! */ pos = 0; while (PyDict_Next(v, &pos, &key, &value)) { w_object(key, p); w_object(value, p); } w_object((PyObject *)NULL, p); } else if (PyAnySet_CheckExact(v)) { PyObject *value; Py_ssize_t pos = 0; Py_hash_t hash; if (PyFrozenSet_CheckExact(v)) W_TYPE(TYPE_FROZENSET, p); else W_TYPE(TYPE_SET, p); n = PySet_GET_SIZE(v); W_SIZE(n, p); // bpo-37596: To support reproducible builds, sets and frozensets need // to have their elements serialized in a consistent order (even when // they have been scrambled by hash randomization). To ensure this, we // use an order equivalent to sorted(v, key=marshal.dumps): PyObject *pairs = PyList_New(n); if (pairs == NULL) { p->error = WFERR_NOMEMORY; return; } Py_ssize_t i = 0; while (_PySet_NextEntry(v, &pos, &value, &hash)) { PyObject *dump = PyMarshal_WriteObjectToString(value, p->version); if (dump == NULL) { p->error = WFERR_UNMARSHALLABLE; Py_DECREF(pairs); return; } PyObject *pair = PyTuple_Pack(2, dump, value); Py_DECREF(dump); if (pair == NULL) { p->error = WFERR_NOMEMORY; Py_DECREF(pairs); return; } PyList_SET_ITEM(pairs, i++, pair); } assert(i == n); if (PyList_Sort(pairs)) { p->error = WFERR_NOMEMORY; Py_DECREF(pairs); return; } for (Py_ssize_t i = 0; i < n; i++) { PyObject *pair = PyList_GET_ITEM(pairs, i); value = PyTuple_GET_ITEM(pair, 1); w_object(value, p); } Py_DECREF(pairs); } else if (PyCode_Check(v)) { PyCodeObject *co = (PyCodeObject *)v; PyObject *co_code = _PyCode_GetCode(co); if (co_code == NULL) { p->error = WFERR_NOMEMORY; return; } W_TYPE(TYPE_CODE, p); w_long(co->co_argcount, p); w_long(co->co_posonlyargcount, p); w_long(co->co_kwonlyargcount, p); w_long(co->co_stacksize, p); w_long(co->co_flags, p); w_object(co_code, p); w_object(co->co_consts, p); w_object(co->co_names, p); w_object(co->co_localsplusnames, p); w_object(co->co_localspluskinds, p); w_object(co->co_filename, p); w_object(co->co_name, p); w_object(co->co_qualname, p); w_long(co->co_firstlineno, p); w_object(co->co_linetable, p); w_object(co->co_exceptiontable, p); Py_DECREF(co_code); } else if (PyObject_CheckBuffer(v)) { /* Write unknown bytes-like objects as a bytes object */ Py_buffer view; if (PyObject_GetBuffer(v, &view, PyBUF_SIMPLE) != 0) { w_byte(TYPE_UNKNOWN, p); p->depth--; p->error = WFERR_UNMARSHALLABLE; return; } W_TYPE(TYPE_STRING, p); w_pstring(view.buf, view.len, p); PyBuffer_Release(&view); } else { W_TYPE(TYPE_UNKNOWN, p); p->error = WFERR_UNMARSHALLABLE; } } static void w_decref_entry(void *key) { PyObject *entry_key = (PyObject *)key; Py_XDECREF(entry_key); } static int w_init_refs(WFILE *wf, int version) { if (version >= 3) { wf->hashtable = _Py_hashtable_new_full(_Py_hashtable_hash_ptr, _Py_hashtable_compare_direct, w_decref_entry, NULL, NULL); if (wf->hashtable == NULL) { PyErr_NoMemory(); return -1; } } return 0; } static void w_clear_refs(WFILE *wf) { if (wf->hashtable != NULL) { _Py_hashtable_destroy(wf->hashtable); } } /* version currently has no effect for writing ints. */ /* Note that while the documentation states that this function * can error, currently it never does. Setting an exception in * this function should be regarded as an API-breaking change. */ void PyMarshal_WriteLongToFile(long x, FILE *fp, int version) { char buf[4]; WFILE wf; memset(&wf, 0, sizeof(wf)); wf.fp = fp; wf.ptr = wf.buf = buf; wf.end = wf.ptr + sizeof(buf); wf.error = WFERR_OK; wf.version = version; w_long(x, &wf); w_flush(&wf); } void PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version) { char buf[BUFSIZ]; WFILE wf; if (PySys_Audit("marshal.dumps", "Oi", x, version) < 0) { return; /* caller must check PyErr_Occurred() */ } memset(&wf, 0, sizeof(wf)); wf.fp = fp; wf.ptr = wf.buf = buf; wf.end = wf.ptr + sizeof(buf); wf.error = WFERR_OK; wf.version = version; if (w_init_refs(&wf, version)) { return; /* caller must check PyErr_Occurred() */ } w_object(x, &wf); w_clear_refs(&wf); w_flush(&wf); } typedef struct { FILE *fp; int depth; PyObject *readable; /* Stream-like object being read from */ const char *ptr; const char *end; char *buf; Py_ssize_t buf_size; PyObject *refs; /* a list */ } RFILE; static const char * r_string(Py_ssize_t n, RFILE *p) { Py_ssize_t read = -1; if (p->ptr != NULL) { /* Fast path for loads() */ const char *res = p->ptr; Py_ssize_t left = p->end - p->ptr; if (left < n) { PyErr_SetString(PyExc_EOFError, "marshal data too short"); return NULL; } p->ptr += n; return res; } if (p->buf == NULL) { p->buf = PyMem_Malloc(n); if (p->buf == NULL) { PyErr_NoMemory(); return NULL; } p->buf_size = n; } else if (p->buf_size < n) { char *tmp = PyMem_Realloc(p->buf, n); if (tmp == NULL) { PyErr_NoMemory(); return NULL; } p->buf = tmp; p->buf_size = n; } if (!p->readable) { assert(p->fp != NULL); read = fread(p->buf, 1, n, p->fp); } else { PyObject *res, *mview; Py_buffer buf; if (PyBuffer_FillInfo(&buf, NULL, p->buf, n, 0, PyBUF_CONTIG) == -1) return NULL; mview = PyMemoryView_FromBuffer(&buf); if (mview == NULL) return NULL; res = _PyObject_CallMethod(p->readable, &_Py_ID(readinto), "N", mview); if (res != NULL) { read = PyNumber_AsSsize_t(res, PyExc_ValueError); Py_DECREF(res); } } if (read != n) { if (!PyErr_Occurred()) { if (read > n) PyErr_Format(PyExc_ValueError, "read() returned too much data: " "%zd bytes requested, %zd returned", n, read); else PyErr_SetString(PyExc_EOFError, "EOF read where not expected"); } return NULL; } return p->buf; } static int r_byte(RFILE *p) { int c = EOF; if (p->ptr != NULL) { if (p->ptr < p->end) c = (unsigned char) *p->ptr++; return c; } if (!p->readable) { assert(p->fp); c = getc(p->fp); } else { const char *ptr = r_string(1, p); if (ptr != NULL) c = *(const unsigned char *) ptr; } return c; } static int r_short(RFILE *p) { short x = -1; const unsigned char *buffer; buffer = (const unsigned char *) r_string(2, p); if (buffer != NULL) { x = buffer[0]; x |= buffer[1] << 8; /* Sign-extension, in case short greater than 16 bits */ x |= -(x & 0x8000); } return x; } static long r_long(RFILE *p) { long x = -1; const unsigned char *buffer; buffer = (const unsigned char *) r_string(4, p); if (buffer != NULL) { x = buffer[0]; x |= (long)buffer[1] << 8; x |= (long)buffer[2] << 16; x |= (long)buffer[3] << 24; #if SIZEOF_LONG > 4 /* Sign extension for 64-bit machines */ x |= -(x & 0x80000000L); #endif } return x; } /* r_long64 deals with the TYPE_INT64 code. */ static PyObject * r_long64(RFILE *p) { const unsigned char *buffer = (const unsigned char *) r_string(8, p); if (buffer == NULL) { return NULL; } return _PyLong_FromByteArray(buffer, 8, 1 /* little endian */, 1 /* signed */); } static PyObject * r_PyLong(RFILE *p) { PyLongObject *ob; long n, size, i; int j, md, shorts_in_top_digit; digit d; n = r_long(p); if (PyErr_Occurred()) return NULL; if (n == 0) return (PyObject *)_PyLong_New(0); if (n < -SIZE32_MAX || n > SIZE32_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (long size out of range)"); return NULL; } size = 1 + (Py_ABS(n) - 1) / PyLong_MARSHAL_RATIO; shorts_in_top_digit = 1 + (Py_ABS(n) - 1) % PyLong_MARSHAL_RATIO; ob = _PyLong_New(size); if (ob == NULL) return NULL; _PyLong_SetSignAndDigitCount(ob, n < 0 ? -1 : 1, size); for (i = 0; i < size-1; i++) { d = 0; for (j=0; j < PyLong_MARSHAL_RATIO; j++) { md = r_short(p); if (PyErr_Occurred()) { Py_DECREF(ob); return NULL; } if (md < 0 || md > PyLong_MARSHAL_BASE) goto bad_digit; d += (digit)md << j*PyLong_MARSHAL_SHIFT; } ob->long_value.ob_digit[i] = d; } d = 0; for (j=0; j < shorts_in_top_digit; j++) { md = r_short(p); if (PyErr_Occurred()) { Py_DECREF(ob); return NULL; } if (md < 0 || md > PyLong_MARSHAL_BASE) goto bad_digit; /* topmost marshal digit should be nonzero */ if (md == 0 && j == shorts_in_top_digit - 1) { Py_DECREF(ob); PyErr_SetString(PyExc_ValueError, "bad marshal data (unnormalized long data)"); return NULL; } d += (digit)md << j*PyLong_MARSHAL_SHIFT; } if (PyErr_Occurred()) { Py_DECREF(ob); return NULL; } /* top digit should be nonzero, else the resulting PyLong won't be normalized */ ob->long_value.ob_digit[size-1] = d; return (PyObject *)ob; bad_digit: Py_DECREF(ob); PyErr_SetString(PyExc_ValueError, "bad marshal data (digit out of range in long)"); return NULL; } static double r_float_bin(RFILE *p) { const char *buf = r_string(8, p); if (buf == NULL) return -1; return PyFloat_Unpack8(buf, 1); } /* Issue #33720: Disable inlining for reducing the C stack consumption on PGO builds. */ Py_NO_INLINE static double r_float_str(RFILE *p) { int n; char buf[256]; const char *ptr; n = r_byte(p); if (n == EOF) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); return -1; } ptr = r_string(n, p); if (ptr == NULL) { return -1; } memcpy(buf, ptr, n); buf[n] = '\0'; return PyOS_string_to_double(buf, NULL, NULL); } /* allocate the reflist index for a new object. Return -1 on failure */ static Py_ssize_t r_ref_reserve(int flag, RFILE *p) { if (flag) { /* currently only FLAG_REF is defined */ Py_ssize_t idx = PyList_GET_SIZE(p->refs); if (idx >= 0x7ffffffe) { PyErr_SetString(PyExc_ValueError, "bad marshal data (index list too large)"); return -1; } if (PyList_Append(p->refs, Py_None) < 0) return -1; return idx; } else return 0; } /* insert the new object 'o' to the reflist at previously * allocated index 'idx'. * 'o' can be NULL, in which case nothing is done. * if 'o' was non-NULL, and the function succeeds, 'o' is returned. * if 'o' was non-NULL, and the function fails, 'o' is released and * NULL returned. This simplifies error checking at the call site since * a single test for NULL for the function result is enough. */ static PyObject * r_ref_insert(PyObject *o, Py_ssize_t idx, int flag, RFILE *p) { if (o != NULL && flag) { /* currently only FLAG_REF is defined */ PyObject *tmp = PyList_GET_ITEM(p->refs, idx); PyList_SET_ITEM(p->refs, idx, Py_NewRef(o)); Py_DECREF(tmp); } return o; } /* combination of both above, used when an object can be * created whenever it is seen in the file, as opposed to * after having loaded its sub-objects. */ static PyObject * r_ref(PyObject *o, int flag, RFILE *p) { assert(flag & FLAG_REF); if (o == NULL) return NULL; if (PyList_Append(p->refs, o) < 0) { Py_DECREF(o); /* release the new object */ return NULL; } return o; } static PyObject * r_object(RFILE *p) { /* NULL is a valid return value, it does not necessarily means that an exception is set. */ PyObject *v, *v2; Py_ssize_t idx = 0; long i, n; int type, code = r_byte(p); int flag, is_interned = 0; PyObject *retval = NULL; if (code == EOF) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); return NULL; } p->depth++; if (p->depth > MAX_MARSHAL_STACK_DEPTH) { p->depth--; PyErr_SetString(PyExc_ValueError, "recursion limit exceeded"); return NULL; } flag = code & FLAG_REF; type = code & ~FLAG_REF; #define R_REF(O) do{\ if (flag) \ O = r_ref(O, flag, p);\ } while (0) switch (type) { case TYPE_NULL: break; case TYPE_NONE: retval = Py_NewRef(Py_None); break; case TYPE_STOPITER: retval = Py_NewRef(PyExc_StopIteration); break; case TYPE_ELLIPSIS: retval = Py_NewRef(Py_Ellipsis); break; case TYPE_FALSE: retval = Py_NewRef(Py_False); break; case TYPE_TRUE: retval = Py_NewRef(Py_True); break; case TYPE_INT: n = r_long(p); retval = PyErr_Occurred() ? NULL : PyLong_FromLong(n); R_REF(retval); break; case TYPE_INT64: retval = r_long64(p); R_REF(retval); break; case TYPE_LONG: retval = r_PyLong(p); R_REF(retval); break; case TYPE_FLOAT: { double x = r_float_str(p); if (x == -1.0 && PyErr_Occurred()) break; retval = PyFloat_FromDouble(x); R_REF(retval); break; } case TYPE_BINARY_FLOAT: { double x = r_float_bin(p); if (x == -1.0 && PyErr_Occurred()) break; retval = PyFloat_FromDouble(x); R_REF(retval); break; } case TYPE_COMPLEX: { Py_complex c; c.real = r_float_str(p); if (c.real == -1.0 && PyErr_Occurred()) break; c.imag = r_float_str(p); if (c.imag == -1.0 && PyErr_Occurred()) break; retval = PyComplex_FromCComplex(c); R_REF(retval); break; } case TYPE_BINARY_COMPLEX: { Py_complex c; c.real = r_float_bin(p); if (c.real == -1.0 && PyErr_Occurred()) break; c.imag = r_float_bin(p); if (c.imag == -1.0 && PyErr_Occurred()) break; retval = PyComplex_FromCComplex(c); R_REF(retval); break; } case TYPE_STRING: { const char *ptr; n = r_long(p); if (PyErr_Occurred()) break; if (n < 0 || n > SIZE32_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (bytes object size out of range)"); break; } v = PyBytes_FromStringAndSize((char *)NULL, n); if (v == NULL) break; ptr = r_string(n, p); if (ptr == NULL) { Py_DECREF(v); break; } memcpy(PyBytes_AS_STRING(v), ptr, n); retval = v; R_REF(retval); break; } case TYPE_ASCII_INTERNED: is_interned = 1; /* fall through */ case TYPE_ASCII: n = r_long(p); if (PyErr_Occurred()) break; if (n < 0 || n > SIZE32_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (string size out of range)"); break; } goto _read_ascii; case TYPE_SHORT_ASCII_INTERNED: is_interned = 1; /* fall through */ case TYPE_SHORT_ASCII: n = r_byte(p); if (n == EOF) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); break; } _read_ascii: { const char *ptr; ptr = r_string(n, p); if (ptr == NULL) break; v = PyUnicode_FromKindAndData(PyUnicode_1BYTE_KIND, ptr, n); if (v == NULL) break; if (is_interned) PyUnicode_InternInPlace(&v); retval = v; R_REF(retval); break; } case TYPE_INTERNED: is_interned = 1; /* fall through */ case TYPE_UNICODE: { const char *buffer; n = r_long(p); if (PyErr_Occurred()) break; if (n < 0 || n > SIZE32_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (string size out of range)"); break; } if (n != 0) { buffer = r_string(n, p); if (buffer == NULL) break; v = PyUnicode_DecodeUTF8(buffer, n, "surrogatepass"); } else { v = PyUnicode_New(0, 0); } if (v == NULL) break; if (is_interned) PyUnicode_InternInPlace(&v); retval = v; R_REF(retval); break; } case TYPE_SMALL_TUPLE: n = (unsigned char) r_byte(p); if (PyErr_Occurred()) break; goto _read_tuple; case TYPE_TUPLE: n = r_long(p); if (PyErr_Occurred()) break; if (n < 0 || n > SIZE32_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (tuple size out of range)"); break; } _read_tuple: v = PyTuple_New(n); R_REF(v); if (v == NULL) break; for (i = 0; i < n; i++) { v2 = r_object(p); if ( v2 == NULL ) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_TypeError, "NULL object in marshal data for tuple"); Py_SETREF(v, NULL); break; } PyTuple_SET_ITEM(v, i, v2); } retval = v; break; case TYPE_LIST: n = r_long(p); if (PyErr_Occurred()) break; if (n < 0 || n > SIZE32_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (list size out of range)"); break; } v = PyList_New(n); R_REF(v); if (v == NULL) break; for (i = 0; i < n; i++) { v2 = r_object(p); if ( v2 == NULL ) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_TypeError, "NULL object in marshal data for list"); Py_SETREF(v, NULL); break; } PyList_SET_ITEM(v, i, v2); } retval = v; break; case TYPE_DICT: v = PyDict_New(); R_REF(v); if (v == NULL) break; for (;;) { PyObject *key, *val; key = r_object(p); if (key == NULL) break; val = r_object(p); if (val == NULL) { Py_DECREF(key); break; } if (PyDict_SetItem(v, key, val) < 0) { Py_DECREF(key); Py_DECREF(val); break; } Py_DECREF(key); Py_DECREF(val); } if (PyErr_Occurred()) { Py_SETREF(v, NULL); } retval = v; break; case TYPE_SET: case TYPE_FROZENSET: n = r_long(p); if (PyErr_Occurred()) break; if (n < 0 || n > SIZE32_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (set size out of range)"); break; } if (n == 0 && type == TYPE_FROZENSET) { /* call frozenset() to get the empty frozenset singleton */ v = _PyObject_CallNoArgs((PyObject*)&PyFrozenSet_Type); if (v == NULL) break; R_REF(v); retval = v; } else { v = (type == TYPE_SET) ? PySet_New(NULL) : PyFrozenSet_New(NULL); if (type == TYPE_SET) { R_REF(v); } else { /* must use delayed registration of frozensets because they must * be init with a refcount of 1 */ idx = r_ref_reserve(flag, p); if (idx < 0) Py_CLEAR(v); /* signal error */ } if (v == NULL) break; for (i = 0; i < n; i++) { v2 = r_object(p); if ( v2 == NULL ) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_TypeError, "NULL object in marshal data for set"); Py_SETREF(v, NULL); break; } if (PySet_Add(v, v2) == -1) { Py_DECREF(v); Py_DECREF(v2); v = NULL; break; } Py_DECREF(v2); } if (type != TYPE_SET) v = r_ref_insert(v, idx, flag, p); retval = v; } break; case TYPE_CODE: { int argcount; int posonlyargcount; int kwonlyargcount; int stacksize; int flags; PyObject *code = NULL; PyObject *consts = NULL; PyObject *names = NULL; PyObject *localsplusnames = NULL; PyObject *localspluskinds = NULL; PyObject *filename = NULL; PyObject *name = NULL; PyObject *qualname = NULL; int firstlineno; PyObject* linetable = NULL; PyObject *exceptiontable = NULL; idx = r_ref_reserve(flag, p); if (idx < 0) break; v = NULL; /* XXX ignore long->int overflows for now */ argcount = (int)r_long(p); if (PyErr_Occurred()) goto code_error; posonlyargcount = (int)r_long(p); if (PyErr_Occurred()) { goto code_error; } kwonlyargcount = (int)r_long(p); if (PyErr_Occurred()) goto code_error; stacksize = (int)r_long(p); if (PyErr_Occurred()) goto code_error; flags = (int)r_long(p); if (PyErr_Occurred()) goto code_error; code = r_object(p); if (code == NULL) goto code_error; consts = r_object(p); if (consts == NULL) goto code_error; names = r_object(p); if (names == NULL) goto code_error; localsplusnames = r_object(p); if (localsplusnames == NULL) goto code_error; localspluskinds = r_object(p); if (localspluskinds == NULL) goto code_error; filename = r_object(p); if (filename == NULL) goto code_error; name = r_object(p); if (name == NULL) goto code_error; qualname = r_object(p); if (qualname == NULL) goto code_error; firstlineno = (int)r_long(p); if (firstlineno == -1 && PyErr_Occurred()) break; linetable = r_object(p); if (linetable == NULL) goto code_error; exceptiontable = r_object(p); if (exceptiontable == NULL) goto code_error; struct _PyCodeConstructor con = { .filename = filename, .name = name, .qualname = qualname, .flags = flags, .code = code, .firstlineno = firstlineno, .linetable = linetable, .consts = consts, .names = names, .localsplusnames = localsplusnames, .localspluskinds = localspluskinds, .argcount = argcount, .posonlyargcount = posonlyargcount, .kwonlyargcount = kwonlyargcount, .stacksize = stacksize, .exceptiontable = exceptiontable, }; if (_PyCode_Validate(&con) < 0) { goto code_error; } v = (PyObject *)_PyCode_New(&con); if (v == NULL) { goto code_error; } v = r_ref_insert(v, idx, flag, p); code_error: Py_XDECREF(code); Py_XDECREF(consts); Py_XDECREF(names); Py_XDECREF(localsplusnames); Py_XDECREF(localspluskinds); Py_XDECREF(filename); Py_XDECREF(name); Py_XDECREF(qualname); Py_XDECREF(linetable); Py_XDECREF(exceptiontable); } retval = v; break; case TYPE_REF: n = r_long(p); if (n < 0 || n >= PyList_GET_SIZE(p->refs)) { if (n == -1 && PyErr_Occurred()) break; PyErr_SetString(PyExc_ValueError, "bad marshal data (invalid reference)"); break; } v = PyList_GET_ITEM(p->refs, n); if (v == Py_None) { PyErr_SetString(PyExc_ValueError, "bad marshal data (invalid reference)"); break; } retval = Py_NewRef(v); break; default: /* Bogus data got written, which isn't ideal. This will let you keep working and recover. */ PyErr_SetString(PyExc_ValueError, "bad marshal data (unknown type code)"); break; } p->depth--; return retval; } static PyObject * read_object(RFILE *p) { PyObject *v; if (PyErr_Occurred()) { fprintf(stderr, "XXX readobject called with exception set\n"); return NULL; } if (p->ptr && p->end) { if (PySys_Audit("marshal.loads", "y#", p->ptr, (Py_ssize_t)(p->end - p->ptr)) < 0) { return NULL; } } else if (p->fp || p->readable) { if (PySys_Audit("marshal.load", NULL) < 0) { return NULL; } } v = r_object(p); if (v == NULL && !PyErr_Occurred()) PyErr_SetString(PyExc_TypeError, "NULL object in marshal data for object"); return v; } int PyMarshal_ReadShortFromFile(FILE *fp) { RFILE rf; int res; assert(fp); rf.readable = NULL; rf.fp = fp; rf.end = rf.ptr = NULL; rf.buf = NULL; res = r_short(&rf); if (rf.buf != NULL) PyMem_Free(rf.buf); return res; } long PyMarshal_ReadLongFromFile(FILE *fp) { RFILE rf; long res; rf.fp = fp; rf.readable = NULL; rf.ptr = rf.end = NULL; rf.buf = NULL; res = r_long(&rf); if (rf.buf != NULL) PyMem_Free(rf.buf); return res; } /* Return size of file in bytes; < 0 if unknown or INT_MAX if too big */ static off_t getfilesize(FILE *fp) { struct _Py_stat_struct st; if (_Py_fstat_noraise(fileno(fp), &st) != 0) return -1; #if SIZEOF_OFF_T == 4 else if (st.st_size >= INT_MAX) return (off_t)INT_MAX; #endif else return (off_t)st.st_size; } /* If we can get the size of the file up-front, and it's reasonably small, * read it in one gulp and delegate to ...FromString() instead. Much quicker * than reading a byte at a time from file; speeds .pyc imports. * CAUTION: since this may read the entire remainder of the file, don't * call it unless you know you're done with the file. */ PyObject * PyMarshal_ReadLastObjectFromFile(FILE *fp) { /* REASONABLE_FILE_LIMIT is by defn something big enough for Tkinter.pyc. */ #define REASONABLE_FILE_LIMIT (1L << 18) off_t filesize; filesize = getfilesize(fp); if (filesize > 0 && filesize <= REASONABLE_FILE_LIMIT) { char* pBuf = (char *)PyMem_Malloc(filesize); if (pBuf != NULL) { size_t n = fread(pBuf, 1, (size_t)filesize, fp); PyObject* v = PyMarshal_ReadObjectFromString(pBuf, n); PyMem_Free(pBuf); return v; } } /* We don't have fstat, or we do but the file is larger than * REASONABLE_FILE_LIMIT or malloc failed -- read a byte at a time. */ return PyMarshal_ReadObjectFromFile(fp); #undef REASONABLE_FILE_LIMIT } PyObject * PyMarshal_ReadObjectFromFile(FILE *fp) { RFILE rf; PyObject *result; rf.fp = fp; rf.readable = NULL; rf.depth = 0; rf.ptr = rf.end = NULL; rf.buf = NULL; rf.refs = PyList_New(0); if (rf.refs == NULL) return NULL; result = read_object(&rf); Py_DECREF(rf.refs); if (rf.buf != NULL) PyMem_Free(rf.buf); return result; } PyObject * PyMarshal_ReadObjectFromString(const char *str, Py_ssize_t len) { RFILE rf; PyObject *result; rf.fp = NULL; rf.readable = NULL; rf.ptr = str; rf.end = str + len; rf.buf = NULL; rf.depth = 0; rf.refs = PyList_New(0); if (rf.refs == NULL) return NULL; result = read_object(&rf); Py_DECREF(rf.refs); if (rf.buf != NULL) PyMem_Free(rf.buf); return result; } PyObject * PyMarshal_WriteObjectToString(PyObject *x, int version) { WFILE wf; if (PySys_Audit("marshal.dumps", "Oi", x, version) < 0) { return NULL; } memset(&wf, 0, sizeof(wf)); wf.str = PyBytes_FromStringAndSize((char *)NULL, 50); if (wf.str == NULL) return NULL; wf.ptr = wf.buf = PyBytes_AS_STRING(wf.str); wf.end = wf.ptr + PyBytes_GET_SIZE(wf.str); wf.error = WFERR_OK; wf.version = version; if (w_init_refs(&wf, version)) { Py_DECREF(wf.str); return NULL; } w_object(x, &wf); w_clear_refs(&wf); if (wf.str != NULL) { const char *base = PyBytes_AS_STRING(wf.str); if (_PyBytes_Resize(&wf.str, (Py_ssize_t)(wf.ptr - base)) < 0) return NULL; } if (wf.error != WFERR_OK) { Py_XDECREF(wf.str); if (wf.error == WFERR_NOMEMORY) PyErr_NoMemory(); else PyErr_SetString(PyExc_ValueError, (wf.error==WFERR_UNMARSHALLABLE)?"unmarshallable object" :"object too deeply nested to marshal"); return NULL; } return wf.str; } /* And an interface for Python programs... */ /*[clinic input] marshal.dump value: object Must be a supported type. file: object Must be a writeable binary file. version: int(c_default="Py_MARSHAL_VERSION") = version Indicates the data format that dump should use. / Write the value on the open file. If the value has (or contains an object that has) an unsupported type, a ValueError exception is raised - but garbage data will also be written to the file. The object will not be properly read back by load(). [clinic start generated code]*/ static PyObject * marshal_dump_impl(PyObject *module, PyObject *value, PyObject *file, int version) /*[clinic end generated code: output=aaee62c7028a7cb2 input=6c7a3c23c6fef556]*/ { /* XXX Quick hack -- need to do this differently */ PyObject *s; PyObject *res; s = PyMarshal_WriteObjectToString(value, version); if (s == NULL) return NULL; res = _PyObject_CallMethodOneArg(file, &_Py_ID(write), s); Py_DECREF(s); return res; } /*[clinic input] marshal.load file: object Must be readable binary file. / Read one value from the open file and return it. If no valid value is read (e.g. because the data has a different Python version's incompatible marshal format), raise EOFError, ValueError or TypeError. Note: If an object containing an unsupported type was marshalled with dump(), load() will substitute None for the unmarshallable type. [clinic start generated code]*/ static PyObject * marshal_load(PyObject *module, PyObject *file) /*[clinic end generated code: output=f8e5c33233566344 input=c85c2b594cd8124a]*/ { PyObject *data, *result; RFILE rf; /* * Make a call to the read method, but read zero bytes. * This is to ensure that the object passed in at least * has a read method which returns bytes. * This can be removed if we guarantee good error handling * for r_string() */ data = _PyObject_CallMethod(file, &_Py_ID(read), "i", 0); if (data == NULL) return NULL; if (!PyBytes_Check(data)) { PyErr_Format(PyExc_TypeError, "file.read() returned not bytes but %.100s", Py_TYPE(data)->tp_name); result = NULL; } else { rf.depth = 0; rf.fp = NULL; rf.readable = file; rf.ptr = rf.end = NULL; rf.buf = NULL; if ((rf.refs = PyList_New(0)) != NULL) { result = read_object(&rf); Py_DECREF(rf.refs); if (rf.buf != NULL) PyMem_Free(rf.buf); } else result = NULL; } Py_DECREF(data); return result; } /*[clinic input] marshal.dumps value: object Must be a supported type. version: int(c_default="Py_MARSHAL_VERSION") = version Indicates the data format that dumps should use. / Return the bytes object that would be written to a file by dump(value, file). Raise a ValueError exception if value has (or contains an object that has) an unsupported type. [clinic start generated code]*/ static PyObject * marshal_dumps_impl(PyObject *module, PyObject *value, int version) /*[clinic end generated code: output=9c200f98d7256cad input=a2139ea8608e9b27]*/ { return PyMarshal_WriteObjectToString(value, version); } /*[clinic input] marshal.loads bytes: Py_buffer / Convert the bytes-like object to a value. If no valid value is found, raise EOFError, ValueError or TypeError. Extra bytes in the input are ignored. [clinic start generated code]*/ static PyObject * marshal_loads_impl(PyObject *module, Py_buffer *bytes) /*[clinic end generated code: output=9fc65985c93d1bb1 input=6f426518459c8495]*/ { RFILE rf; char *s = bytes->buf; Py_ssize_t n = bytes->len; PyObject* result; rf.fp = NULL; rf.readable = NULL; rf.ptr = s; rf.end = s + n; rf.depth = 0; if ((rf.refs = PyList_New(0)) == NULL) return NULL; result = read_object(&rf); Py_DECREF(rf.refs); return result; } static PyMethodDef marshal_methods[] = { MARSHAL_DUMP_METHODDEF MARSHAL_LOAD_METHODDEF MARSHAL_DUMPS_METHODDEF MARSHAL_LOADS_METHODDEF {NULL, NULL} /* sentinel */ }; PyDoc_STRVAR(module_doc, "This module contains functions that can read and write Python values in\n\ a binary format. The format is specific to Python, but independent of\n\ machine architecture issues.\n\ \n\ Not all Python object types are supported; in general, only objects\n\ whose value is independent from a particular invocation of Python can be\n\ written and read by this module. The following types are supported:\n\ None, integers, floating point numbers, strings, bytes, bytearrays,\n\ tuples, lists, sets, dictionaries, and code objects, where it\n\ should be understood that tuples, lists and dictionaries are only\n\ supported as long as the values contained therein are themselves\n\ supported; and recursive lists and dictionaries should not be written\n\ (they will cause infinite loops).\n\ \n\ Variables:\n\ \n\ version -- indicates the format that the module uses. Version 0 is the\n\ historical format, version 1 shares interned strings and version 2\n\ uses a binary format for floating point numbers.\n\ Version 3 shares common object references (New in version 3.4).\n\ \n\ Functions:\n\ \n\ dump() -- write value to a file\n\ load() -- read value from a file\n\ dumps() -- marshal value as a bytes object\n\ loads() -- read value from a bytes-like object"); static int marshal_module_exec(PyObject *mod) { if (PyModule_AddIntConstant(mod, "version", Py_MARSHAL_VERSION) < 0) { return -1; } return 0; } static PyModuleDef_Slot marshalmodule_slots[] = { {Py_mod_exec, marshal_module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; static struct PyModuleDef marshalmodule = { PyModuleDef_HEAD_INIT, .m_name = "marshal", .m_doc = module_doc, .m_methods = marshal_methods, .m_slots = marshalmodule_slots, }; PyMODINIT_FUNC PyMarshal_Init(void) { return PyModuleDef_Init(&marshalmodule); } ================================================ FILE: ModSupport.c ================================================ /* Module support implementation */ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_object.h" // _PyType_IsReady() typedef double va_double; static PyObject *va_build_value(const char *, va_list); int _Py_convert_optional_to_ssize_t(PyObject *obj, void *result) { Py_ssize_t limit; if (obj == Py_None) { return 1; } else if (_PyIndex_Check(obj)) { limit = PyNumber_AsSsize_t(obj, PyExc_OverflowError); if (limit == -1 && PyErr_Occurred()) { return 0; } } else { PyErr_Format(PyExc_TypeError, "argument should be integer or None, not '%.200s'", Py_TYPE(obj)->tp_name); return 0; } *((Py_ssize_t *)result) = limit; return 1; } /* Helper for mkvalue() to scan the length of a format */ static Py_ssize_t countformat(const char *format, char endchar) { Py_ssize_t count = 0; int level = 0; while (level > 0 || *format != endchar) { switch (*format) { case '\0': /* Premature end */ PyErr_SetString(PyExc_SystemError, "unmatched paren in format"); return -1; case '(': case '[': case '{': if (level == 0) { count++; } level++; break; case ')': case ']': case '}': level--; break; case '#': case '&': case ',': case ':': case ' ': case '\t': break; default: if (level == 0) { count++; } } format++; } return count; } /* Generic function to create a value -- the inverse of getargs() */ /* After an original idea and first implementation by Steven Miale */ static PyObject *do_mktuple(const char**, va_list *, char, Py_ssize_t); static int do_mkstack(PyObject **, const char**, va_list *, char, Py_ssize_t); static PyObject *do_mklist(const char**, va_list *, char, Py_ssize_t); static PyObject *do_mkdict(const char**, va_list *, char, Py_ssize_t); static PyObject *do_mkvalue(const char**, va_list *); static void do_ignore(const char **p_format, va_list *p_va, char endchar, Py_ssize_t n) { assert(PyErr_Occurred()); PyObject *v = PyTuple_New(n); for (Py_ssize_t i = 0; i < n; i++) { PyObject *exc = PyErr_GetRaisedException(); PyObject *w = do_mkvalue(p_format, p_va); PyErr_SetRaisedException(exc); if (w != NULL) { if (v != NULL) { PyTuple_SET_ITEM(v, i, w); } else { Py_DECREF(w); } } } Py_XDECREF(v); if (**p_format != endchar) { PyErr_SetString(PyExc_SystemError, "Unmatched paren in format"); return; } if (endchar) { ++*p_format; } } static PyObject * do_mkdict(const char **p_format, va_list *p_va, char endchar, Py_ssize_t n) { PyObject *d; Py_ssize_t i; if (n < 0) return NULL; if (n % 2) { PyErr_SetString(PyExc_SystemError, "Bad dict format"); do_ignore(p_format, p_va, endchar, n); return NULL; } /* Note that we can't bail immediately on error as this will leak refcounts on any 'N' arguments. */ if ((d = PyDict_New()) == NULL) { do_ignore(p_format, p_va, endchar, n); return NULL; } for (i = 0; i < n; i+= 2) { PyObject *k, *v; k = do_mkvalue(p_format, p_va); if (k == NULL) { do_ignore(p_format, p_va, endchar, n - i - 1); Py_DECREF(d); return NULL; } v = do_mkvalue(p_format, p_va); if (v == NULL || PyDict_SetItem(d, k, v) < 0) { do_ignore(p_format, p_va, endchar, n - i - 2); Py_DECREF(k); Py_XDECREF(v); Py_DECREF(d); return NULL; } Py_DECREF(k); Py_DECREF(v); } if (**p_format != endchar) { Py_DECREF(d); PyErr_SetString(PyExc_SystemError, "Unmatched paren in format"); return NULL; } if (endchar) ++*p_format; return d; } static PyObject * do_mklist(const char **p_format, va_list *p_va, char endchar, Py_ssize_t n) { PyObject *v; Py_ssize_t i; if (n < 0) return NULL; /* Note that we can't bail immediately on error as this will leak refcounts on any 'N' arguments. */ v = PyList_New(n); if (v == NULL) { do_ignore(p_format, p_va, endchar, n); return NULL; } for (i = 0; i < n; i++) { PyObject *w = do_mkvalue(p_format, p_va); if (w == NULL) { do_ignore(p_format, p_va, endchar, n - i - 1); Py_DECREF(v); return NULL; } PyList_SET_ITEM(v, i, w); } if (**p_format != endchar) { Py_DECREF(v); PyErr_SetString(PyExc_SystemError, "Unmatched paren in format"); return NULL; } if (endchar) ++*p_format; return v; } static int do_mkstack(PyObject **stack, const char **p_format, va_list *p_va, char endchar, Py_ssize_t n) { Py_ssize_t i; if (n < 0) { return -1; } /* Note that we can't bail immediately on error as this will leak refcounts on any 'N' arguments. */ for (i = 0; i < n; i++) { PyObject *w = do_mkvalue(p_format, p_va); if (w == NULL) { do_ignore(p_format, p_va, endchar, n - i - 1); goto error; } stack[i] = w; } if (**p_format != endchar) { PyErr_SetString(PyExc_SystemError, "Unmatched paren in format"); goto error; } if (endchar) { ++*p_format; } return 0; error: n = i; for (i=0; i < n; i++) { Py_DECREF(stack[i]); } return -1; } static PyObject * do_mktuple(const char **p_format, va_list *p_va, char endchar, Py_ssize_t n) { PyObject *v; Py_ssize_t i; if (n < 0) return NULL; /* Note that we can't bail immediately on error as this will leak refcounts on any 'N' arguments. */ if ((v = PyTuple_New(n)) == NULL) { do_ignore(p_format, p_va, endchar, n); return NULL; } for (i = 0; i < n; i++) { PyObject *w = do_mkvalue(p_format, p_va); if (w == NULL) { do_ignore(p_format, p_va, endchar, n - i - 1); Py_DECREF(v); return NULL; } PyTuple_SET_ITEM(v, i, w); } if (**p_format != endchar) { Py_DECREF(v); PyErr_SetString(PyExc_SystemError, "Unmatched paren in format"); return NULL; } if (endchar) ++*p_format; return v; } static PyObject * do_mkvalue(const char **p_format, va_list *p_va) { for (;;) { switch (*(*p_format)++) { case '(': return do_mktuple(p_format, p_va, ')', countformat(*p_format, ')')); case '[': return do_mklist(p_format, p_va, ']', countformat(*p_format, ']')); case '{': return do_mkdict(p_format, p_va, '}', countformat(*p_format, '}')); case 'b': case 'B': case 'h': case 'i': return PyLong_FromLong((long)va_arg(*p_va, int)); case 'H': return PyLong_FromLong((long)va_arg(*p_va, unsigned int)); case 'I': { unsigned int n; n = va_arg(*p_va, unsigned int); return PyLong_FromUnsignedLong(n); } case 'n': #if SIZEOF_SIZE_T!=SIZEOF_LONG return PyLong_FromSsize_t(va_arg(*p_va, Py_ssize_t)); #endif /* Fall through from 'n' to 'l' if Py_ssize_t is long */ case 'l': return PyLong_FromLong(va_arg(*p_va, long)); case 'k': { unsigned long n; n = va_arg(*p_va, unsigned long); return PyLong_FromUnsignedLong(n); } case 'L': return PyLong_FromLongLong((long long)va_arg(*p_va, long long)); case 'K': return PyLong_FromUnsignedLongLong((long long)va_arg(*p_va, unsigned long long)); case 'u': { PyObject *v; const wchar_t *u = va_arg(*p_va, wchar_t*); Py_ssize_t n; if (**p_format == '#') { ++*p_format; n = va_arg(*p_va, Py_ssize_t); } else n = -1; if (u == NULL) { v = Py_NewRef(Py_None); } else { if (n < 0) n = wcslen(u); v = PyUnicode_FromWideChar(u, n); } return v; } case 'f': case 'd': return PyFloat_FromDouble( (double)va_arg(*p_va, va_double)); case 'D': return PyComplex_FromCComplex( *((Py_complex *)va_arg(*p_va, Py_complex *))); case 'c': { char p[1]; p[0] = (char)va_arg(*p_va, int); return PyBytes_FromStringAndSize(p, 1); } case 'C': { int i = va_arg(*p_va, int); return PyUnicode_FromOrdinal(i); } case 's': case 'z': case 'U': /* XXX deprecated alias */ { PyObject *v; const char *str = va_arg(*p_va, const char *); Py_ssize_t n; if (**p_format == '#') { ++*p_format; n = va_arg(*p_va, Py_ssize_t); } else n = -1; if (str == NULL) { v = Py_NewRef(Py_None); } else { if (n < 0) { size_t m = strlen(str); if (m > PY_SSIZE_T_MAX) { PyErr_SetString(PyExc_OverflowError, "string too long for Python string"); return NULL; } n = (Py_ssize_t)m; } v = PyUnicode_FromStringAndSize(str, n); } return v; } case 'y': { PyObject *v; const char *str = va_arg(*p_va, const char *); Py_ssize_t n; if (**p_format == '#') { ++*p_format; n = va_arg(*p_va, Py_ssize_t); } else n = -1; if (str == NULL) { v = Py_NewRef(Py_None); } else { if (n < 0) { size_t m = strlen(str); if (m > PY_SSIZE_T_MAX) { PyErr_SetString(PyExc_OverflowError, "string too long for Python bytes"); return NULL; } n = (Py_ssize_t)m; } v = PyBytes_FromStringAndSize(str, n); } return v; } case 'N': case 'S': case 'O': if (**p_format == '&') { typedef PyObject *(*converter)(void *); converter func = va_arg(*p_va, converter); void *arg = va_arg(*p_va, void *); ++*p_format; return (*func)(arg); } else { PyObject *v; v = va_arg(*p_va, PyObject *); if (v != NULL) { if (*(*p_format - 1) != 'N') Py_INCREF(v); } else if (!PyErr_Occurred()) /* If a NULL was passed * because a call that should * have constructed a value * failed, that's OK, and we * pass the error on; but if * no error occurred it's not * clear that the caller knew * what she was doing. */ PyErr_SetString(PyExc_SystemError, "NULL object passed to Py_BuildValue"); return v; } case ':': case ',': case ' ': case '\t': break; default: PyErr_SetString(PyExc_SystemError, "bad format char passed to Py_BuildValue"); return NULL; } } } PyObject * Py_BuildValue(const char *format, ...) { va_list va; PyObject* retval; va_start(va, format); retval = va_build_value(format, va); va_end(va); return retval; } PyAPI_FUNC(PyObject *) /* abi only */ _Py_BuildValue_SizeT(const char *format, ...) { va_list va; PyObject* retval; va_start(va, format); retval = va_build_value(format, va); va_end(va); return retval; } PyObject * Py_VaBuildValue(const char *format, va_list va) { return va_build_value(format, va); } PyAPI_FUNC(PyObject *) /* abi only */ _Py_VaBuildValue_SizeT(const char *format, va_list va) { return va_build_value(format, va); } static PyObject * va_build_value(const char *format, va_list va) { const char *f = format; Py_ssize_t n = countformat(f, '\0'); va_list lva; PyObject *retval; if (n < 0) return NULL; if (n == 0) { Py_RETURN_NONE; } va_copy(lva, va); if (n == 1) { retval = do_mkvalue(&f, &lva); } else { retval = do_mktuple(&f, &lva, '\0', n); } va_end(lva); return retval; } PyObject ** _Py_VaBuildStack(PyObject **small_stack, Py_ssize_t small_stack_len, const char *format, va_list va, Py_ssize_t *p_nargs) { const char *f; Py_ssize_t n; va_list lva; PyObject **stack; int res; n = countformat(format, '\0'); if (n < 0) { *p_nargs = 0; return NULL; } if (n == 0) { *p_nargs = 0; return small_stack; } if (n <= small_stack_len) { stack = small_stack; } else { stack = PyMem_Malloc(n * sizeof(stack[0])); if (stack == NULL) { PyErr_NoMemory(); return NULL; } } va_copy(lva, va); f = format; res = do_mkstack(stack, &f, &lva, '\0', n); va_end(lva); if (res < 0) { if (stack != small_stack) { PyMem_Free(stack); } return NULL; } *p_nargs = n; return stack; } int PyModule_AddObjectRef(PyObject *mod, const char *name, PyObject *value) { if (!PyModule_Check(mod)) { PyErr_SetString(PyExc_TypeError, "PyModule_AddObjectRef() first argument " "must be a module"); return -1; } if (!value) { if (!PyErr_Occurred()) { PyErr_SetString(PyExc_SystemError, "PyModule_AddObjectRef() must be called " "with an exception raised if value is NULL"); } return -1; } PyObject *dict = PyModule_GetDict(mod); if (dict == NULL) { /* Internal error -- modules must have a dict! */ PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__", PyModule_GetName(mod)); return -1; } if (PyDict_SetItemString(dict, name, value)) { return -1; } return 0; } int PyModule_AddObject(PyObject *mod, const char *name, PyObject *value) { int res = PyModule_AddObjectRef(mod, name, value); if (res == 0) { Py_DECREF(value); } return res; } int PyModule_AddIntConstant(PyObject *m, const char *name, long value) { PyObject *obj = PyLong_FromLong(value); if (!obj) { return -1; } int res = PyModule_AddObjectRef(m, name, obj); Py_DECREF(obj); return res; } int PyModule_AddStringConstant(PyObject *m, const char *name, const char *value) { PyObject *obj = PyUnicode_FromString(value); if (!obj) { return -1; } int res = PyModule_AddObjectRef(m, name, obj); Py_DECREF(obj); return res; } int PyModule_AddType(PyObject *module, PyTypeObject *type) { if (!_PyType_IsReady(type) && PyType_Ready(type) < 0) { return -1; } const char *name = _PyType_Name(type); assert(name != NULL); return PyModule_AddObjectRef(module, name, (PyObject *)type); } ================================================ FILE: MySnPrintf.c ================================================ #include "Python.h" /* snprintf() and vsnprintf() wrappers. If the platform has vsnprintf, we use it, else we emulate it in a half-hearted way. Even if the platform has it, we wrap it because platforms differ in what vsnprintf does in case the buffer is too small: C99 behavior is to return the number of characters that would have been written had the buffer not been too small, and to set the last byte of the buffer to \0. At least MS _vsnprintf returns a negative value instead, and fills the entire buffer with non-\0 data. Unlike C99, our wrappers do not support passing a null buffer. The wrappers ensure that str[size-1] is always \0 upon return. PyOS_snprintf and PyOS_vsnprintf never write more than size bytes (including the trailing '\0') into str. Return value (rv): When 0 <= rv < size, the output conversion was unexceptional, and rv characters were written to str (excluding a trailing \0 byte at str[rv]). When rv >= size, output conversion was truncated, and a buffer of size rv+1 would have been needed to avoid truncation. str[size-1] is \0 in this case. When rv < 0, "something bad happened". str[size-1] is \0 in this case too, but the rest of str is unreliable. It could be that an error in format codes was detected by libc, or on platforms with a non-C99 vsnprintf simply that the buffer wasn't big enough to avoid truncation, or on platforms without any vsnprintf that PyMem_Malloc couldn't obtain space for a temp buffer. CAUTION: Unlike C99, str != NULL and size > 0 are required. Also, size must be smaller than INT_MAX. */ int PyOS_snprintf(char *str, size_t size, const char *format, ...) { int rc; va_list va; va_start(va, format); rc = PyOS_vsnprintf(str, size, format, va); va_end(va); return rc; } int PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va) { assert(str != NULL); assert(size > 0); assert(size <= (INT_MAX - 1)); assert(format != NULL); int len; /* # bytes written, excluding \0 */ /* We take a size_t as input but return an int. Sanity check * our input so that it won't cause an overflow in the * vsnprintf return value. */ if (size > INT_MAX - 1) { len = -666; goto Done; } #if defined(_MSC_VER) len = _vsnprintf(str, size, format, va); #else len = vsnprintf(str, size, format, va); #endif Done: if (size > 0) { str[size-1] = '\0'; } return len; } ================================================ FILE: MyStrtoul.c ================================================ #include "Python.h" #include "pycore_long.h" // _PyLong_DigitValue #if defined(__sgi) && !defined(_SGI_MP_SOURCE) #define _SGI_MP_SOURCE #endif /* strtol and strtoul, renamed to avoid conflicts */ #include #ifdef HAVE_ERRNO_H #include #endif /* Static overflow check values for bases 2 through 36. * smallmax[base] is the largest unsigned long i such that * i * base doesn't overflow unsigned long. */ static const unsigned long smallmax[] = { 0, /* bases 0 and 1 are invalid */ 0, ULONG_MAX / 2, ULONG_MAX / 3, ULONG_MAX / 4, ULONG_MAX / 5, ULONG_MAX / 6, ULONG_MAX / 7, ULONG_MAX / 8, ULONG_MAX / 9, ULONG_MAX / 10, ULONG_MAX / 11, ULONG_MAX / 12, ULONG_MAX / 13, ULONG_MAX / 14, ULONG_MAX / 15, ULONG_MAX / 16, ULONG_MAX / 17, ULONG_MAX / 18, ULONG_MAX / 19, ULONG_MAX / 20, ULONG_MAX / 21, ULONG_MAX / 22, ULONG_MAX / 23, ULONG_MAX / 24, ULONG_MAX / 25, ULONG_MAX / 26, ULONG_MAX / 27, ULONG_MAX / 28, ULONG_MAX / 29, ULONG_MAX / 30, ULONG_MAX / 31, ULONG_MAX / 32, ULONG_MAX / 33, ULONG_MAX / 34, ULONG_MAX / 35, ULONG_MAX / 36, }; /* maximum digits that can't ever overflow for bases 2 through 36, * calculated by [int(math.floor(math.log(2**32, i))) for i in range(2, 37)]. * Note that this is pessimistic if sizeof(long) > 4. */ #if SIZEOF_LONG == 4 static const int digitlimit[] = { 0, 0, 32, 20, 16, 13, 12, 11, 10, 10, /* 0 - 9 */ 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, /* 10 - 19 */ 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, /* 20 - 29 */ 6, 6, 6, 6, 6, 6, 6}; /* 30 - 36 */ #elif SIZEOF_LONG == 8 /* [int(math.floor(math.log(2**64, i))) for i in range(2, 37)] */ static const int digitlimit[] = { 0, 0, 64, 40, 32, 27, 24, 22, 21, 20, /* 0 - 9 */ 19, 18, 17, 17, 16, 16, 16, 15, 15, 15, /* 10 - 19 */ 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, /* 20 - 29 */ 13, 12, 12, 12, 12, 12, 12}; /* 30 - 36 */ #else #error "Need table for SIZEOF_LONG" #endif /* ** strtoul ** This is a general purpose routine for converting ** an ascii string to an integer in an arbitrary base. ** Leading white space is ignored. If 'base' is zero ** it looks for a leading 0b, 0o or 0x to tell which ** base. If these are absent it defaults to 10. ** Base must be 0 or between 2 and 36 (inclusive). ** If 'ptr' is non-NULL it will contain a pointer to ** the end of the scan. ** Errors due to bad pointers will probably result in ** exceptions - we don't check for them. */ unsigned long PyOS_strtoul(const char *str, char **ptr, int base) { unsigned long result = 0; /* return value of the function */ int c; /* current input character */ int ovlimit; /* required digits to overflow */ /* skip leading white space */ while (*str && Py_ISSPACE(*str)) ++str; /* check for leading 0b, 0o or 0x for auto-base or base 16 */ switch (base) { case 0: /* look for leading 0b, 0o or 0x */ if (*str == '0') { ++str; if (*str == 'x' || *str == 'X') { /* there must be at least one digit after 0x */ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) { if (ptr) *ptr = (char *)str; return 0; } ++str; base = 16; } else if (*str == 'o' || *str == 'O') { /* there must be at least one digit after 0o */ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) { if (ptr) *ptr = (char *)str; return 0; } ++str; base = 8; } else if (*str == 'b' || *str == 'B') { /* there must be at least one digit after 0b */ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) { if (ptr) *ptr = (char *)str; return 0; } ++str; base = 2; } else { /* skip all zeroes... */ while (*str == '0') ++str; while (Py_ISSPACE(*str)) ++str; if (ptr) *ptr = (char *)str; return 0; } } else base = 10; break; /* even with explicit base, skip leading 0? prefix */ case 16: if (*str == '0') { ++str; if (*str == 'x' || *str == 'X') { /* there must be at least one digit after 0x */ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) { if (ptr) *ptr = (char *)str; return 0; } ++str; } } break; case 8: if (*str == '0') { ++str; if (*str == 'o' || *str == 'O') { /* there must be at least one digit after 0o */ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) { if (ptr) *ptr = (char *)str; return 0; } ++str; } } break; case 2: if(*str == '0') { ++str; if (*str == 'b' || *str == 'B') { /* there must be at least one digit after 0b */ if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) { if (ptr) *ptr = (char *)str; return 0; } ++str; } } break; } /* catch silly bases */ if (base < 2 || base > 36) { if (ptr) *ptr = (char *)str; return 0; } /* skip leading zeroes */ while (*str == '0') ++str; /* base is guaranteed to be in [2, 36] at this point */ ovlimit = digitlimit[base]; /* do the conversion until non-digit character encountered */ while ((c = _PyLong_DigitValue[Py_CHARMASK(*str)]) < base) { if (ovlimit > 0) /* no overflow check required */ result = result * base + c; else { /* requires overflow check */ unsigned long temp_result; if (ovlimit < 0) /* guaranteed overflow */ goto overflowed; /* there could be an overflow */ /* check overflow just from shifting */ if (result > smallmax[base]) goto overflowed; result *= base; /* check overflow from the digit's value */ temp_result = result + c; if (temp_result < result) goto overflowed; result = temp_result; } ++str; --ovlimit; } /* set pointer to point to the last character scanned */ if (ptr) *ptr = (char *)str; return result; overflowed: if (ptr) { /* spool through remaining digit characters */ while (_PyLong_DigitValue[Py_CHARMASK(*str)] < base) ++str; *ptr = (char *)str; } errno = ERANGE; return (unsigned long)-1; } /* Checking for overflow in PyOS_strtol is a PITA; see comments * about PY_ABS_LONG_MIN in longobject.c. */ #define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN) long PyOS_strtol(const char *str, char **ptr, int base) { long result; unsigned long uresult; char sign; while (*str && Py_ISSPACE(*str)) str++; sign = *str; if (sign == '+' || sign == '-') str++; uresult = PyOS_strtoul(str, ptr, base); if (uresult <= (unsigned long)LONG_MAX) { result = (long)uresult; if (sign == '-') result = -result; } else if (sign == '-' && uresult == PY_ABS_LONG_MIN) { result = LONG_MIN; } else { errno = ERANGE; result = LONG_MAX; } return result; } ================================================ FILE: OpCode_MetaData.h ================================================ // This file is generated by Tools/cases_generator/generate_cases.py // from: // Python/bytecodes.c // Do not edit! #ifndef NEED_OPCODE_METADATA extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); #else int _PyOpcode_num_popped(int opcode, int oparg, bool jump) { switch(opcode) { case NOP: return 0; case RESUME: return 0; case INSTRUMENTED_RESUME: return 0; case LOAD_CLOSURE: return 0; case LOAD_FAST_CHECK: return 0; case LOAD_FAST: return 0; case LOAD_FAST_AND_CLEAR: return 0; case LOAD_CONST: return 0; case STORE_FAST: return 1; case LOAD_FAST__LOAD_FAST: return 0+0; case LOAD_FAST__LOAD_CONST: return 0+0; case STORE_FAST__LOAD_FAST: return 1+0; case STORE_FAST__STORE_FAST: return 1+1; case LOAD_CONST__LOAD_FAST: return 0+0; case POP_TOP: return 1; case PUSH_NULL: return 0; case END_FOR: return 2; case INSTRUMENTED_END_FOR: return 2; case END_SEND: return 2; case INSTRUMENTED_END_SEND: return 2; case UNARY_NEGATIVE: return 1; case UNARY_NOT: return 1; case UNARY_INVERT: return 1; case BINARY_OP_MULTIPLY_INT: return 2; case BINARY_OP_ADD_INT: return 2; case BINARY_OP_SUBTRACT_INT: return 2; case BINARY_OP_MULTIPLY_FLOAT: return 2; case BINARY_OP_ADD_FLOAT: return 2; case BINARY_OP_SUBTRACT_FLOAT: return 2; case BINARY_OP_ADD_UNICODE: return 2; case BINARY_OP_INPLACE_ADD_UNICODE: return 2; case BINARY_SUBSCR: return 2; case BINARY_SLICE: return 3; case STORE_SLICE: return 4; case BINARY_SUBSCR_LIST_INT: return 2; case BINARY_SUBSCR_TUPLE_INT: return 2; case BINARY_SUBSCR_DICT: return 2; case BINARY_SUBSCR_GETITEM: return 2; case LIST_APPEND: return (oparg-1) + 2; case SET_ADD: return (oparg-1) + 2; case STORE_SUBSCR: return 3; case STORE_SUBSCR_LIST_INT: return 3; case STORE_SUBSCR_DICT: return 3; case DELETE_SUBSCR: return 2; case CALL_INTRINSIC_1: return 1; case CALL_INTRINSIC_2: return 2; case RAISE_VARARGS: return oparg; case INTERPRETER_EXIT: return 1; case RETURN_VALUE: return 1; case INSTRUMENTED_RETURN_VALUE: return 1; case RETURN_CONST: return 0; case INSTRUMENTED_RETURN_CONST: return 0; case GET_AITER: return 1; case GET_ANEXT: return 1; case GET_AWAITABLE: return 1; case SEND: return 2; case SEND_GEN: return 2; case INSTRUMENTED_YIELD_VALUE: return 1; case YIELD_VALUE: return 1; case POP_EXCEPT: return 1; case RERAISE: return oparg + 1; case END_ASYNC_FOR: return 2; case CLEANUP_THROW: return 3; case LOAD_ASSERTION_ERROR: return 0; case LOAD_BUILD_CLASS: return 0; case STORE_NAME: return 1; case DELETE_NAME: return 0; case UNPACK_SEQUENCE: return 1; case UNPACK_SEQUENCE_TWO_TUPLE: return 1; case UNPACK_SEQUENCE_TUPLE: return 1; case UNPACK_SEQUENCE_LIST: return 1; case UNPACK_EX: return 1; case STORE_ATTR: return 2; case DELETE_ATTR: return 1; case STORE_GLOBAL: return 1; case DELETE_GLOBAL: return 0; case LOAD_LOCALS: return 0; case LOAD_NAME: return 0; case LOAD_FROM_DICT_OR_GLOBALS: return 1; case LOAD_GLOBAL: return 0; case LOAD_GLOBAL_MODULE: return 0; case LOAD_GLOBAL_BUILTIN: return 0; case DELETE_FAST: return 0; case MAKE_CELL: return 0; case DELETE_DEREF: return 0; case LOAD_FROM_DICT_OR_DEREF: return 1; case LOAD_DEREF: return 0; case STORE_DEREF: return 1; case COPY_FREE_VARS: return 0; case BUILD_STRING: return oparg; case BUILD_TUPLE: return oparg; case BUILD_LIST: return oparg; case LIST_EXTEND: return (oparg-1) + 2; case SET_UPDATE: return (oparg-1) + 2; case BUILD_SET: return oparg; case BUILD_MAP: return oparg*2; case SETUP_ANNOTATIONS: return 0; case BUILD_CONST_KEY_MAP: return oparg + 1; case DICT_UPDATE: return 1; case DICT_MERGE: return 1; case MAP_ADD: return 2; case INSTRUMENTED_LOAD_SUPER_ATTR: return 3; case LOAD_SUPER_ATTR: return 3; case LOAD_SUPER_ATTR_ATTR: return 3; case LOAD_SUPER_ATTR_METHOD: return 3; case LOAD_ATTR: return 1; case LOAD_ATTR_INSTANCE_VALUE: return 1; case LOAD_ATTR_MODULE: return 1; case LOAD_ATTR_WITH_HINT: return 1; case LOAD_ATTR_SLOT: return 1; case LOAD_ATTR_CLASS: return 1; case LOAD_ATTR_PROPERTY: return 1; case LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN: return 1; case STORE_ATTR_INSTANCE_VALUE: return 2; case STORE_ATTR_WITH_HINT: return 2; case STORE_ATTR_SLOT: return 2; case COMPARE_OP: return 2; case COMPARE_OP_FLOAT: return 2; case COMPARE_OP_INT: return 2; case COMPARE_OP_STR: return 2; case IS_OP: return 2; case CONTAINS_OP: return 2; case CHECK_EG_MATCH: return 2; case CHECK_EXC_MATCH: return 2; case IMPORT_NAME: return 2; case IMPORT_FROM: return 1; case JUMP_FORWARD: return 0; case JUMP_BACKWARD: return 0; case POP_JUMP_IF_FALSE: return 1; case POP_JUMP_IF_TRUE: return 1; case POP_JUMP_IF_NOT_NONE: return 1; case POP_JUMP_IF_NONE: return 1; case JUMP_BACKWARD_NO_INTERRUPT: return 0; case GET_LEN: return 1; case MATCH_CLASS: return 3; case MATCH_MAPPING: return 1; case MATCH_SEQUENCE: return 1; case MATCH_KEYS: return 2; case GET_ITER: return 1; case GET_YIELD_FROM_ITER: return 1; case FOR_ITER: return 1; case INSTRUMENTED_FOR_ITER: return 0; case FOR_ITER_LIST: return 1; case FOR_ITER_TUPLE: return 1; case FOR_ITER_RANGE: return 1; case FOR_ITER_GEN: return 1; case BEFORE_ASYNC_WITH: return 1; case BEFORE_WITH: return 1; case WITH_EXCEPT_START: return 4; case PUSH_EXC_INFO: return 1; case LOAD_ATTR_METHOD_WITH_VALUES: return 1; case LOAD_ATTR_METHOD_NO_DICT: return 1; case LOAD_ATTR_METHOD_LAZY_DICT: return 1; case KW_NAMES: return 0; case INSTRUMENTED_CALL: return 0; case CALL: return oparg + 2; case CALL_BOUND_METHOD_EXACT_ARGS: return oparg + 2; case CALL_PY_EXACT_ARGS: return oparg + 2; case CALL_PY_WITH_DEFAULTS: return oparg + 2; case CALL_NO_KW_TYPE_1: return oparg + 2; case CALL_NO_KW_STR_1: return oparg + 2; case CALL_NO_KW_TUPLE_1: return oparg + 2; case CALL_BUILTIN_CLASS: return oparg + 2; case CALL_NO_KW_BUILTIN_O: return oparg + 2; case CALL_NO_KW_BUILTIN_FAST: return oparg + 2; case CALL_BUILTIN_FAST_WITH_KEYWORDS: return oparg + 2; case CALL_NO_KW_LEN: return oparg + 2; case CALL_NO_KW_ISINSTANCE: return oparg + 2; case CALL_NO_KW_LIST_APPEND: return oparg + 2; case CALL_NO_KW_METHOD_DESCRIPTOR_O: return oparg + 2; case CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: return oparg + 2; case CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS: return oparg + 2; case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: return oparg + 2; case INSTRUMENTED_CALL_FUNCTION_EX: return 0; case CALL_FUNCTION_EX: return ((oparg & 1) ? 1 : 0) + 3; case MAKE_FUNCTION: return ((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0) + 1; case RETURN_GENERATOR: return 0; case BUILD_SLICE: return ((oparg == 3) ? 1 : 0) + 2; case FORMAT_VALUE: return (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0) + 1; case COPY: return (oparg-1) + 1; case BINARY_OP: return 2; case SWAP: return (oparg-2) + 2; case INSTRUMENTED_INSTRUCTION: return 0; case INSTRUMENTED_JUMP_FORWARD: return 0; case INSTRUMENTED_JUMP_BACKWARD: return 0; case INSTRUMENTED_POP_JUMP_IF_TRUE: return 0; case INSTRUMENTED_POP_JUMP_IF_FALSE: return 0; case INSTRUMENTED_POP_JUMP_IF_NONE: return 0; case INSTRUMENTED_POP_JUMP_IF_NOT_NONE: return 0; case EXTENDED_ARG: return 0; case CACHE: return 0; case RESERVED: return 0; default: return -1; } } #endif #ifndef NEED_OPCODE_METADATA extern int _PyOpcode_num_pushed(int opcode, int oparg, bool jump); #else int _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { switch(opcode) { case NOP: return 0; case RESUME: return 0; case INSTRUMENTED_RESUME: return 0; case LOAD_CLOSURE: return 1; case LOAD_FAST_CHECK: return 1; case LOAD_FAST: return 1; case LOAD_FAST_AND_CLEAR: return 1; case LOAD_CONST: return 1; case STORE_FAST: return 0; case LOAD_FAST__LOAD_FAST: return 1+1; case LOAD_FAST__LOAD_CONST: return 1+1; case STORE_FAST__LOAD_FAST: return 0+1; case STORE_FAST__STORE_FAST: return 0+0; case LOAD_CONST__LOAD_FAST: return 1+1; case POP_TOP: return 0; case PUSH_NULL: return 1; case END_FOR: return 0; case INSTRUMENTED_END_FOR: return 0; case END_SEND: return 1; case INSTRUMENTED_END_SEND: return 1; case UNARY_NEGATIVE: return 1; case UNARY_NOT: return 1; case UNARY_INVERT: return 1; case BINARY_OP_MULTIPLY_INT: return 1; case BINARY_OP_ADD_INT: return 1; case BINARY_OP_SUBTRACT_INT: return 1; case BINARY_OP_MULTIPLY_FLOAT: return 1; case BINARY_OP_ADD_FLOAT: return 1; case BINARY_OP_SUBTRACT_FLOAT: return 1; case BINARY_OP_ADD_UNICODE: return 1; case BINARY_OP_INPLACE_ADD_UNICODE: return 0; case BINARY_SUBSCR: return 1; case BINARY_SLICE: return 1; case STORE_SLICE: return 0; case BINARY_SUBSCR_LIST_INT: return 1; case BINARY_SUBSCR_TUPLE_INT: return 1; case BINARY_SUBSCR_DICT: return 1; case BINARY_SUBSCR_GETITEM: return 1; case LIST_APPEND: return (oparg-1) + 1; case SET_ADD: return (oparg-1) + 1; case STORE_SUBSCR: return 0; case STORE_SUBSCR_LIST_INT: return 0; case STORE_SUBSCR_DICT: return 0; case DELETE_SUBSCR: return 0; case CALL_INTRINSIC_1: return 1; case CALL_INTRINSIC_2: return 1; case RAISE_VARARGS: return 0; case INTERPRETER_EXIT: return 0; case RETURN_VALUE: return 0; case INSTRUMENTED_RETURN_VALUE: return 0; case RETURN_CONST: return 0; case INSTRUMENTED_RETURN_CONST: return 0; case GET_AITER: return 1; case GET_ANEXT: return 2; case GET_AWAITABLE: return 1; case SEND: return 2; case SEND_GEN: return 2; case INSTRUMENTED_YIELD_VALUE: return 1; case YIELD_VALUE: return 1; case POP_EXCEPT: return 0; case RERAISE: return oparg; case END_ASYNC_FOR: return 0; case CLEANUP_THROW: return 2; case LOAD_ASSERTION_ERROR: return 1; case LOAD_BUILD_CLASS: return 1; case STORE_NAME: return 0; case DELETE_NAME: return 0; case UNPACK_SEQUENCE: return oparg; case UNPACK_SEQUENCE_TWO_TUPLE: return oparg; case UNPACK_SEQUENCE_TUPLE: return oparg; case UNPACK_SEQUENCE_LIST: return oparg; case UNPACK_EX: return (oparg & 0xFF) + (oparg >> 8) + 1; case STORE_ATTR: return 0; case DELETE_ATTR: return 0; case STORE_GLOBAL: return 0; case DELETE_GLOBAL: return 0; case LOAD_LOCALS: return 1; case LOAD_NAME: return 1; case LOAD_FROM_DICT_OR_GLOBALS: return 1; case LOAD_GLOBAL: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_GLOBAL_MODULE: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_GLOBAL_BUILTIN: return ((oparg & 1) ? 1 : 0) + 1; case DELETE_FAST: return 0; case MAKE_CELL: return 0; case DELETE_DEREF: return 0; case LOAD_FROM_DICT_OR_DEREF: return 1; case LOAD_DEREF: return 1; case STORE_DEREF: return 0; case COPY_FREE_VARS: return 0; case BUILD_STRING: return 1; case BUILD_TUPLE: return 1; case BUILD_LIST: return 1; case LIST_EXTEND: return (oparg-1) + 1; case SET_UPDATE: return (oparg-1) + 1; case BUILD_SET: return 1; case BUILD_MAP: return 1; case SETUP_ANNOTATIONS: return 0; case BUILD_CONST_KEY_MAP: return 1; case DICT_UPDATE: return 0; case DICT_MERGE: return 0; case MAP_ADD: return 0; case INSTRUMENTED_LOAD_SUPER_ATTR: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_SUPER_ATTR: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_SUPER_ATTR_ATTR: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_SUPER_ATTR_METHOD: return 2; case LOAD_ATTR: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_ATTR_INSTANCE_VALUE: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_ATTR_MODULE: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_ATTR_WITH_HINT: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_ATTR_SLOT: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_ATTR_CLASS: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_ATTR_PROPERTY: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN: return ((oparg & 1) ? 1 : 0) + 1; case STORE_ATTR_INSTANCE_VALUE: return 0; case STORE_ATTR_WITH_HINT: return 0; case STORE_ATTR_SLOT: return 0; case COMPARE_OP: return 1; case COMPARE_OP_FLOAT: return 1; case COMPARE_OP_INT: return 1; case COMPARE_OP_STR: return 1; case IS_OP: return 1; case CONTAINS_OP: return 1; case CHECK_EG_MATCH: return 2; case CHECK_EXC_MATCH: return 2; case IMPORT_NAME: return 1; case IMPORT_FROM: return 2; case JUMP_FORWARD: return 0; case JUMP_BACKWARD: return 0; case POP_JUMP_IF_FALSE: return 0; case POP_JUMP_IF_TRUE: return 0; case POP_JUMP_IF_NOT_NONE: return 0; case POP_JUMP_IF_NONE: return 0; case JUMP_BACKWARD_NO_INTERRUPT: return 0; case GET_LEN: return 2; case MATCH_CLASS: return 1; case MATCH_MAPPING: return 2; case MATCH_SEQUENCE: return 2; case MATCH_KEYS: return 3; case GET_ITER: return 1; case GET_YIELD_FROM_ITER: return 1; case FOR_ITER: return 2; case INSTRUMENTED_FOR_ITER: return 0; case FOR_ITER_LIST: return 2; case FOR_ITER_TUPLE: return 2; case FOR_ITER_RANGE: return 2; case FOR_ITER_GEN: return 2; case BEFORE_ASYNC_WITH: return 2; case BEFORE_WITH: return 2; case WITH_EXCEPT_START: return 5; case PUSH_EXC_INFO: return 2; case LOAD_ATTR_METHOD_WITH_VALUES: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_ATTR_METHOD_NO_DICT: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_ATTR_METHOD_LAZY_DICT: return ((oparg & 1) ? 1 : 0) + 1; case KW_NAMES: return 0; case INSTRUMENTED_CALL: return 0; case CALL: return 1; case CALL_BOUND_METHOD_EXACT_ARGS: return 1; case CALL_PY_EXACT_ARGS: return 1; case CALL_PY_WITH_DEFAULTS: return 1; case CALL_NO_KW_TYPE_1: return 1; case CALL_NO_KW_STR_1: return 1; case CALL_NO_KW_TUPLE_1: return 1; case CALL_BUILTIN_CLASS: return 1; case CALL_NO_KW_BUILTIN_O: return 1; case CALL_NO_KW_BUILTIN_FAST: return 1; case CALL_BUILTIN_FAST_WITH_KEYWORDS: return 1; case CALL_NO_KW_LEN: return 1; case CALL_NO_KW_ISINSTANCE: return 1; case CALL_NO_KW_LIST_APPEND: return 1; case CALL_NO_KW_METHOD_DESCRIPTOR_O: return 1; case CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: return 1; case CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS: return 1; case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: return 1; case INSTRUMENTED_CALL_FUNCTION_EX: return 0; case CALL_FUNCTION_EX: return 1; case MAKE_FUNCTION: return 1; case RETURN_GENERATOR: return 0; case BUILD_SLICE: return 1; case FORMAT_VALUE: return 1; case COPY: return (oparg-1) + 2; case BINARY_OP: return 1; case SWAP: return (oparg-2) + 2; case INSTRUMENTED_INSTRUCTION: return 0; case INSTRUMENTED_JUMP_FORWARD: return 0; case INSTRUMENTED_JUMP_BACKWARD: return 0; case INSTRUMENTED_POP_JUMP_IF_TRUE: return 0; case INSTRUMENTED_POP_JUMP_IF_FALSE: return 0; case INSTRUMENTED_POP_JUMP_IF_NONE: return 0; case INSTRUMENTED_POP_JUMP_IF_NOT_NONE: return 0; case EXTENDED_ARG: return 0; case CACHE: return 0; case RESERVED: return 0; default: return -1; } } #endif enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; struct opcode_metadata { bool valid_entry; enum InstructionFormat instr_format; }; #ifndef NEED_OPCODE_METADATA extern const struct opcode_metadata _PyOpcode_opcode_metadata[256]; #else const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [NOP] = { true, INSTR_FMT_IX }, [RESUME] = { true, INSTR_FMT_IB }, [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB }, [LOAD_CLOSURE] = { true, INSTR_FMT_IB }, [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB }, [LOAD_FAST] = { true, INSTR_FMT_IB }, [LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB }, [LOAD_CONST] = { true, INSTR_FMT_IB }, [STORE_FAST] = { true, INSTR_FMT_IB }, [LOAD_FAST__LOAD_FAST] = { true, INSTR_FMT_IBIB }, [LOAD_FAST__LOAD_CONST] = { true, INSTR_FMT_IBIB }, [STORE_FAST__LOAD_FAST] = { true, INSTR_FMT_IBIB }, [STORE_FAST__STORE_FAST] = { true, INSTR_FMT_IBIB }, [LOAD_CONST__LOAD_FAST] = { true, INSTR_FMT_IBIB }, [POP_TOP] = { true, INSTR_FMT_IX }, [PUSH_NULL] = { true, INSTR_FMT_IX }, [END_FOR] = { true, INSTR_FMT_IB }, [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX }, [END_SEND] = { true, INSTR_FMT_IX }, [INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX }, [UNARY_NEGATIVE] = { true, INSTR_FMT_IX }, [UNARY_NOT] = { true, INSTR_FMT_IX }, [UNARY_INVERT] = { true, INSTR_FMT_IX }, [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IBC }, [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IBC }, [BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IBC }, [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IBC }, [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IBC }, [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IBC }, [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IBC }, [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IB }, [BINARY_SUBSCR] = { true, INSTR_FMT_IXC }, [BINARY_SLICE] = { true, INSTR_FMT_IX }, [STORE_SLICE] = { true, INSTR_FMT_IX }, [BINARY_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC }, [BINARY_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC }, [BINARY_SUBSCR_DICT] = { true, INSTR_FMT_IXC }, [BINARY_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC }, [LIST_APPEND] = { true, INSTR_FMT_IB }, [SET_ADD] = { true, INSTR_FMT_IB }, [STORE_SUBSCR] = { true, INSTR_FMT_IXC }, [STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC }, [STORE_SUBSCR_DICT] = { true, INSTR_FMT_IXC }, [DELETE_SUBSCR] = { true, INSTR_FMT_IX }, [CALL_INTRINSIC_1] = { true, INSTR_FMT_IB }, [CALL_INTRINSIC_2] = { true, INSTR_FMT_IB }, [RAISE_VARARGS] = { true, INSTR_FMT_IB }, [INTERPRETER_EXIT] = { true, INSTR_FMT_IX }, [RETURN_VALUE] = { true, INSTR_FMT_IX }, [INSTRUMENTED_RETURN_VALUE] = { true, INSTR_FMT_IX }, [RETURN_CONST] = { true, INSTR_FMT_IB }, [INSTRUMENTED_RETURN_CONST] = { true, INSTR_FMT_IB }, [GET_AITER] = { true, INSTR_FMT_IX }, [GET_ANEXT] = { true, INSTR_FMT_IX }, [GET_AWAITABLE] = { true, INSTR_FMT_IB }, [SEND] = { true, INSTR_FMT_IBC }, [SEND_GEN] = { true, INSTR_FMT_IBC }, [INSTRUMENTED_YIELD_VALUE] = { true, INSTR_FMT_IX }, [YIELD_VALUE] = { true, INSTR_FMT_IX }, [POP_EXCEPT] = { true, INSTR_FMT_IX }, [RERAISE] = { true, INSTR_FMT_IB }, [END_ASYNC_FOR] = { true, INSTR_FMT_IX }, [CLEANUP_THROW] = { true, INSTR_FMT_IX }, [LOAD_ASSERTION_ERROR] = { true, INSTR_FMT_IX }, [LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX }, [STORE_NAME] = { true, INSTR_FMT_IB }, [DELETE_NAME] = { true, INSTR_FMT_IB }, [UNPACK_SEQUENCE] = { true, INSTR_FMT_IBC }, [UNPACK_SEQUENCE_TWO_TUPLE] = { true, INSTR_FMT_IBC }, [UNPACK_SEQUENCE_TUPLE] = { true, INSTR_FMT_IBC }, [UNPACK_SEQUENCE_LIST] = { true, INSTR_FMT_IBC }, [UNPACK_EX] = { true, INSTR_FMT_IB }, [STORE_ATTR] = { true, INSTR_FMT_IBC000 }, [DELETE_ATTR] = { true, INSTR_FMT_IB }, [STORE_GLOBAL] = { true, INSTR_FMT_IB }, [DELETE_GLOBAL] = { true, INSTR_FMT_IB }, [LOAD_LOCALS] = { true, INSTR_FMT_IB }, [LOAD_NAME] = { true, INSTR_FMT_IB }, [LOAD_FROM_DICT_OR_GLOBALS] = { true, INSTR_FMT_IB }, [LOAD_GLOBAL] = { true, INSTR_FMT_IBC000 }, [LOAD_GLOBAL_MODULE] = { true, INSTR_FMT_IBC000 }, [LOAD_GLOBAL_BUILTIN] = { true, INSTR_FMT_IBC000 }, [DELETE_FAST] = { true, INSTR_FMT_IB }, [MAKE_CELL] = { true, INSTR_FMT_IB }, [DELETE_DEREF] = { true, INSTR_FMT_IB }, [LOAD_FROM_DICT_OR_DEREF] = { true, INSTR_FMT_IB }, [LOAD_DEREF] = { true, INSTR_FMT_IB }, [STORE_DEREF] = { true, INSTR_FMT_IB }, [COPY_FREE_VARS] = { true, INSTR_FMT_IB }, [BUILD_STRING] = { true, INSTR_FMT_IB }, [BUILD_TUPLE] = { true, INSTR_FMT_IB }, [BUILD_LIST] = { true, INSTR_FMT_IB }, [LIST_EXTEND] = { true, INSTR_FMT_IB }, [SET_UPDATE] = { true, INSTR_FMT_IB }, [BUILD_SET] = { true, INSTR_FMT_IB }, [BUILD_MAP] = { true, INSTR_FMT_IB }, [SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX }, [BUILD_CONST_KEY_MAP] = { true, INSTR_FMT_IB }, [DICT_UPDATE] = { true, INSTR_FMT_IB }, [DICT_MERGE] = { true, INSTR_FMT_IB }, [MAP_ADD] = { true, INSTR_FMT_IB }, [INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC00000000 }, [LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC }, [LOAD_SUPER_ATTR_ATTR] = { true, INSTR_FMT_IBC }, [LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IBC }, [LOAD_ATTR] = { true, INSTR_FMT_IBC00000000 }, [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000 }, [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000 }, [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000 }, [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000 }, [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000 }, [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000 }, [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000 }, [STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000 }, [STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000 }, [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000 }, [COMPARE_OP] = { true, INSTR_FMT_IBC }, [COMPARE_OP_FLOAT] = { true, INSTR_FMT_IBC }, [COMPARE_OP_INT] = { true, INSTR_FMT_IBC }, [COMPARE_OP_STR] = { true, INSTR_FMT_IBC }, [IS_OP] = { true, INSTR_FMT_IB }, [CONTAINS_OP] = { true, INSTR_FMT_IB }, [CHECK_EG_MATCH] = { true, INSTR_FMT_IX }, [CHECK_EXC_MATCH] = { true, INSTR_FMT_IX }, [IMPORT_NAME] = { true, INSTR_FMT_IB }, [IMPORT_FROM] = { true, INSTR_FMT_IB }, [JUMP_FORWARD] = { true, INSTR_FMT_IB }, [JUMP_BACKWARD] = { true, INSTR_FMT_IB }, [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB }, [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB }, [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB }, [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB }, [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB }, [GET_LEN] = { true, INSTR_FMT_IX }, [MATCH_CLASS] = { true, INSTR_FMT_IB }, [MATCH_MAPPING] = { true, INSTR_FMT_IX }, [MATCH_SEQUENCE] = { true, INSTR_FMT_IX }, [MATCH_KEYS] = { true, INSTR_FMT_IX }, [GET_ITER] = { true, INSTR_FMT_IX }, [GET_YIELD_FROM_ITER] = { true, INSTR_FMT_IX }, [FOR_ITER] = { true, INSTR_FMT_IBC }, [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IB }, [FOR_ITER_LIST] = { true, INSTR_FMT_IBC }, [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC }, [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC }, [FOR_ITER_GEN] = { true, INSTR_FMT_IBC }, [BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX }, [BEFORE_WITH] = { true, INSTR_FMT_IX }, [WITH_EXCEPT_START] = { true, INSTR_FMT_IX }, [PUSH_EXC_INFO] = { true, INSTR_FMT_IX }, [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000 }, [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000 }, [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000 }, [KW_NAMES] = { true, INSTR_FMT_IB }, [INSTRUMENTED_CALL] = { true, INSTR_FMT_IB }, [CALL] = { true, INSTR_FMT_IBC00 }, [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00 }, [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00 }, [CALL_PY_WITH_DEFAULTS] = { true, INSTR_FMT_IBC00 }, [CALL_NO_KW_TYPE_1] = { true, INSTR_FMT_IBC00 }, [CALL_NO_KW_STR_1] = { true, INSTR_FMT_IBC00 }, [CALL_NO_KW_TUPLE_1] = { true, INSTR_FMT_IBC00 }, [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00 }, [CALL_NO_KW_BUILTIN_O] = { true, INSTR_FMT_IBC00 }, [CALL_NO_KW_BUILTIN_FAST] = { true, INSTR_FMT_IBC00 }, [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00 }, [CALL_NO_KW_LEN] = { true, INSTR_FMT_IBC00 }, [CALL_NO_KW_ISINSTANCE] = { true, INSTR_FMT_IBC00 }, [CALL_NO_KW_LIST_APPEND] = { true, INSTR_FMT_IBC00 }, [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00 }, [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00 }, [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00 }, [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00 }, [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX }, [CALL_FUNCTION_EX] = { true, INSTR_FMT_IB }, [MAKE_FUNCTION] = { true, INSTR_FMT_IB }, [RETURN_GENERATOR] = { true, INSTR_FMT_IX }, [BUILD_SLICE] = { true, INSTR_FMT_IB }, [FORMAT_VALUE] = { true, INSTR_FMT_IB }, [COPY] = { true, INSTR_FMT_IB }, [BINARY_OP] = { true, INSTR_FMT_IBC }, [SWAP] = { true, INSTR_FMT_IB }, [INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX }, [INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB }, [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IB }, [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB }, [INSTRUMENTED_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB }, [INSTRUMENTED_POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB }, [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB }, [EXTENDED_ARG] = { true, INSTR_FMT_IB }, [CACHE] = { true, INSTR_FMT_IX }, [RESERVED] = { true, INSTR_FMT_IX }, }; #endif ================================================ FILE: OpCode_Targets.h ================================================ static void *opcode_targets[256] = { &&TARGET_CACHE, &&TARGET_POP_TOP, &&TARGET_PUSH_NULL, &&TARGET_INTERPRETER_EXIT, &&TARGET_END_FOR, &&TARGET_END_SEND, &&TARGET_BINARY_OP_ADD_FLOAT, &&TARGET_BINARY_OP_ADD_INT, &&TARGET_BINARY_OP_ADD_UNICODE, &&TARGET_NOP, &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, &&TARGET_UNARY_NEGATIVE, &&TARGET_UNARY_NOT, &&TARGET_BINARY_OP_MULTIPLY_FLOAT, &&TARGET_BINARY_OP_MULTIPLY_INT, &&TARGET_UNARY_INVERT, &&TARGET_BINARY_OP_SUBTRACT_FLOAT, &&TARGET_RESERVED, &&TARGET_BINARY_OP_SUBTRACT_INT, &&TARGET_BINARY_SUBSCR_DICT, &&TARGET_BINARY_SUBSCR_GETITEM, &&TARGET_BINARY_SUBSCR_LIST_INT, &&TARGET_BINARY_SUBSCR_TUPLE_INT, &&TARGET_CALL_PY_EXACT_ARGS, &&TARGET_CALL_PY_WITH_DEFAULTS, &&TARGET_BINARY_SUBSCR, &&TARGET_BINARY_SLICE, &&TARGET_STORE_SLICE, &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, &&TARGET_CALL_BUILTIN_CLASS, &&TARGET_GET_LEN, &&TARGET_MATCH_MAPPING, &&TARGET_MATCH_SEQUENCE, &&TARGET_MATCH_KEYS, &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_PUSH_EXC_INFO, &&TARGET_CHECK_EXC_MATCH, &&TARGET_CHECK_EG_MATCH, &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, &&TARGET_CALL_NO_KW_BUILTIN_FAST, &&TARGET_CALL_NO_KW_BUILTIN_O, &&TARGET_CALL_NO_KW_ISINSTANCE, &&TARGET_CALL_NO_KW_LEN, &&TARGET_CALL_NO_KW_LIST_APPEND, &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_CALL_NO_KW_STR_1, &&TARGET_CALL_NO_KW_TUPLE_1, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, &&TARGET_BEFORE_ASYNC_WITH, &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, &&TARGET_CLEANUP_THROW, &&TARGET_CALL_NO_KW_TYPE_1, &&TARGET_COMPARE_OP_FLOAT, &&TARGET_COMPARE_OP_INT, &&TARGET_COMPARE_OP_STR, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, &&TARGET_FOR_ITER_LIST, &&TARGET_FOR_ITER_TUPLE, &&TARGET_FOR_ITER_RANGE, &&TARGET_FOR_ITER_GEN, &&TARGET_LOAD_SUPER_ATTR_ATTR, &&TARGET_LOAD_SUPER_ATTR_METHOD, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_LOAD_ATTR_CLASS, &&TARGET_LOAD_BUILD_CLASS, &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, &&TARGET_LOAD_ATTR_MODULE, &&TARGET_LOAD_ATTR_PROPERTY, &&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, &&TARGET_LOAD_ATTR_METHOD_NO_DICT, &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_RETURN_VALUE, &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_SETUP_ANNOTATIONS, &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_LOAD_LOCALS, &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_POP_EXCEPT, &&TARGET_STORE_NAME, &&TARGET_DELETE_NAME, &&TARGET_UNPACK_SEQUENCE, &&TARGET_FOR_ITER, &&TARGET_UNPACK_EX, &&TARGET_STORE_ATTR, &&TARGET_DELETE_ATTR, &&TARGET_STORE_GLOBAL, &&TARGET_DELETE_GLOBAL, &&TARGET_SWAP, &&TARGET_LOAD_CONST, &&TARGET_LOAD_NAME, &&TARGET_BUILD_TUPLE, &&TARGET_BUILD_LIST, &&TARGET_BUILD_SET, &&TARGET_BUILD_MAP, &&TARGET_LOAD_ATTR, &&TARGET_COMPARE_OP, &&TARGET_IMPORT_NAME, &&TARGET_IMPORT_FROM, &&TARGET_JUMP_FORWARD, &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, &&TARGET_IS_OP, &&TARGET_CONTAINS_OP, &&TARGET_RERAISE, &&TARGET_COPY, &&TARGET_RETURN_CONST, &&TARGET_BINARY_OP, &&TARGET_SEND, &&TARGET_LOAD_FAST, &&TARGET_STORE_FAST, &&TARGET_DELETE_FAST, &&TARGET_LOAD_FAST_CHECK, &&TARGET_POP_JUMP_IF_NOT_NONE, &&TARGET_POP_JUMP_IF_NONE, &&TARGET_RAISE_VARARGS, &&TARGET_GET_AWAITABLE, &&TARGET_MAKE_FUNCTION, &&TARGET_BUILD_SLICE, &&TARGET_JUMP_BACKWARD_NO_INTERRUPT, &&TARGET_MAKE_CELL, &&TARGET_LOAD_CLOSURE, &&TARGET_LOAD_DEREF, &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, &&TARGET_JUMP_BACKWARD, &&TARGET_LOAD_SUPER_ATTR, &&TARGET_CALL_FUNCTION_EX, &&TARGET_LOAD_FAST_AND_CLEAR, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, &&TARGET_MAP_ADD, &&TARGET_STORE_ATTR_SLOT, &&TARGET_COPY_FREE_VARS, &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, &&TARGET_STORE_FAST__STORE_FAST, &&TARGET_STORE_SUBSCR_DICT, &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_SEND_GEN, &&_unknown_opcode, &&_unknown_opcode, &&TARGET_CALL, &&TARGET_KW_NAMES, &&TARGET_CALL_INTRINSIC_1, &&TARGET_CALL_INTRINSIC_2, &&TARGET_LOAD_FROM_DICT_OR_GLOBALS, &&TARGET_LOAD_FROM_DICT_OR_DEREF, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&TARGET_INSTRUMENTED_LOAD_SUPER_ATTR, &&TARGET_INSTRUMENTED_POP_JUMP_IF_NONE, &&TARGET_INSTRUMENTED_POP_JUMP_IF_NOT_NONE, &&TARGET_INSTRUMENTED_RESUME, &&TARGET_INSTRUMENTED_CALL, &&TARGET_INSTRUMENTED_RETURN_VALUE, &&TARGET_INSTRUMENTED_YIELD_VALUE, &&TARGET_INSTRUMENTED_CALL_FUNCTION_EX, &&TARGET_INSTRUMENTED_JUMP_FORWARD, &&TARGET_INSTRUMENTED_JUMP_BACKWARD, &&TARGET_INSTRUMENTED_RETURN_CONST, &&TARGET_INSTRUMENTED_FOR_ITER, &&TARGET_INSTRUMENTED_POP_JUMP_IF_FALSE, &&TARGET_INSTRUMENTED_POP_JUMP_IF_TRUE, &&TARGET_INSTRUMENTED_END_FOR, &&TARGET_INSTRUMENTED_END_SEND, &&TARGET_INSTRUMENTED_INSTRUCTION, &&TARGET_INSTRUMENTED_LINE, &&_unknown_opcode }; ================================================ FILE: OptiMizer.c ================================================ #include "Python.h" #include "opcode.h" #include "pycore_interp.h" #include "pycore_opcode.h" #include "pycore_pystate.h" #include "cpython/optimizer.h" #include #include #include /* Returns the index of the next space, or -1 if there is no * more space. Doesn't set an exception. */ static int32_t get_next_free_in_executor_array(PyCodeObject *code) { _PyExecutorArray *old = code->co_executors; int size = 0; int capacity = 0; if (old != NULL) { size = old->size; capacity = old->capacity; if (capacity >= 256) { return -1; } } assert(size <= capacity); if (size == capacity) { /* Array is full. Grow array */ int new_capacity = capacity ? capacity * 2 : 4; _PyExecutorArray *new = PyMem_Realloc( old, offsetof(_PyExecutorArray, executors) + new_capacity * sizeof(_PyExecutorObject *)); if (new == NULL) { return -1; } new->capacity = new_capacity; new->size = size; code->co_executors = new; } assert(size < code->co_executors->capacity); code->co_executors->size++; return size; } static void insert_executor(PyCodeObject *code, _Py_CODEUNIT *instr, int index, _PyExecutorObject *executor) { if (instr->op.code == ENTER_EXECUTOR) { assert(index == instr->op.arg); _PyExecutorObject *old = code->co_executors->executors[index]; executor->vm_data.opcode = old->vm_data.opcode; executor->vm_data.oparg = old->vm_data.oparg; old->vm_data.opcode = 0; Py_INCREF(executor); code->co_executors->executors[index] = executor; Py_DECREF(old); } else { Py_INCREF(executor); executor->vm_data.opcode = instr->op.code; executor->vm_data.oparg = instr->op.arg; code->co_executors->executors[index] = executor; assert(index < 256); instr->op.code = ENTER_EXECUTOR; instr->op.arg = index; } return; } static int get_executor_index(PyCodeObject *code, _Py_CODEUNIT *instr) { if (instr->op.code == ENTER_EXECUTOR) { return instr->op.arg; } else { return get_next_free_in_executor_array(code); } } int PyUnstable_Replace_Executor(PyCodeObject *code, _Py_CODEUNIT *instr, _PyExecutorObject *new) { if (instr->op.code != ENTER_EXECUTOR) { PyErr_Format(PyExc_ValueError, "No executor to replace"); return -1; } int index = get_executor_index(code, instr); assert(index >= 0); insert_executor(code, instr, index, new); return 0; } static int error_optimize( _PyOptimizerObject* self, PyCodeObject *code, _Py_CODEUNIT *instr, _PyExecutorObject **exec) { PyErr_Format(PyExc_SystemError, "Should never call error_optimize"); return -1; } static PyTypeObject DefaultOptimizer_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) .tp_name = "noop_optimizer", .tp_basicsize = sizeof(_PyOptimizerObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, }; _PyOptimizerObject _PyOptimizer_Default = { PyObject_HEAD_INIT(&DefaultOptimizer_Type) .optimize = error_optimize, .resume_threshold = UINT16_MAX, .backedge_threshold = UINT16_MAX, }; _PyOptimizerObject * PyUnstable_GetOptimizer(void) { PyInterpreterState *interp = PyInterpreterState_Get(); if (interp->optimizer == &_PyOptimizer_Default) { return NULL; } Py_INCREF(interp->optimizer); return interp->optimizer; } void PyUnstable_SetOptimizer(_PyOptimizerObject *optimizer) { PyInterpreterState *interp = PyInterpreterState_Get(); if (optimizer == NULL) { optimizer = &_PyOptimizer_Default; } _PyOptimizerObject *old = interp->optimizer; Py_INCREF(optimizer); interp->optimizer = optimizer; interp->optimizer_backedge_threshold = optimizer->backedge_threshold; interp->optimizer_resume_threshold = optimizer->resume_threshold; Py_DECREF(old); } _PyInterpreterFrame * _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest, PyObject **stack_pointer) { PyInterpreterState *interp = PyInterpreterState_Get(); int index = get_executor_index(frame->f_code, src); if (index < 0) { _PyFrame_SetStackPointer(frame, stack_pointer); return frame; } _PyOptimizerObject *opt = interp->optimizer; _PyExecutorObject *executor; int err = opt->optimize(opt, frame->f_code, dest, &executor); if (err <= 0) { if (err < 0) { return NULL; } _PyFrame_SetStackPointer(frame, stack_pointer); return frame; } insert_executor(frame->f_code, src, index, executor); return executor->execute(executor, frame, stack_pointer); } /** Test support **/ typedef struct { _PyOptimizerObject base; int64_t count; } _PyCounterOptimizerObject; typedef struct { _PyExecutorObject executor; _PyCounterOptimizerObject *optimizer; _Py_CODEUNIT *next_instr; } _PyCounterExecutorObject; static void counter_dealloc(_PyCounterExecutorObject *self) { Py_DECREF(self->optimizer); PyObject_Free(self); } static PyTypeObject CounterExecutor_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) .tp_name = "counting_executor", .tp_basicsize = sizeof(_PyCounterExecutorObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, .tp_dealloc = (destructor)counter_dealloc, }; static _PyInterpreterFrame * counter_execute(_PyExecutorObject *self, _PyInterpreterFrame *frame, PyObject **stack_pointer) { ((_PyCounterExecutorObject *)self)->optimizer->count++; _PyFrame_SetStackPointer(frame, stack_pointer); frame->prev_instr = ((_PyCounterExecutorObject *)self)->next_instr - 1; Py_DECREF(self); return frame; } static int counter_optimize( _PyOptimizerObject* self, PyCodeObject *code, _Py_CODEUNIT *instr, _PyExecutorObject **exec_ptr) { _PyCounterExecutorObject *executor = (_PyCounterExecutorObject *)_PyObject_New(&CounterExecutor_Type); if (executor == NULL) { return -1; } executor->executor.execute = counter_execute; Py_INCREF(self); executor->optimizer = (_PyCounterOptimizerObject *)self; executor->next_instr = instr; *exec_ptr = (_PyExecutorObject *)executor; return 1; } static PyObject * counter_get_counter(PyObject *self, PyObject *args) { return PyLong_FromLongLong(((_PyCounterOptimizerObject *)self)->count); } static PyMethodDef counter_methods[] = { { "get_count", counter_get_counter, METH_NOARGS, NULL }, { NULL, NULL }, }; static PyTypeObject CounterOptimizer_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) .tp_name = "Counter optimizer", .tp_basicsize = sizeof(_PyCounterOptimizerObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, .tp_methods = counter_methods, }; PyObject * PyUnstable_Optimizer_NewCounter(void) { _PyCounterOptimizerObject *opt = (_PyCounterOptimizerObject *)_PyObject_New(&CounterOptimizer_Type); if (opt == NULL) { return NULL; } opt->base.optimize = counter_optimize; opt->base.resume_threshold = UINT16_MAX; opt->base.backedge_threshold = 0; opt->count = 0; return (PyObject *)opt; } ================================================ FILE: PathConfig.c ================================================ /* Path configuration like module_search_path (sys.path) */ #include "Python.h" #include "marshal.h" // PyMarshal_ReadObjectFromString #include "osdefs.h" // DELIM #include "pycore_initconfig.h" #include "pycore_fileutils.h" #include "pycore_pathconfig.h" #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator() #include #ifdef MS_WINDOWS # include // GetFullPathNameW(), MAX_PATH # include # include #endif #ifdef __cplusplus extern "C" { #endif /* External interface */ /* Stored values set by C API functions */ typedef struct _PyPathConfig { /* Full path to the Python program */ wchar_t *program_full_path; wchar_t *prefix; wchar_t *exec_prefix; wchar_t *stdlib_dir; /* Set by Py_SetPath */ wchar_t *module_search_path; /* Set by _PyPathConfig_UpdateGlobal */ wchar_t *calculated_module_search_path; /* Python program name */ wchar_t *program_name; /* Set by Py_SetPythonHome() or PYTHONHOME environment variable */ wchar_t *home; int _is_python_build; } _PyPathConfig; # define _PyPathConfig_INIT \ {.module_search_path = NULL, ._is_python_build = 0} _PyPathConfig _Py_path_config = _PyPathConfig_INIT; const wchar_t * _PyPathConfig_GetGlobalModuleSearchPath(void) { return _Py_path_config.module_search_path; } void _PyPathConfig_ClearGlobal(void) { PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); #define CLEAR(ATTR) \ do { \ PyMem_RawFree(_Py_path_config.ATTR); \ _Py_path_config.ATTR = NULL; \ } while (0) CLEAR(program_full_path); CLEAR(prefix); CLEAR(exec_prefix); CLEAR(stdlib_dir); CLEAR(module_search_path); CLEAR(calculated_module_search_path); CLEAR(program_name); CLEAR(home); _Py_path_config._is_python_build = 0; #undef CLEAR PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); } PyStatus _PyPathConfig_ReadGlobal(PyConfig *config) { PyStatus status = _PyStatus_OK(); #define COPY(ATTR) \ do { \ if (_Py_path_config.ATTR && !config->ATTR) { \ status = PyConfig_SetString(config, &config->ATTR, _Py_path_config.ATTR); \ if (_PyStatus_EXCEPTION(status)) goto done; \ } \ } while (0) #define COPY2(ATTR, SRCATTR) \ do { \ if (_Py_path_config.SRCATTR && !config->ATTR) { \ status = PyConfig_SetString(config, &config->ATTR, _Py_path_config.SRCATTR); \ if (_PyStatus_EXCEPTION(status)) goto done; \ } \ } while (0) #define COPY_INT(ATTR) \ do { \ assert(_Py_path_config.ATTR >= 0); \ if ((_Py_path_config.ATTR >= 0) && (config->ATTR <= 0)) { \ config->ATTR = _Py_path_config.ATTR; \ } \ } while (0) COPY(prefix); COPY(exec_prefix); COPY(stdlib_dir); COPY(program_name); COPY(home); COPY2(executable, program_full_path); COPY_INT(_is_python_build); // module_search_path must be initialised - not read #undef COPY #undef COPY2 #undef COPY_INT done: return status; } PyStatus _PyPathConfig_UpdateGlobal(const PyConfig *config) { PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); #define COPY(ATTR) \ do { \ if (config->ATTR) { \ PyMem_RawFree(_Py_path_config.ATTR); \ _Py_path_config.ATTR = _PyMem_RawWcsdup(config->ATTR); \ if (!_Py_path_config.ATTR) goto error; \ } \ } while (0) #define COPY2(ATTR, SRCATTR) \ do { \ if (config->SRCATTR) { \ PyMem_RawFree(_Py_path_config.ATTR); \ _Py_path_config.ATTR = _PyMem_RawWcsdup(config->SRCATTR); \ if (!_Py_path_config.ATTR) goto error; \ } \ } while (0) #define COPY_INT(ATTR) \ do { \ if (config->ATTR > 0) { \ _Py_path_config.ATTR = config->ATTR; \ } \ } while (0) COPY(prefix); COPY(exec_prefix); COPY(stdlib_dir); COPY(program_name); COPY(home); COPY2(program_full_path, executable); COPY_INT(_is_python_build); #undef COPY #undef COPY2 #undef COPY_INT PyMem_RawFree(_Py_path_config.module_search_path); _Py_path_config.module_search_path = NULL; PyMem_RawFree(_Py_path_config.calculated_module_search_path); _Py_path_config.calculated_module_search_path = NULL; do { size_t cch = 1; for (Py_ssize_t i = 0; i < config->module_search_paths.length; ++i) { cch += 1 + wcslen(config->module_search_paths.items[i]); } wchar_t *path = (wchar_t*)PyMem_RawMalloc(sizeof(wchar_t) * cch); if (!path) { goto error; } wchar_t *p = path; for (Py_ssize_t i = 0; i < config->module_search_paths.length; ++i) { wcscpy(p, config->module_search_paths.items[i]); p = wcschr(p, L'\0'); *p++ = DELIM; *p = L'\0'; } do { *p = L'\0'; } while (p != path && *--p == DELIM); _Py_path_config.calculated_module_search_path = path; } while (0); PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); return _PyStatus_OK(); error: PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); return _PyStatus_NO_MEMORY(); } static void _Py_NO_RETURN path_out_of_memory(const char *func) { _Py_FatalErrorFunc(func, "out of memory"); } // Removed in Python 3.13 API, but kept for the stable ABI PyAPI_FUNC(void) Py_SetPath(const wchar_t *path) { if (path == NULL) { _PyPathConfig_ClearGlobal(); return; } PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); PyMem_RawFree(_Py_path_config.prefix); PyMem_RawFree(_Py_path_config.exec_prefix); PyMem_RawFree(_Py_path_config.stdlib_dir); PyMem_RawFree(_Py_path_config.module_search_path); PyMem_RawFree(_Py_path_config.calculated_module_search_path); _Py_path_config.prefix = _PyMem_RawWcsdup(L""); _Py_path_config.exec_prefix = _PyMem_RawWcsdup(L""); // XXX Copy this from the new module_search_path? if (_Py_path_config.home != NULL) { _Py_path_config.stdlib_dir = _PyMem_RawWcsdup(_Py_path_config.home); } else { _Py_path_config.stdlib_dir = _PyMem_RawWcsdup(L""); } _Py_path_config.module_search_path = _PyMem_RawWcsdup(path); _Py_path_config.calculated_module_search_path = NULL; PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); if (_Py_path_config.prefix == NULL || _Py_path_config.exec_prefix == NULL || _Py_path_config.stdlib_dir == NULL || _Py_path_config.module_search_path == NULL) { path_out_of_memory(__func__); } } // Removed in Python 3.13 API, but kept for the stable ABI PyAPI_FUNC(void) Py_SetPythonHome(const wchar_t *home) { int has_value = home && home[0]; PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); PyMem_RawFree(_Py_path_config.home); _Py_path_config.home = NULL; if (has_value) { _Py_path_config.home = _PyMem_RawWcsdup(home); } PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); if (has_value && _Py_path_config.home == NULL) { path_out_of_memory(__func__); } } // Removed in Python 3.13 API, but kept for the stable ABI PyAPI_FUNC(void) Py_SetProgramName(const wchar_t *program_name) { int has_value = program_name && program_name[0]; PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); PyMem_RawFree(_Py_path_config.program_name); _Py_path_config.program_name = NULL; if (has_value) { _Py_path_config.program_name = _PyMem_RawWcsdup(program_name); } PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); if (has_value && _Py_path_config.program_name == NULL) { path_out_of_memory(__func__); } } wchar_t * Py_GetPath(void) { /* If the user has provided a path, return that */ if (_Py_path_config.module_search_path) { return _Py_path_config.module_search_path; } /* If we have already done calculations, return the calculated path */ return _Py_path_config.calculated_module_search_path; } wchar_t * _Py_GetStdlibDir(void) { wchar_t *stdlib_dir = _Py_path_config.stdlib_dir; if (stdlib_dir != NULL && stdlib_dir[0] != L'\0') { return stdlib_dir; } return NULL; } wchar_t * Py_GetPrefix(void) { return _Py_path_config.prefix; } wchar_t * Py_GetExecPrefix(void) { return _Py_path_config.exec_prefix; } wchar_t * Py_GetProgramFullPath(void) { return _Py_path_config.program_full_path; } wchar_t* Py_GetPythonHome(void) { return _Py_path_config.home; } wchar_t * Py_GetProgramName(void) { return _Py_path_config.program_name; } /* Compute module search path from argv[0] or the current working directory ("-m module" case) which will be prepended to sys.argv: sys.path[0]. Return 1 if the path is correctly resolved and written into *path0_p. Return 0 if it fails to resolve the full path. For example, return 0 if the current working directory has been removed (bpo-36236) or if argv is empty. Raise an exception and return -1 on error. */ int _PyPathConfig_ComputeSysPath0(const PyWideStringList *argv, PyObject **path0_p) { assert(_PyWideStringList_CheckConsistency(argv)); if (argv->length == 0) { /* Leave sys.path unchanged if sys.argv is empty */ return 0; } wchar_t *argv0 = argv->items[0]; int have_module_arg = (wcscmp(argv0, L"-m") == 0); int have_script_arg = (!have_module_arg && (wcscmp(argv0, L"-c") != 0)); wchar_t *path0 = argv0; Py_ssize_t n = 0; #ifdef HAVE_REALPATH wchar_t fullpath[MAXPATHLEN]; #elif defined(MS_WINDOWS) wchar_t fullpath[MAX_PATH]; #endif if (have_module_arg) { #if defined(HAVE_REALPATH) || defined(MS_WINDOWS) if (!_Py_wgetcwd(fullpath, Py_ARRAY_LENGTH(fullpath))) { return 0; } path0 = fullpath; #else path0 = L"."; #endif n = wcslen(path0); } #ifdef HAVE_READLINK wchar_t link[MAXPATHLEN + 1]; int nr = 0; wchar_t path0copy[2 * MAXPATHLEN + 1]; if (have_script_arg) { nr = _Py_wreadlink(path0, link, Py_ARRAY_LENGTH(link)); } if (nr > 0) { /* It's a symlink */ link[nr] = '\0'; if (link[0] == SEP) { path0 = link; /* Link to absolute path */ } else if (wcschr(link, SEP) == NULL) { /* Link without path */ } else { /* Must join(dirname(path0), link) */ wchar_t *q = wcsrchr(path0, SEP); if (q == NULL) { /* path0 without path */ path0 = link; } else { /* Must make a copy, path0copy has room for 2 * MAXPATHLEN */ wcsncpy(path0copy, path0, MAXPATHLEN); q = wcsrchr(path0copy, SEP); wcsncpy(q+1, link, MAXPATHLEN); q[MAXPATHLEN + 1] = L'\0'; path0 = path0copy; } } } #endif /* HAVE_READLINK */ wchar_t *p = NULL; #if SEP == '\\' /* Special case for Microsoft filename syntax */ if (have_script_arg) { wchar_t *q; #if defined(MS_WINDOWS) /* Replace the first element in argv with the full path. */ wchar_t *ptemp; if (GetFullPathNameW(path0, Py_ARRAY_LENGTH(fullpath), fullpath, &ptemp)) { path0 = fullpath; } #endif p = wcsrchr(path0, SEP); /* Test for alternate separator */ q = wcsrchr(p ? p : path0, '/'); if (q != NULL) p = q; if (p != NULL) { n = p + 1 - path0; if (n > 1 && p[-1] != ':') n--; /* Drop trailing separator */ } } #else /* All other filename syntaxes */ if (have_script_arg) { #if defined(HAVE_REALPATH) if (_Py_wrealpath(path0, fullpath, Py_ARRAY_LENGTH(fullpath))) { path0 = fullpath; } #endif p = wcsrchr(path0, SEP); } if (p != NULL) { n = p + 1 - path0; #if SEP == '/' /* Special case for Unix filename syntax */ if (n > 1) { /* Drop trailing separator */ n--; } #endif /* Unix */ } #endif /* All others */ PyObject *path0_obj = PyUnicode_FromWideChar(path0, n); if (path0_obj == NULL) { return -1; } *path0_p = path0_obj; return 1; } #ifdef __cplusplus } #endif ================================================ FILE: Perf_Trampoline.c ================================================ /* Perf trampoline instrumentation =============================== This file contains instrumentation to allow to associate calls to the CPython eval loop back to the names of the Python functions and filename being executed. Many native performance profilers like the Linux perf tools are only available to 'see' the C stack when sampling from the profiled process. This means that if we have the following python code: import time def foo(n): # Some CPU intensive code def bar(n): foo(n) def baz(n): bar(n) baz(10000000) A performance profiler that is only able to see native frames will produce the following backtrace when sampling from foo(): _PyEval_EvalFrameDefault -----> Evaluation frame of foo() _PyEval_Vector _PyFunction_Vectorcall PyObject_Vectorcall call_function _PyEval_EvalFrameDefault ------> Evaluation frame of bar() _PyEval_EvalFrame _PyEval_Vector _PyFunction_Vectorcall PyObject_Vectorcall call_function _PyEval_EvalFrameDefault -------> Evaluation frame of baz() _PyEval_EvalFrame _PyEval_Vector _PyFunction_Vectorcall PyObject_Vectorcall call_function ... Py_RunMain Because the profiler is only able to see the native frames and the native function that runs the evaluation loop is the same (_PyEval_EvalFrameDefault) then the profiler and any reporter generated by it will not be able to associate the names of the Python functions and the filenames associated with those calls, rendering the results useless in the Python world. To fix this problem, we introduce the concept of a trampoline frame. A trampoline frame is a piece of code that is unique per Python code object that is executed before entering the CPython eval loop. This piece of code just calls the original Python evaluation function (_PyEval_EvalFrameDefault) and forwards all the arguments received. In this way, when a profiler samples frames from the previous example it will see; _PyEval_EvalFrameDefault -----> Evaluation frame of foo() [Jit compiled code 3] _PyEval_Vector _PyFunction_Vectorcall PyObject_Vectorcall call_function _PyEval_EvalFrameDefault ------> Evaluation frame of bar() [Jit compiled code 2] _PyEval_EvalFrame _PyEval_Vector _PyFunction_Vectorcall PyObject_Vectorcall call_function _PyEval_EvalFrameDefault -------> Evaluation frame of baz() [Jit compiled code 1] _PyEval_EvalFrame _PyEval_Vector _PyFunction_Vectorcall PyObject_Vectorcall call_function ... Py_RunMain When we generate every unique copy of the trampoline (what here we called "[Jit compiled code N]") we write the relationship between the compiled code and the Python function that is associated with it. Every profiler requires this information in a different format. For example, the Linux "perf" profiler requires a file in "/tmp/perf-PID.map" (name and location not configurable) with the following format: If this file is available when "perf" generates reports, it will automatically associate every trampoline with the Python function that it is associated with allowing it to generate reports that include Python information. These reports then can also be filtered in a way that *only* Python information appears. Notice that for this to work, there must be a unique copied of the trampoline per Python code object even if the code in the trampoline is the same. To achieve this we have a assembly template in Objects/asm_trampiline.S that is compiled into the Python executable/shared library. This template generates a symbol that maps the start of the assembly code and another that marks the end of the assembly code for the trampoline. Then, every time we need a unique trampoline for a Python code object, we copy the assembly code into a mmaped area that has executable permissions and we return the start of that area as our trampoline function. Asking for a mmap-ed memory area for trampoline is very wasteful so we allocate big arenas of memory in a single mmap call, we populate the entire arena with copies of the trampoline (this allows us to now have to invalidate the icache for the instructions in the page) and then we return the next available chunk every time someone asks for a new trampoline. We keep a linked list of arenas in case the current memory arena is exhausted and another one is needed. For the best results, Python should be compiled with CFLAGS="-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer" as this allows profilers to unwind using only the frame pointer and not on DWARF debug information (note that as trampilines are dynamically generated there won't be any DWARF information available for them). */ #include "Python.h" #include "pycore_ceval.h" #include "pycore_frame.h" #include "pycore_interp.h" #ifdef PY_HAVE_PERF_TRAMPOLINE #include #include #include #include #include #include #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) #define PY_HAVE_INVALIDATE_ICACHE #if defined(__clang__) || defined(__GNUC__) extern void __clear_cache(void *, void*); #endif static void invalidate_icache(char* begin, char*end) { #if defined(__clang__) || defined(__GNUC__) return __clear_cache(begin, end); #else return; #endif } #endif /* The function pointer is passed as last argument. The other three arguments * are passed in the same order as the function requires. This results in * shorter, more efficient ASM code for trampoline. */ typedef PyObject *(*py_evaluator)(PyThreadState *, _PyInterpreterFrame *, int throwflag); typedef PyObject *(*py_trampoline)(PyThreadState *, _PyInterpreterFrame *, int, py_evaluator); extern void *_Py_trampoline_func_start; // Start of the template of the // assembly trampoline extern void * _Py_trampoline_func_end; // End of the template of the assembly trampoline struct code_arena_st { char *start_addr; // Start of the memory arena char *current_addr; // Address of the current trampoline within the arena size_t size; // Size of the memory arena size_t size_left; // Remaining size of the memory arena size_t code_size; // Size of the code of every trampoline in the arena struct code_arena_st *prev; // Pointer to the arena or NULL if this is the first arena. }; typedef struct code_arena_st code_arena_t; typedef struct trampoline_api_st trampoline_api_t; #define perf_status _PyRuntime.ceval.perf.status #define extra_code_index _PyRuntime.ceval.perf.extra_code_index #define perf_code_arena _PyRuntime.ceval.perf.code_arena #define trampoline_api _PyRuntime.ceval.perf.trampoline_api #define perf_map_file _PyRuntime.ceval.perf.map_file static void perf_map_write_entry(void *state, const void *code_addr, unsigned int code_size, PyCodeObject *co) { const char *entry = ""; if (co->co_qualname != NULL) { entry = PyUnicode_AsUTF8(co->co_qualname); } const char *filename = ""; if (co->co_filename != NULL) { filename = PyUnicode_AsUTF8(co->co_filename); } size_t perf_map_entry_size = snprintf(NULL, 0, "py::%s:%s", entry, filename) + 1; char* perf_map_entry = (char*) PyMem_RawMalloc(perf_map_entry_size); if (perf_map_entry == NULL) { return; } snprintf(perf_map_entry, perf_map_entry_size, "py::%s:%s", entry, filename); PyUnstable_WritePerfMapEntry(code_addr, code_size, perf_map_entry); PyMem_RawFree(perf_map_entry); } _PyPerf_Callbacks _Py_perfmap_callbacks = { NULL, &perf_map_write_entry, NULL, }; static int new_code_arena(void) { // non-trivial programs typically need 64 to 256 kiB. size_t mem_size = 4096 * 16; assert(mem_size % sysconf(_SC_PAGESIZE) == 0); char *memory = mmap(NULL, // address mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, // fd (not used here) 0); // offset (not used here) if (!memory) { PyErr_SetFromErrno(PyExc_OSError); _PyErr_WriteUnraisableMsg( "Failed to create new mmap for perf trampoline", NULL); perf_status = PERF_STATUS_FAILED; return -1; } void *start = &_Py_trampoline_func_start; void *end = &_Py_trampoline_func_end; size_t code_size = end - start; // TODO: Check the effect of alignment of the code chunks. Initial investigation // showed that this has no effect on performance in x86-64 or aarch64 and the current // version has the advantage that the unwinder in GDB can unwind across JIT-ed code. // // We should check the values in the future and see if there is a // measurable performance improvement by rounding trampolines up to 32-bit // or 64-bit alignment. size_t n_copies = mem_size / code_size; for (size_t i = 0; i < n_copies; i++) { memcpy(memory + i * code_size, start, code_size * sizeof(char)); } // Some systems may prevent us from creating executable code on the fly. int res = mprotect(memory, mem_size, PROT_READ | PROT_EXEC); if (res == -1) { PyErr_SetFromErrno(PyExc_OSError); munmap(memory, mem_size); _PyErr_WriteUnraisableMsg( "Failed to set mmap for perf trampoline to PROT_READ | PROT_EXEC", NULL); return -1; } #ifdef PY_HAVE_INVALIDATE_ICACHE // Before the JIT can run a block of code that has been emitted it must invalidate // the instruction cache on some platforms like arm and aarch64. invalidate_icache(memory, memory + mem_size); #endif code_arena_t *new_arena = PyMem_RawCalloc(1, sizeof(code_arena_t)); if (new_arena == NULL) { PyErr_NoMemory(); munmap(memory, mem_size); _PyErr_WriteUnraisableMsg("Failed to allocate new code arena struct", NULL); return -1; } new_arena->start_addr = memory; new_arena->current_addr = memory; new_arena->size = mem_size; new_arena->size_left = mem_size; new_arena->code_size = code_size; new_arena->prev = perf_code_arena; perf_code_arena = new_arena; return 0; } static void free_code_arenas(void) { code_arena_t *cur = perf_code_arena; code_arena_t *prev; perf_code_arena = NULL; // invalid static pointer while (cur) { munmap(cur->start_addr, cur->size); prev = cur->prev; PyMem_RawFree(cur); cur = prev; } } static inline py_trampoline code_arena_new_code(code_arena_t *code_arena) { py_trampoline trampoline = (py_trampoline)code_arena->current_addr; code_arena->size_left -= code_arena->code_size; code_arena->current_addr += code_arena->code_size; return trampoline; } static inline py_trampoline compile_trampoline(void) { if ((perf_code_arena == NULL) || (perf_code_arena->size_left <= perf_code_arena->code_size)) { if (new_code_arena() < 0) { return NULL; } } assert(perf_code_arena->size_left <= perf_code_arena->size); return code_arena_new_code(perf_code_arena); } static PyObject * py_trampoline_evaluator(PyThreadState *ts, _PyInterpreterFrame *frame, int throw) { if (perf_status == PERF_STATUS_FAILED || perf_status == PERF_STATUS_NO_INIT) { goto default_eval; } PyCodeObject *co = frame->f_code; py_trampoline f = NULL; assert(extra_code_index != -1); int ret = _PyCode_GetExtra((PyObject *)co, extra_code_index, (void **)&f); if (ret != 0 || f == NULL) { // This is the first time we see this code object so we need // to compile a trampoline for it. py_trampoline new_trampoline = compile_trampoline(); if (new_trampoline == NULL) { goto default_eval; } trampoline_api.write_state(trampoline_api.state, new_trampoline, perf_code_arena->code_size, co); _PyCode_SetExtra((PyObject *)co, extra_code_index, (void *)new_trampoline); f = new_trampoline; } assert(f != NULL); return f(ts, frame, throw, _PyEval_EvalFrameDefault); default_eval: // Something failed, fall back to the default evaluator. return _PyEval_EvalFrameDefault(ts, frame, throw); } #endif // PY_HAVE_PERF_TRAMPOLINE int _PyIsPerfTrampolineActive(void) { #ifdef PY_HAVE_PERF_TRAMPOLINE PyThreadState *tstate = _PyThreadState_GET(); return tstate->interp->eval_frame == py_trampoline_evaluator; #endif return 0; } void _PyPerfTrampoline_GetCallbacks(_PyPerf_Callbacks *callbacks) { if (callbacks == NULL) { return; } #ifdef PY_HAVE_PERF_TRAMPOLINE callbacks->init_state = trampoline_api.init_state; callbacks->write_state = trampoline_api.write_state; callbacks->free_state = trampoline_api.free_state; #endif return; } int _PyPerfTrampoline_SetCallbacks(_PyPerf_Callbacks *callbacks) { if (callbacks == NULL) { return -1; } #ifdef PY_HAVE_PERF_TRAMPOLINE if (trampoline_api.state) { _PyPerfTrampoline_Fini(); } trampoline_api.init_state = callbacks->init_state; trampoline_api.write_state = callbacks->write_state; trampoline_api.free_state = callbacks->free_state; trampoline_api.state = NULL; perf_status = PERF_STATUS_OK; #endif return 0; } int _PyPerfTrampoline_Init(int activate) { #ifdef PY_HAVE_PERF_TRAMPOLINE PyThreadState *tstate = _PyThreadState_GET(); if (tstate->interp->eval_frame && tstate->interp->eval_frame != py_trampoline_evaluator) { PyErr_SetString(PyExc_RuntimeError, "Trampoline cannot be initialized as a custom eval " "frame is already present"); return -1; } if (!activate) { tstate->interp->eval_frame = NULL; } else { tstate->interp->eval_frame = py_trampoline_evaluator; if (new_code_arena() < 0) { return -1; } extra_code_index = _PyEval_RequestCodeExtraIndex(NULL); if (extra_code_index == -1) { return -1; } perf_status = PERF_STATUS_OK; } #endif return 0; } int _PyPerfTrampoline_Fini(void) { #ifdef PY_HAVE_PERF_TRAMPOLINE PyThreadState *tstate = _PyThreadState_GET(); if (tstate->interp->eval_frame == py_trampoline_evaluator) { tstate->interp->eval_frame = NULL; } free_code_arenas(); extra_code_index = -1; #endif return 0; } PyStatus _PyPerfTrampoline_AfterFork_Child(void) { #ifdef PY_HAVE_PERF_TRAMPOLINE // Restart trampoline in file in child. int was_active = _PyIsPerfTrampolineActive(); _PyPerfTrampoline_Fini(); PyUnstable_PerfMapState_Fini(); if (was_active) { _PyPerfTrampoline_Init(1); } #endif return PyStatus_Ok(); } ================================================ FILE: PreConfig.c ================================================ #include "Python.h" #include "pycore_fileutils.h" // DECODE_LOCALE_ERR #include "pycore_getopt.h" // _PyOS_GetOpt() #include "pycore_initconfig.h" // _PyArgv #include "pycore_pymem.h" // _PyMem_GetAllocatorName() #include "pycore_runtime.h" // _PyRuntime_Initialize() #include // setlocale() #include // getenv() /* Forward declarations */ static void preconfig_copy(PyPreConfig *config, const PyPreConfig *config2); /* --- File system encoding/errors -------------------------------- */ const char *Py_FileSystemDefaultEncoding = NULL; int Py_HasFileSystemDefaultEncoding = 0; const char *Py_FileSystemDefaultEncodeErrors = NULL; int _Py_HasFileSystemDefaultEncodeErrors = 0; void _Py_ClearFileSystemEncoding(void) { _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS if (!Py_HasFileSystemDefaultEncoding && Py_FileSystemDefaultEncoding) { PyMem_RawFree((char*)Py_FileSystemDefaultEncoding); Py_FileSystemDefaultEncoding = NULL; } if (!_Py_HasFileSystemDefaultEncodeErrors && Py_FileSystemDefaultEncodeErrors) { PyMem_RawFree((char*)Py_FileSystemDefaultEncodeErrors); Py_FileSystemDefaultEncodeErrors = NULL; } _Py_COMP_DIAG_POP } /* Set Py_FileSystemDefaultEncoding and Py_FileSystemDefaultEncodeErrors global configuration variables to PyConfig.filesystem_encoding and PyConfig.filesystem_errors (encoded to UTF-8). Function called by _PyUnicode_InitEncodings(). */ int _Py_SetFileSystemEncoding(const char *encoding, const char *errors) { char *encoding2 = _PyMem_RawStrdup(encoding); if (encoding2 == NULL) { return -1; } char *errors2 = _PyMem_RawStrdup(errors); if (errors2 == NULL) { PyMem_RawFree(encoding2); return -1; } _Py_ClearFileSystemEncoding(); _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS Py_FileSystemDefaultEncoding = encoding2; Py_HasFileSystemDefaultEncoding = 0; Py_FileSystemDefaultEncodeErrors = errors2; _Py_HasFileSystemDefaultEncodeErrors = 0; _Py_COMP_DIAG_POP return 0; } /* --- _PyArgv ---------------------------------------------------- */ /* Decode bytes_argv using Py_DecodeLocale() */ PyStatus _PyArgv_AsWstrList(const _PyArgv *args, PyWideStringList *list) { PyWideStringList wargv = _PyWideStringList_INIT; if (args->use_bytes_argv) { size_t size = sizeof(wchar_t*) * args->argc; wargv.items = (wchar_t **)PyMem_RawMalloc(size); if (wargv.items == NULL) { return _PyStatus_NO_MEMORY(); } for (Py_ssize_t i = 0; i < args->argc; i++) { size_t len; wchar_t *arg = Py_DecodeLocale(args->bytes_argv[i], &len); if (arg == NULL) { _PyWideStringList_Clear(&wargv); return DECODE_LOCALE_ERR("command line arguments", len); } wargv.items[i] = arg; wargv.length++; } _PyWideStringList_Clear(list); *list = wargv; } else { wargv.length = args->argc; wargv.items = (wchar_t **)args->wchar_argv; if (_PyWideStringList_Copy(list, &wargv) < 0) { return _PyStatus_NO_MEMORY(); } } return _PyStatus_OK(); } /* --- _PyPreCmdline ------------------------------------------------- */ void _PyPreCmdline_Clear(_PyPreCmdline *cmdline) { _PyWideStringList_Clear(&cmdline->argv); _PyWideStringList_Clear(&cmdline->xoptions); } PyStatus _PyPreCmdline_SetArgv(_PyPreCmdline *cmdline, const _PyArgv *args) { return _PyArgv_AsWstrList(args, &cmdline->argv); } static void precmdline_get_preconfig(_PyPreCmdline *cmdline, const PyPreConfig *config) { #define COPY_ATTR(ATTR) \ if (config->ATTR != -1) { \ cmdline->ATTR = config->ATTR; \ } COPY_ATTR(isolated); COPY_ATTR(use_environment); COPY_ATTR(dev_mode); #undef COPY_ATTR } static void precmdline_set_preconfig(const _PyPreCmdline *cmdline, PyPreConfig *config) { #define COPY_ATTR(ATTR) \ config->ATTR = cmdline->ATTR COPY_ATTR(isolated); COPY_ATTR(use_environment); COPY_ATTR(dev_mode); #undef COPY_ATTR } PyStatus _PyPreCmdline_SetConfig(const _PyPreCmdline *cmdline, PyConfig *config) { #define COPY_ATTR(ATTR) \ config->ATTR = cmdline->ATTR PyStatus status = _PyWideStringList_Extend(&config->xoptions, &cmdline->xoptions); if (_PyStatus_EXCEPTION(status)) { return status; } COPY_ATTR(isolated); COPY_ATTR(use_environment); COPY_ATTR(dev_mode); COPY_ATTR(warn_default_encoding); return _PyStatus_OK(); #undef COPY_ATTR } /* Parse the command line arguments */ static PyStatus precmdline_parse_cmdline(_PyPreCmdline *cmdline) { const PyWideStringList *argv = &cmdline->argv; _PyOS_ResetGetOpt(); /* Don't log parsing errors into stderr here: PyConfig_Read() is responsible for that */ _PyOS_opterr = 0; do { int longindex = -1; int c = _PyOS_GetOpt(argv->length, argv->items, &longindex); if (c == EOF || c == 'c' || c == 'm') { break; } switch (c) { case 'E': cmdline->use_environment = 0; break; case 'I': cmdline->isolated = 1; break; case 'X': { PyStatus status = PyWideStringList_Append(&cmdline->xoptions, _PyOS_optarg); if (_PyStatus_EXCEPTION(status)) { return status; } break; } default: /* ignore other argument: handled by PyConfig_Read() */ break; } } while (1); return _PyStatus_OK(); } PyStatus _PyPreCmdline_Read(_PyPreCmdline *cmdline, const PyPreConfig *preconfig) { precmdline_get_preconfig(cmdline, preconfig); if (preconfig->parse_argv) { PyStatus status = precmdline_parse_cmdline(cmdline); if (_PyStatus_EXCEPTION(status)) { return status; } } /* isolated, use_environment */ if (cmdline->isolated < 0) { cmdline->isolated = 0; } if (cmdline->isolated > 0) { cmdline->use_environment = 0; } if (cmdline->use_environment < 0) { cmdline->use_environment = 0; } /* dev_mode */ if ((cmdline->dev_mode < 0) && (_Py_get_xoption(&cmdline->xoptions, L"dev") || _Py_GetEnv(cmdline->use_environment, "PYTHONDEVMODE"))) { cmdline->dev_mode = 1; } if (cmdline->dev_mode < 0) { cmdline->dev_mode = 0; } // warn_default_encoding if (_Py_get_xoption(&cmdline->xoptions, L"warn_default_encoding") || _Py_GetEnv(cmdline->use_environment, "PYTHONWARNDEFAULTENCODING")) { cmdline->warn_default_encoding = 1; } assert(cmdline->use_environment >= 0); assert(cmdline->isolated >= 0); assert(cmdline->dev_mode >= 0); assert(cmdline->warn_default_encoding >= 0); return _PyStatus_OK(); } /* --- PyPreConfig ----------------------------------------------- */ void _PyPreConfig_InitCompatConfig(PyPreConfig *config) { memset(config, 0, sizeof(*config)); config->_config_init = (int)_PyConfig_INIT_COMPAT; config->parse_argv = 0; config->isolated = -1; config->use_environment = -1; config->configure_locale = 1; /* bpo-36443: C locale coercion (PEP 538) and UTF-8 Mode (PEP 540) are disabled by default using the Compat configuration. Py_UTF8Mode=1 enables the UTF-8 mode. PYTHONUTF8 environment variable is ignored (even if use_environment=1). */ config->utf8_mode = 0; config->coerce_c_locale = 0; config->coerce_c_locale_warn = 0; config->dev_mode = -1; config->allocator = PYMEM_ALLOCATOR_NOT_SET; #ifdef MS_WINDOWS config->legacy_windows_fs_encoding = -1; #endif } void PyPreConfig_InitPythonConfig(PyPreConfig *config) { _PyPreConfig_InitCompatConfig(config); config->_config_init = (int)_PyConfig_INIT_PYTHON; config->isolated = 0; config->parse_argv = 1; config->use_environment = 1; /* Set to -1 to enable C locale coercion (PEP 538) and UTF-8 Mode (PEP 540) depending on the LC_CTYPE locale, PYTHONUTF8 and PYTHONCOERCECLOCALE environment variables. */ config->coerce_c_locale = -1; config->coerce_c_locale_warn = -1; config->utf8_mode = -1; #ifdef MS_WINDOWS config->legacy_windows_fs_encoding = 0; #endif } void PyPreConfig_InitIsolatedConfig(PyPreConfig *config) { _PyPreConfig_InitCompatConfig(config); config->_config_init = (int)_PyConfig_INIT_ISOLATED; config->configure_locale = 0; config->isolated = 1; config->use_environment = 0; config->utf8_mode = 0; config->dev_mode = 0; #ifdef MS_WINDOWS config->legacy_windows_fs_encoding = 0; #endif } PyStatus _PyPreConfig_InitFromPreConfig(PyPreConfig *config, const PyPreConfig *config2) { PyPreConfig_InitPythonConfig(config); preconfig_copy(config, config2); return _PyStatus_OK(); } void _PyPreConfig_InitFromConfig(PyPreConfig *preconfig, const PyConfig *config) { _PyConfigInitEnum config_init = (_PyConfigInitEnum)config->_config_init; switch (config_init) { case _PyConfig_INIT_PYTHON: PyPreConfig_InitPythonConfig(preconfig); break; case _PyConfig_INIT_ISOLATED: PyPreConfig_InitIsolatedConfig(preconfig); break; case _PyConfig_INIT_COMPAT: default: _PyPreConfig_InitCompatConfig(preconfig); } _PyPreConfig_GetConfig(preconfig, config); } static void preconfig_copy(PyPreConfig *config, const PyPreConfig *config2) { #define COPY_ATTR(ATTR) config->ATTR = config2->ATTR COPY_ATTR(_config_init); COPY_ATTR(parse_argv); COPY_ATTR(isolated); COPY_ATTR(use_environment); COPY_ATTR(configure_locale); COPY_ATTR(dev_mode); COPY_ATTR(coerce_c_locale); COPY_ATTR(coerce_c_locale_warn); COPY_ATTR(utf8_mode); COPY_ATTR(allocator); #ifdef MS_WINDOWS COPY_ATTR(legacy_windows_fs_encoding); #endif #undef COPY_ATTR } PyObject* _PyPreConfig_AsDict(const PyPreConfig *config) { PyObject *dict; dict = PyDict_New(); if (dict == NULL) { return NULL; } #define SET_ITEM_INT(ATTR) \ do { \ PyObject *obj = PyLong_FromLong(config->ATTR); \ if (obj == NULL) { \ goto fail; \ } \ int res = PyDict_SetItemString(dict, #ATTR, obj); \ Py_DECREF(obj); \ if (res < 0) { \ goto fail; \ } \ } while (0) SET_ITEM_INT(_config_init); SET_ITEM_INT(parse_argv); SET_ITEM_INT(isolated); SET_ITEM_INT(use_environment); SET_ITEM_INT(configure_locale); SET_ITEM_INT(coerce_c_locale); SET_ITEM_INT(coerce_c_locale_warn); SET_ITEM_INT(utf8_mode); #ifdef MS_WINDOWS SET_ITEM_INT(legacy_windows_fs_encoding); #endif SET_ITEM_INT(dev_mode); SET_ITEM_INT(allocator); return dict; fail: Py_DECREF(dict); return NULL; #undef SET_ITEM_INT } void _PyPreConfig_GetConfig(PyPreConfig *preconfig, const PyConfig *config) { #define COPY_ATTR(ATTR) \ if (config->ATTR != -1) { \ preconfig->ATTR = config->ATTR; \ } COPY_ATTR(parse_argv); COPY_ATTR(isolated); COPY_ATTR(use_environment); COPY_ATTR(dev_mode); #undef COPY_ATTR } static void preconfig_get_global_vars(PyPreConfig *config) { if (config->_config_init != _PyConfig_INIT_COMPAT) { /* Python and Isolated configuration ignore global variables */ return; } #define COPY_FLAG(ATTR, VALUE) \ if (config->ATTR < 0) { \ config->ATTR = VALUE; \ } #define COPY_NOT_FLAG(ATTR, VALUE) \ if (config->ATTR < 0) { \ config->ATTR = !(VALUE); \ } _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS COPY_FLAG(isolated, Py_IsolatedFlag); COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag); if (Py_UTF8Mode > 0) { config->utf8_mode = Py_UTF8Mode; } #ifdef MS_WINDOWS COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag); #endif _Py_COMP_DIAG_POP #undef COPY_FLAG #undef COPY_NOT_FLAG } static void preconfig_set_global_vars(const PyPreConfig *config) { #define COPY_FLAG(ATTR, VAR) \ if (config->ATTR >= 0) { \ VAR = config->ATTR; \ } #define COPY_NOT_FLAG(ATTR, VAR) \ if (config->ATTR >= 0) { \ VAR = !config->ATTR; \ } _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS COPY_FLAG(isolated, Py_IsolatedFlag); COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag); #ifdef MS_WINDOWS COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag); #endif COPY_FLAG(utf8_mode, Py_UTF8Mode); _Py_COMP_DIAG_POP #undef COPY_FLAG #undef COPY_NOT_FLAG } const char* _Py_GetEnv(int use_environment, const char *name) { assert(use_environment >= 0); if (!use_environment) { return NULL; } const char *var = getenv(name); if (var && var[0] != '\0') { return var; } else { return NULL; } } int _Py_str_to_int(const char *str, int *result) { const char *endptr = str; errno = 0; long value = strtol(str, (char **)&endptr, 10); if (*endptr != '\0' || errno == ERANGE) { return -1; } if (value < INT_MIN || value > INT_MAX) { return -1; } *result = (int)value; return 0; } void _Py_get_env_flag(int use_environment, int *flag, const char *name) { const char *var = _Py_GetEnv(use_environment, name); if (!var) { return; } int value; if (_Py_str_to_int(var, &value) < 0 || value < 0) { /* PYTHONDEBUG=text and PYTHONDEBUG=-2 behave as PYTHONDEBUG=1 */ value = 1; } if (*flag < value) { *flag = value; } } const wchar_t* _Py_get_xoption(const PyWideStringList *xoptions, const wchar_t *name) { for (Py_ssize_t i=0; i < xoptions->length; i++) { const wchar_t *option = xoptions->items[i]; size_t len; wchar_t *sep = wcschr(option, L'='); if (sep != NULL) { len = (sep - option); } else { len = wcslen(option); } if (wcsncmp(option, name, len) == 0 && name[len] == L'\0') { return option; } } return NULL; } static PyStatus preconfig_init_utf8_mode(PyPreConfig *config, const _PyPreCmdline *cmdline) { #ifdef MS_WINDOWS if (config->legacy_windows_fs_encoding) { config->utf8_mode = 0; } #endif if (config->utf8_mode >= 0) { return _PyStatus_OK(); } const wchar_t *xopt; xopt = _Py_get_xoption(&cmdline->xoptions, L"utf8"); if (xopt) { wchar_t *sep = wcschr(xopt, L'='); if (sep) { xopt = sep + 1; if (wcscmp(xopt, L"1") == 0) { config->utf8_mode = 1; } else if (wcscmp(xopt, L"0") == 0) { config->utf8_mode = 0; } else { return _PyStatus_ERR("invalid -X utf8 option value"); } } else { config->utf8_mode = 1; } return _PyStatus_OK(); } const char *opt = _Py_GetEnv(config->use_environment, "PYTHONUTF8"); if (opt) { if (strcmp(opt, "1") == 0) { config->utf8_mode = 1; } else if (strcmp(opt, "0") == 0) { config->utf8_mode = 0; } else { return _PyStatus_ERR("invalid PYTHONUTF8 environment " "variable value"); } return _PyStatus_OK(); } #ifndef MS_WINDOWS if (config->utf8_mode < 0) { /* The C locale and the POSIX locale enable the UTF-8 Mode (PEP 540) */ const char *ctype_loc = setlocale(LC_CTYPE, NULL); if (ctype_loc != NULL && (strcmp(ctype_loc, "C") == 0 || strcmp(ctype_loc, "POSIX") == 0)) { config->utf8_mode = 1; } } #endif if (config->utf8_mode < 0) { config->utf8_mode = 0; } return _PyStatus_OK(); } static void preconfig_init_coerce_c_locale(PyPreConfig *config) { if (!config->configure_locale) { config->coerce_c_locale = 0; config->coerce_c_locale_warn = 0; return; } const char *env = _Py_GetEnv(config->use_environment, "PYTHONCOERCECLOCALE"); if (env) { if (strcmp(env, "0") == 0) { if (config->coerce_c_locale < 0) { config->coerce_c_locale = 0; } } else if (strcmp(env, "warn") == 0) { if (config->coerce_c_locale_warn < 0) { config->coerce_c_locale_warn = 1; } } else { if (config->coerce_c_locale < 0) { config->coerce_c_locale = 1; } } } /* Test if coerce_c_locale equals to -1 or equals to 1: PYTHONCOERCECLOCALE=1 doesn't imply that the C locale is always coerced. It is only coerced if if the LC_CTYPE locale is "C". */ if (config->coerce_c_locale < 0 || config->coerce_c_locale == 1) { /* The C locale enables the C locale coercion (PEP 538) */ if (_Py_LegacyLocaleDetected(0)) { config->coerce_c_locale = 2; } else { config->coerce_c_locale = 0; } } if (config->coerce_c_locale_warn < 0) { config->coerce_c_locale_warn = 0; } } static PyStatus preconfig_init_allocator(PyPreConfig *config) { if (config->allocator == PYMEM_ALLOCATOR_NOT_SET) { /* bpo-34247. The PYTHONMALLOC environment variable has the priority over PYTHONDEV env var and "-X dev" command line option. For example, PYTHONMALLOC=malloc PYTHONDEVMODE=1 sets the memory allocators to "malloc" (and not to "debug"). */ const char *envvar = _Py_GetEnv(config->use_environment, "PYTHONMALLOC"); if (envvar) { PyMemAllocatorName name; if (_PyMem_GetAllocatorName(envvar, &name) < 0) { return _PyStatus_ERR("PYTHONMALLOC: unknown allocator"); } config->allocator = (int)name; } } if (config->dev_mode && config->allocator == PYMEM_ALLOCATOR_NOT_SET) { config->allocator = PYMEM_ALLOCATOR_DEBUG; } return _PyStatus_OK(); } static PyStatus preconfig_read(PyPreConfig *config, _PyPreCmdline *cmdline) { PyStatus status; status = _PyPreCmdline_Read(cmdline, config); if (_PyStatus_EXCEPTION(status)) { return status; } precmdline_set_preconfig(cmdline, config); /* legacy_windows_fs_encoding, coerce_c_locale, utf8_mode */ #ifdef MS_WINDOWS _Py_get_env_flag(config->use_environment, &config->legacy_windows_fs_encoding, "PYTHONLEGACYWINDOWSFSENCODING"); #endif preconfig_init_coerce_c_locale(config); status = preconfig_init_utf8_mode(config, cmdline); if (_PyStatus_EXCEPTION(status)) { return status; } /* allocator */ status = preconfig_init_allocator(config); if (_PyStatus_EXCEPTION(status)) { return status; } assert(config->coerce_c_locale >= 0); assert(config->coerce_c_locale_warn >= 0); #ifdef MS_WINDOWS assert(config->legacy_windows_fs_encoding >= 0); #endif assert(config->utf8_mode >= 0); assert(config->isolated >= 0); assert(config->use_environment >= 0); assert(config->dev_mode >= 0); return _PyStatus_OK(); } /* Read the configuration from: - command line arguments - environment variables - Py_xxx global configuration variables - the LC_CTYPE locale */ PyStatus _PyPreConfig_Read(PyPreConfig *config, const _PyArgv *args) { PyStatus status; status = _PyRuntime_Initialize(); if (_PyStatus_EXCEPTION(status)) { return status; } preconfig_get_global_vars(config); /* Copy LC_CTYPE locale, since it's modified later */ const char *loc = setlocale(LC_CTYPE, NULL); if (loc == NULL) { return _PyStatus_ERR("failed to LC_CTYPE locale"); } char *init_ctype_locale = _PyMem_RawStrdup(loc); if (init_ctype_locale == NULL) { return _PyStatus_NO_MEMORY(); } /* Save the config to be able to restore it if encodings change */ PyPreConfig save_config; status = _PyPreConfig_InitFromPreConfig(&save_config, config); if (_PyStatus_EXCEPTION(status)) { return status; } /* Set LC_CTYPE to the user preferred locale */ if (config->configure_locale) { _Py_SetLocaleFromEnv(LC_CTYPE); } PyPreConfig save_runtime_config; preconfig_copy(&save_runtime_config, &_PyRuntime.preconfig); _PyPreCmdline cmdline = _PyPreCmdline_INIT; int locale_coerced = 0; int loops = 0; while (1) { int utf8_mode = config->utf8_mode; /* Watchdog to prevent an infinite loop */ loops++; if (loops == 3) { status = _PyStatus_ERR("Encoding changed twice while " "reading the configuration"); goto done; } /* bpo-34207: Py_DecodeLocale() and Py_EncodeLocale() depend on the utf8_mode and legacy_windows_fs_encoding members of _PyRuntime.preconfig. */ preconfig_copy(&_PyRuntime.preconfig, config); if (args) { // Set command line arguments at each iteration. If they are bytes // strings, they are decoded from the new encoding. status = _PyPreCmdline_SetArgv(&cmdline, args); if (_PyStatus_EXCEPTION(status)) { goto done; } } status = preconfig_read(config, &cmdline); if (_PyStatus_EXCEPTION(status)) { goto done; } /* The legacy C locale assumes ASCII as the default text encoding, which * causes problems not only for the CPython runtime, but also other * components like GNU readline. * * Accordingly, when the CLI detects it, it attempts to coerce it to a * more capable UTF-8 based alternative. * * See the documentation of the PYTHONCOERCECLOCALE setting for more * details. */ int encoding_changed = 0; if (config->coerce_c_locale && !locale_coerced) { locale_coerced = 1; _Py_CoerceLegacyLocale(0); encoding_changed = 1; } if (utf8_mode == -1) { if (config->utf8_mode == 1) { /* UTF-8 Mode enabled */ encoding_changed = 1; } } else { if (config->utf8_mode != utf8_mode) { encoding_changed = 1; } } if (!encoding_changed) { break; } /* Reset the configuration before reading again the configuration, just keep UTF-8 Mode and coerce C locale value. */ int new_utf8_mode = config->utf8_mode; int new_coerce_c_locale = config->coerce_c_locale; preconfig_copy(config, &save_config); config->utf8_mode = new_utf8_mode; config->coerce_c_locale = new_coerce_c_locale; /* The encoding changed: read again the configuration with the new encoding */ } status = _PyStatus_OK(); done: // Revert side effects setlocale(LC_CTYPE, init_ctype_locale); PyMem_RawFree(init_ctype_locale); preconfig_copy(&_PyRuntime.preconfig, &save_runtime_config); _PyPreCmdline_Clear(&cmdline); return status; } /* Write the pre-configuration: - set the memory allocators - set Py_xxx global configuration variables - set the LC_CTYPE locale (coerce C locale, PEP 538) and set the UTF-8 mode (PEP 540) The applied configuration is written into _PyRuntime.preconfig. If the C locale cannot be coerced, set coerce_c_locale to 0. Do nothing if called after Py_Initialize(): ignore the new pre-configuration. */ PyStatus _PyPreConfig_Write(const PyPreConfig *src_config) { PyPreConfig config; PyStatus status = _PyPreConfig_InitFromPreConfig(&config, src_config); if (_PyStatus_EXCEPTION(status)) { return status; } if (_PyRuntime.core_initialized) { /* bpo-34008: Calling this functions after Py_Initialize() ignores the new configuration. */ return _PyStatus_OK(); } PyMemAllocatorName name = (PyMemAllocatorName)config.allocator; if (name != PYMEM_ALLOCATOR_NOT_SET) { if (_PyMem_SetupAllocators(name) < 0) { return _PyStatus_ERR("Unknown PYTHONMALLOC allocator"); } } preconfig_set_global_vars(&config); if (config.configure_locale) { if (config.coerce_c_locale) { if (!_Py_CoerceLegacyLocale(config.coerce_c_locale_warn)) { /* C locale not coerced */ config.coerce_c_locale = 0; } } /* Set LC_CTYPE to the user preferred locale */ _Py_SetLocaleFromEnv(LC_CTYPE); } /* Write the new pre-configuration into _PyRuntime */ preconfig_copy(&_PyRuntime.preconfig, &config); return _PyStatus_OK(); } ================================================ FILE: PyArena.c ================================================ #include "Python.h" #include "pycore_pyarena.h" // PyArena /* A simple arena block structure. Measurements with standard library modules suggest the average allocation is about 20 bytes and that most compiles use a single block. TODO(jhylton): Think about a realloc API, maybe just for the last allocation? */ #define DEFAULT_BLOCK_SIZE 8192 #define ALIGNMENT 8 typedef struct _block { /* Total number of bytes owned by this block available to pass out. * Read-only after initialization. The first such byte starts at * ab_mem. */ size_t ab_size; /* Total number of bytes already passed out. The next byte available * to pass out starts at ab_mem + ab_offset. */ size_t ab_offset; /* An arena maintains a singly-linked, NULL-terminated list of * all blocks owned by the arena. These are linked via the * ab_next member. */ struct _block *ab_next; /* Pointer to the first allocatable byte owned by this block. Read- * only after initialization. */ void *ab_mem; } block; /* The arena manages two kinds of memory, blocks of raw memory and a list of PyObject* pointers. PyObjects are decrefed when the arena is freed. */ struct _arena { /* Pointer to the first block allocated for the arena, never NULL. It is used only to find the first block when the arena is being freed. */ block *a_head; /* Pointer to the block currently used for allocation. Its ab_next field should be NULL. If it is not-null after a call to block_alloc(), it means a new block has been allocated and a_cur should be reset to point it. */ block *a_cur; /* A Python list object containing references to all the PyObject pointers associated with this arena. They will be DECREFed when the arena is freed. */ PyObject *a_objects; #if defined(Py_DEBUG) /* Debug output */ size_t total_allocs; size_t total_size; size_t total_blocks; size_t total_block_size; size_t total_big_blocks; #endif }; static block * block_new(size_t size) { /* Allocate header and block as one unit. ab_mem points just past header. */ block *b = (block *)PyMem_Malloc(sizeof(block) + size); if (!b) return NULL; b->ab_size = size; b->ab_mem = (void *)(b + 1); b->ab_next = NULL; b->ab_offset = (char *)_Py_ALIGN_UP(b->ab_mem, ALIGNMENT) - (char *)(b->ab_mem); return b; } static void block_free(block *b) { while (b) { block *next = b->ab_next; PyMem_Free(b); b = next; } } static void * block_alloc(block *b, size_t size) { void *p; assert(b); size = _Py_SIZE_ROUND_UP(size, ALIGNMENT); if (b->ab_offset + size > b->ab_size) { /* If we need to allocate more memory than will fit in the default block, allocate a one-off block that is exactly the right size. */ /* TODO(jhylton): Think about space waste at end of block */ block *newbl = block_new( size < DEFAULT_BLOCK_SIZE ? DEFAULT_BLOCK_SIZE : size); if (!newbl) return NULL; assert(!b->ab_next); b->ab_next = newbl; b = newbl; } assert(b->ab_offset + size <= b->ab_size); p = (void *)(((char *)b->ab_mem) + b->ab_offset); b->ab_offset += size; return p; } PyArena * _PyArena_New(void) { PyArena* arena = (PyArena *)PyMem_Malloc(sizeof(PyArena)); if (!arena) return (PyArena*)PyErr_NoMemory(); arena->a_head = block_new(DEFAULT_BLOCK_SIZE); arena->a_cur = arena->a_head; if (!arena->a_head) { PyMem_Free((void *)arena); return (PyArena*)PyErr_NoMemory(); } arena->a_objects = PyList_New(0); if (!arena->a_objects) { block_free(arena->a_head); PyMem_Free((void *)arena); return (PyArena*)PyErr_NoMemory(); } #if defined(Py_DEBUG) arena->total_allocs = 0; arena->total_size = 0; arena->total_blocks = 1; arena->total_block_size = DEFAULT_BLOCK_SIZE; arena->total_big_blocks = 0; #endif return arena; } void _PyArena_Free(PyArena *arena) { assert(arena); #if defined(Py_DEBUG) /* fprintf(stderr, "alloc=%zu size=%zu blocks=%zu block_size=%zu big=%zu objects=%zu\n", arena->total_allocs, arena->total_size, arena->total_blocks, arena->total_block_size, arena->total_big_blocks, PyList_Size(arena->a_objects)); */ #endif block_free(arena->a_head); /* This property normally holds, except when the code being compiled is sys.getobjects(0), in which case there will be two references. assert(arena->a_objects->ob_refcnt == 1); */ Py_DECREF(arena->a_objects); PyMem_Free(arena); } void * _PyArena_Malloc(PyArena *arena, size_t size) { void *p = block_alloc(arena->a_cur, size); if (!p) return PyErr_NoMemory(); #if defined(Py_DEBUG) arena->total_allocs++; arena->total_size += size; #endif /* Reset cur if we allocated a new block. */ if (arena->a_cur->ab_next) { arena->a_cur = arena->a_cur->ab_next; #if defined(Py_DEBUG) arena->total_blocks++; arena->total_block_size += arena->a_cur->ab_size; if (arena->a_cur->ab_size > DEFAULT_BLOCK_SIZE) ++arena->total_big_blocks; #endif } return p; } int _PyArena_AddPyObject(PyArena *arena, PyObject *obj) { int r = PyList_Append(arena->a_objects, obj); if (r >= 0) { Py_DECREF(obj); } return r; } ================================================ FILE: PyCtype.c ================================================ #include "Python.h" /* Our own locale-independent ctype.h-like macros */ const unsigned int _Py_ctype_table[256] = { 0, /* 0x0 '\x00' */ 0, /* 0x1 '\x01' */ 0, /* 0x2 '\x02' */ 0, /* 0x3 '\x03' */ 0, /* 0x4 '\x04' */ 0, /* 0x5 '\x05' */ 0, /* 0x6 '\x06' */ 0, /* 0x7 '\x07' */ 0, /* 0x8 '\x08' */ PY_CTF_SPACE, /* 0x9 '\t' */ PY_CTF_SPACE, /* 0xa '\n' */ PY_CTF_SPACE, /* 0xb '\v' */ PY_CTF_SPACE, /* 0xc '\f' */ PY_CTF_SPACE, /* 0xd '\r' */ 0, /* 0xe '\x0e' */ 0, /* 0xf '\x0f' */ 0, /* 0x10 '\x10' */ 0, /* 0x11 '\x11' */ 0, /* 0x12 '\x12' */ 0, /* 0x13 '\x13' */ 0, /* 0x14 '\x14' */ 0, /* 0x15 '\x15' */ 0, /* 0x16 '\x16' */ 0, /* 0x17 '\x17' */ 0, /* 0x18 '\x18' */ 0, /* 0x19 '\x19' */ 0, /* 0x1a '\x1a' */ 0, /* 0x1b '\x1b' */ 0, /* 0x1c '\x1c' */ 0, /* 0x1d '\x1d' */ 0, /* 0x1e '\x1e' */ 0, /* 0x1f '\x1f' */ PY_CTF_SPACE, /* 0x20 ' ' */ 0, /* 0x21 '!' */ 0, /* 0x22 '"' */ 0, /* 0x23 '#' */ 0, /* 0x24 '$' */ 0, /* 0x25 '%' */ 0, /* 0x26 '&' */ 0, /* 0x27 "'" */ 0, /* 0x28 '(' */ 0, /* 0x29 ')' */ 0, /* 0x2a '*' */ 0, /* 0x2b '+' */ 0, /* 0x2c ',' */ 0, /* 0x2d '-' */ 0, /* 0x2e '.' */ 0, /* 0x2f '/' */ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x30 '0' */ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x31 '1' */ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x32 '2' */ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x33 '3' */ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x34 '4' */ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x35 '5' */ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x36 '6' */ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x37 '7' */ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x38 '8' */ PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x39 '9' */ 0, /* 0x3a ':' */ 0, /* 0x3b ';' */ 0, /* 0x3c '<' */ 0, /* 0x3d '=' */ 0, /* 0x3e '>' */ 0, /* 0x3f '?' */ 0, /* 0x40 '@' */ PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x41 'A' */ PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x42 'B' */ PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x43 'C' */ PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x44 'D' */ PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x45 'E' */ PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x46 'F' */ PY_CTF_UPPER, /* 0x47 'G' */ PY_CTF_UPPER, /* 0x48 'H' */ PY_CTF_UPPER, /* 0x49 'I' */ PY_CTF_UPPER, /* 0x4a 'J' */ PY_CTF_UPPER, /* 0x4b 'K' */ PY_CTF_UPPER, /* 0x4c 'L' */ PY_CTF_UPPER, /* 0x4d 'M' */ PY_CTF_UPPER, /* 0x4e 'N' */ PY_CTF_UPPER, /* 0x4f 'O' */ PY_CTF_UPPER, /* 0x50 'P' */ PY_CTF_UPPER, /* 0x51 'Q' */ PY_CTF_UPPER, /* 0x52 'R' */ PY_CTF_UPPER, /* 0x53 'S' */ PY_CTF_UPPER, /* 0x54 'T' */ PY_CTF_UPPER, /* 0x55 'U' */ PY_CTF_UPPER, /* 0x56 'V' */ PY_CTF_UPPER, /* 0x57 'W' */ PY_CTF_UPPER, /* 0x58 'X' */ PY_CTF_UPPER, /* 0x59 'Y' */ PY_CTF_UPPER, /* 0x5a 'Z' */ 0, /* 0x5b '[' */ 0, /* 0x5c '\\' */ 0, /* 0x5d ']' */ 0, /* 0x5e '^' */ 0, /* 0x5f '_' */ 0, /* 0x60 '`' */ PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x61 'a' */ PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x62 'b' */ PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x63 'c' */ PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x64 'd' */ PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x65 'e' */ PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x66 'f' */ PY_CTF_LOWER, /* 0x67 'g' */ PY_CTF_LOWER, /* 0x68 'h' */ PY_CTF_LOWER, /* 0x69 'i' */ PY_CTF_LOWER, /* 0x6a 'j' */ PY_CTF_LOWER, /* 0x6b 'k' */ PY_CTF_LOWER, /* 0x6c 'l' */ PY_CTF_LOWER, /* 0x6d 'm' */ PY_CTF_LOWER, /* 0x6e 'n' */ PY_CTF_LOWER, /* 0x6f 'o' */ PY_CTF_LOWER, /* 0x70 'p' */ PY_CTF_LOWER, /* 0x71 'q' */ PY_CTF_LOWER, /* 0x72 'r' */ PY_CTF_LOWER, /* 0x73 's' */ PY_CTF_LOWER, /* 0x74 't' */ PY_CTF_LOWER, /* 0x75 'u' */ PY_CTF_LOWER, /* 0x76 'v' */ PY_CTF_LOWER, /* 0x77 'w' */ PY_CTF_LOWER, /* 0x78 'x' */ PY_CTF_LOWER, /* 0x79 'y' */ PY_CTF_LOWER, /* 0x7a 'z' */ 0, /* 0x7b '{' */ 0, /* 0x7c '|' */ 0, /* 0x7d '}' */ 0, /* 0x7e '~' */ 0, /* 0x7f '\x7f' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; const unsigned char _Py_ctype_tolower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, }; const unsigned char _Py_ctype_toupper[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, }; ================================================ FILE: PyFpc.c ================================================ /* These variables used to be used when Python was built with --with-fpectl, * but support for that was dropped in 3.7. We continue to define them, * though, because they may be referenced by extensions using the stable ABI. */ #ifdef HAVE_SETJMP_H #include jmp_buf PyFPE_jbuf; #endif int PyFPE_counter; double PyFPE_dummy(void *dummy) { return 1.0; } ================================================ FILE: PyHash.c ================================================ /* Set of hash utility functions to help maintaining the invariant that if a==b then hash(a)==hash(b) All the utility functions (_Py_Hash*()) return "-1" to signify an error. */ #include "Python.h" #ifdef __APPLE__ # include #elif defined(HAVE_LE64TOH) && defined(HAVE_ENDIAN_H) # include #elif defined(HAVE_LE64TOH) && defined(HAVE_SYS_ENDIAN_H) # include #endif #ifdef __cplusplus extern "C" { #endif _Py_HashSecret_t _Py_HashSecret = {{0}}; #if Py_HASH_ALGORITHM == Py_HASH_EXTERNAL extern PyHash_FuncDef PyHash_Func; #else static PyHash_FuncDef PyHash_Func; #endif /* Count _Py_HashBytes() calls */ #ifdef Py_HASH_STATS #define Py_HASH_STATS_MAX 32 static Py_ssize_t hashstats[Py_HASH_STATS_MAX + 1] = {0}; #endif /* For numeric types, the hash of a number x is based on the reduction of x modulo the prime P = 2**_PyHASH_BITS - 1. It's designed so that hash(x) == hash(y) whenever x and y are numerically equal, even if x and y have different types. A quick summary of the hashing strategy: (1) First define the 'reduction of x modulo P' for any rational number x; this is a standard extension of the usual notion of reduction modulo P for integers. If x == p/q (written in lowest terms), the reduction is interpreted as the reduction of p times the inverse of the reduction of q, all modulo P; if q is exactly divisible by P then define the reduction to be infinity. So we've got a well-defined map reduce : { rational numbers } -> { 0, 1, 2, ..., P-1, infinity }. (2) Now for a rational number x, define hash(x) by: reduce(x) if x >= 0 -reduce(-x) if x < 0 If the result of the reduction is infinity (this is impossible for integers, floats and Decimals) then use the predefined hash value _PyHASH_INF for x >= 0, or -_PyHASH_INF for x < 0, instead. _PyHASH_INF and -_PyHASH_INF are also used for the hashes of float and Decimal infinities. NaNs hash with a pointer hash. Having distinct hash values prevents catastrophic pileups from distinct NaN instances which used to always have the same hash value but would compare unequal. A selling point for the above strategy is that it makes it possible to compute hashes of decimal and binary floating-point numbers efficiently, even if the exponent of the binary or decimal number is large. The key point is that reduce(x * y) == reduce(x) * reduce(y) (modulo _PyHASH_MODULUS) provided that {reduce(x), reduce(y)} != {0, infinity}. The reduction of a binary or decimal float is never infinity, since the denominator is a power of 2 (for binary) or a divisor of a power of 10 (for decimal). So we have, for nonnegative x, reduce(x * 2**e) == reduce(x) * reduce(2**e) % _PyHASH_MODULUS reduce(x * 10**e) == reduce(x) * reduce(10**e) % _PyHASH_MODULUS and reduce(10**e) can be computed efficiently by the usual modular exponentiation algorithm. For reduce(2**e) it's even better: since P is of the form 2**n-1, reduce(2**e) is 2**(e mod n), and multiplication by 2**(e mod n) modulo 2**n-1 just amounts to a rotation of bits. */ Py_hash_t _Py_HashPointer(const void *); Py_hash_t _Py_HashDouble(PyObject *inst, double v) { int e, sign; double m; Py_uhash_t x, y; if (!Py_IS_FINITE(v)) { if (Py_IS_INFINITY(v)) return v > 0 ? _PyHASH_INF : -_PyHASH_INF; else return _Py_HashPointer(inst); } m = frexp(v, &e); sign = 1; if (m < 0) { sign = -1; m = -m; } /* process 28 bits at a time; this should work well both for binary and hexadecimal floating point. */ x = 0; while (m) { x = ((x << 28) & _PyHASH_MODULUS) | x >> (_PyHASH_BITS - 28); m *= 268435456.0; /* 2**28 */ e -= 28; y = (Py_uhash_t)m; /* pull out integer part */ m -= y; x += y; if (x >= _PyHASH_MODULUS) x -= _PyHASH_MODULUS; } /* adjust for the exponent; first reduce it modulo _PyHASH_BITS */ e = e >= 0 ? e % _PyHASH_BITS : _PyHASH_BITS-1-((-1-e) % _PyHASH_BITS); x = ((x << e) & _PyHASH_MODULUS) | x >> (_PyHASH_BITS - e); x = x * sign; if (x == (Py_uhash_t)-1) x = (Py_uhash_t)-2; return (Py_hash_t)x; } Py_hash_t _Py_HashPointerRaw(const void *p) { size_t y = (size_t)p; /* bottom 3 or 4 bits are likely to be 0; rotate y by 4 to avoid excessive hash collisions for dicts and sets */ y = (y >> 4) | (y << (8 * SIZEOF_VOID_P - 4)); return (Py_hash_t)y; } Py_hash_t _Py_HashPointer(const void *p) { Py_hash_t x = _Py_HashPointerRaw(p); if (x == -1) { x = -2; } return x; } Py_hash_t _Py_HashBytes(const void *src, Py_ssize_t len) { Py_hash_t x; /* We make the hash of the empty string be 0, rather than using (prefix ^ suffix), since this slightly obfuscates the hash secret */ if (len == 0) { return 0; } #ifdef Py_HASH_STATS hashstats[(len <= Py_HASH_STATS_MAX) ? len : 0]++; #endif #if Py_HASH_CUTOFF > 0 if (len < Py_HASH_CUTOFF) { /* Optimize hashing of very small strings with inline DJBX33A. */ Py_uhash_t hash; const unsigned char *p = src; hash = 5381; /* DJBX33A starts with 5381 */ switch(len) { /* ((hash << 5) + hash) + *p == hash * 33 + *p */ case 7: hash = ((hash << 5) + hash) + *p++; /* fallthrough */ case 6: hash = ((hash << 5) + hash) + *p++; /* fallthrough */ case 5: hash = ((hash << 5) + hash) + *p++; /* fallthrough */ case 4: hash = ((hash << 5) + hash) + *p++; /* fallthrough */ case 3: hash = ((hash << 5) + hash) + *p++; /* fallthrough */ case 2: hash = ((hash << 5) + hash) + *p++; /* fallthrough */ case 1: hash = ((hash << 5) + hash) + *p++; break; default: Py_UNREACHABLE(); } hash ^= len; hash ^= (Py_uhash_t) _Py_HashSecret.djbx33a.suffix; x = (Py_hash_t)hash; } else #endif /* Py_HASH_CUTOFF */ x = PyHash_Func.hash(src, len); if (x == -1) return -2; return x; } void _PyHash_Fini(void) { #ifdef Py_HASH_STATS fprintf(stderr, "len calls total\n"); Py_ssize_t total = 0; for (int i = 1; i <= Py_HASH_STATS_MAX; i++) { total += hashstats[i]; fprintf(stderr, "%2i %8zd %8zd\n", i, hashstats[i], total); } total += hashstats[0]; fprintf(stderr, "> %8zd %8zd\n", hashstats[0], total); #endif } PyHash_FuncDef * PyHash_GetFuncDef(void) { return &PyHash_Func; } /* Optimized memcpy() for Windows */ #ifdef _MSC_VER # if SIZEOF_PY_UHASH_T == 4 # define PY_UHASH_CPY(dst, src) do { \ dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; \ } while(0) # elif SIZEOF_PY_UHASH_T == 8 # define PY_UHASH_CPY(dst, src) do { \ dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; \ dst[4] = src[4]; dst[5] = src[5]; dst[6] = src[6]; dst[7] = src[7]; \ } while(0) # else # error SIZEOF_PY_UHASH_T must be 4 or 8 # endif /* SIZEOF_PY_UHASH_T */ #else /* not Windows */ # define PY_UHASH_CPY(dst, src) memcpy(dst, src, SIZEOF_PY_UHASH_T) #endif /* _MSC_VER */ #if Py_HASH_ALGORITHM == Py_HASH_FNV /* ************************************************************************** * Modified Fowler-Noll-Vo (FNV) hash function */ static Py_hash_t fnv(const void *src, Py_ssize_t len) { const unsigned char *p = src; Py_uhash_t x; Py_ssize_t remainder, blocks; union { Py_uhash_t value; unsigned char bytes[SIZEOF_PY_UHASH_T]; } block; #ifdef Py_DEBUG assert(_Py_HashSecret_Initialized); #endif remainder = len % SIZEOF_PY_UHASH_T; if (remainder == 0) { /* Process at least one block byte by byte to reduce hash collisions * for strings with common prefixes. */ remainder = SIZEOF_PY_UHASH_T; } blocks = (len - remainder) / SIZEOF_PY_UHASH_T; x = (Py_uhash_t) _Py_HashSecret.fnv.prefix; x ^= (Py_uhash_t) *p << 7; while (blocks--) { PY_UHASH_CPY(block.bytes, p); x = (_PyHASH_MULTIPLIER * x) ^ block.value; p += SIZEOF_PY_UHASH_T; } /* add remainder */ for (; remainder > 0; remainder--) x = (_PyHASH_MULTIPLIER * x) ^ (Py_uhash_t) *p++; x ^= (Py_uhash_t) len; x ^= (Py_uhash_t) _Py_HashSecret.fnv.suffix; if (x == (Py_uhash_t) -1) { x = (Py_uhash_t) -2; } return x; } static PyHash_FuncDef PyHash_Func = {fnv, "fnv", 8 * SIZEOF_PY_HASH_T, 16 * SIZEOF_PY_HASH_T}; #endif /* Py_HASH_ALGORITHM == Py_HASH_FNV */ /* ************************************************************************** Copyright (c) 2013 Marek Majkowski Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Original location: https://github.com/majek/csiphash/ Solution inspired by code from: Samuel Neves (supercop/crypto_auth/siphash24/little) djb (supercop/crypto_auth/siphash24/little2) Jean-Philippe Aumasson (https://131002.net/siphash/siphash24.c) Modified for Python by Christian Heimes: - C89 / MSVC compatibility - _rotl64() on Windows - letoh64() fallback */ /* byte swap little endian to host endian * Endian conversion not only ensures that the hash function returns the same * value on all platforms. It is also required to for a good dispersion of * the hash values' least significant bits. */ #if PY_LITTLE_ENDIAN # define _le64toh(x) ((uint64_t)(x)) #elif defined(__APPLE__) # define _le64toh(x) OSSwapLittleToHostInt64(x) #elif defined(HAVE_LETOH64) # define _le64toh(x) le64toh(x) #else # define _le64toh(x) (((uint64_t)(x) << 56) | \ (((uint64_t)(x) << 40) & 0xff000000000000ULL) | \ (((uint64_t)(x) << 24) & 0xff0000000000ULL) | \ (((uint64_t)(x) << 8) & 0xff00000000ULL) | \ (((uint64_t)(x) >> 8) & 0xff000000ULL) | \ (((uint64_t)(x) >> 24) & 0xff0000ULL) | \ (((uint64_t)(x) >> 40) & 0xff00ULL) | \ ((uint64_t)(x) >> 56)) #endif #ifdef _MSC_VER # define ROTATE(x, b) _rotl64(x, b) #else # define ROTATE(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) ) #endif #define HALF_ROUND(a,b,c,d,s,t) \ a += b; c += d; \ b = ROTATE(b, s) ^ a; \ d = ROTATE(d, t) ^ c; \ a = ROTATE(a, 32); #define SINGLE_ROUND(v0,v1,v2,v3) \ HALF_ROUND(v0,v1,v2,v3,13,16); \ HALF_ROUND(v2,v1,v0,v3,17,21); #define DOUBLE_ROUND(v0,v1,v2,v3) \ SINGLE_ROUND(v0,v1,v2,v3); \ SINGLE_ROUND(v0,v1,v2,v3); static uint64_t siphash13(uint64_t k0, uint64_t k1, const void *src, Py_ssize_t src_sz) { uint64_t b = (uint64_t)src_sz << 56; const uint8_t *in = (const uint8_t*)src; uint64_t v0 = k0 ^ 0x736f6d6570736575ULL; uint64_t v1 = k1 ^ 0x646f72616e646f6dULL; uint64_t v2 = k0 ^ 0x6c7967656e657261ULL; uint64_t v3 = k1 ^ 0x7465646279746573ULL; uint64_t t; uint8_t *pt; while (src_sz >= 8) { uint64_t mi; memcpy(&mi, in, sizeof(mi)); mi = _le64toh(mi); in += sizeof(mi); src_sz -= sizeof(mi); v3 ^= mi; SINGLE_ROUND(v0,v1,v2,v3); v0 ^= mi; } t = 0; pt = (uint8_t *)&t; switch (src_sz) { case 7: pt[6] = in[6]; /* fall through */ case 6: pt[5] = in[5]; /* fall through */ case 5: pt[4] = in[4]; /* fall through */ case 4: memcpy(pt, in, sizeof(uint32_t)); break; case 3: pt[2] = in[2]; /* fall through */ case 2: pt[1] = in[1]; /* fall through */ case 1: pt[0] = in[0]; /* fall through */ } b |= _le64toh(t); v3 ^= b; SINGLE_ROUND(v0,v1,v2,v3); v0 ^= b; v2 ^= 0xff; SINGLE_ROUND(v0,v1,v2,v3); SINGLE_ROUND(v0,v1,v2,v3); SINGLE_ROUND(v0,v1,v2,v3); /* modified */ t = (v0 ^ v1) ^ (v2 ^ v3); return t; } #if Py_HASH_ALGORITHM == Py_HASH_SIPHASH24 static uint64_t siphash24(uint64_t k0, uint64_t k1, const void *src, Py_ssize_t src_sz) { uint64_t b = (uint64_t)src_sz << 56; const uint8_t *in = (const uint8_t*)src; uint64_t v0 = k0 ^ 0x736f6d6570736575ULL; uint64_t v1 = k1 ^ 0x646f72616e646f6dULL; uint64_t v2 = k0 ^ 0x6c7967656e657261ULL; uint64_t v3 = k1 ^ 0x7465646279746573ULL; uint64_t t; uint8_t *pt; while (src_sz >= 8) { uint64_t mi; memcpy(&mi, in, sizeof(mi)); mi = _le64toh(mi); in += sizeof(mi); src_sz -= sizeof(mi); v3 ^= mi; DOUBLE_ROUND(v0,v1,v2,v3); v0 ^= mi; } t = 0; pt = (uint8_t *)&t; switch (src_sz) { case 7: pt[6] = in[6]; /* fall through */ case 6: pt[5] = in[5]; /* fall through */ case 5: pt[4] = in[4]; /* fall through */ case 4: memcpy(pt, in, sizeof(uint32_t)); break; case 3: pt[2] = in[2]; /* fall through */ case 2: pt[1] = in[1]; /* fall through */ case 1: pt[0] = in[0]; /* fall through */ } b |= _le64toh(t); v3 ^= b; DOUBLE_ROUND(v0,v1,v2,v3); v0 ^= b; v2 ^= 0xff; DOUBLE_ROUND(v0,v1,v2,v3); DOUBLE_ROUND(v0,v1,v2,v3); /* modified */ t = (v0 ^ v1) ^ (v2 ^ v3); return t; } #endif uint64_t _Py_KeyedHash(uint64_t key, const void *src, Py_ssize_t src_sz) { return siphash13(key, 0, src, src_sz); } #if Py_HASH_ALGORITHM == Py_HASH_SIPHASH13 static Py_hash_t pysiphash(const void *src, Py_ssize_t src_sz) { return (Py_hash_t)siphash13( _le64toh(_Py_HashSecret.siphash.k0), _le64toh(_Py_HashSecret.siphash.k1), src, src_sz); } static PyHash_FuncDef PyHash_Func = {pysiphash, "siphash13", 64, 128}; #endif #if Py_HASH_ALGORITHM == Py_HASH_SIPHASH24 static Py_hash_t pysiphash(const void *src, Py_ssize_t src_sz) { return (Py_hash_t)siphash24( _le64toh(_Py_HashSecret.siphash.k0), _le64toh(_Py_HashSecret.siphash.k1), src, src_sz); } static PyHash_FuncDef PyHash_Func = {pysiphash, "siphash24", 64, 128}; #endif #ifdef __cplusplus } #endif ================================================ FILE: PyLifeCycle.c ================================================ /* Python interpreter top-level routines, including init/exit */ #include "Python.h" #include "pycore_ceval.h" // _PyEval_FiniGIL() #include "pycore_context.h" // _PyContext_Init() #include "pycore_exceptions.h" // _PyExc_InitTypes() #include "pycore_dict.h" // _PyDict_Fini() #include "pycore_fileutils.h" // _Py_ResetForceASCII() #include "pycore_floatobject.h" // _PyFloat_InitTypes() #include "pycore_genobject.h" // _PyAsyncGen_Fini() #include "pycore_global_objects_fini_generated.h" // "_PyStaticObjects_CheckRefcnt() #include "pycore_import.h" // _PyImport_BootstrapImp() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_list.h" // _PyList_Fini() #include "pycore_long.h" // _PyLong_InitTypes() #include "pycore_object.h" // _PyDebug_PrintTotalRefs() #include "pycore_pathconfig.h" // _PyConfig_WritePathConfig() #include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pylifecycle.h" // _PyErr_Print() #include "pycore_pymem.h" // _PyObject_DebugMallocStats() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_runtime.h" // _Py_ID() #include "pycore_runtime_init.h" // _PyRuntimeState_INIT #include "pycore_sliceobject.h" // _PySlice_Fini() #include "pycore_sysmodule.h" // _PySys_ClearAuditHooks() #include "pycore_traceback.h" // _Py_DumpTracebackThreads() #include "pycore_typeobject.h" // _PyTypes_InitTypes() #include "pycore_typevarobject.h" // _Py_clear_generic_types() #include "pycore_unicodeobject.h" // _PyUnicode_InitTypes() #include "opcode.h" #include // setlocale() #include // getenv() #if defined(__APPLE__) #include #endif #ifdef HAVE_SIGNAL_H # include // SIG_IGN #endif #ifdef HAVE_LANGINFO_H # include // nl_langinfo(CODESET) #endif #ifdef HAVE_FCNTL_H # include // F_GETFD #endif #ifdef MS_WINDOWS # undef BYTE #endif #define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str)) #ifdef __cplusplus extern "C" { #endif /* Forward declarations */ static PyStatus add_main_module(PyInterpreterState *interp); static PyStatus init_import_site(void); static PyStatus init_set_builtins_open(void); static PyStatus init_sys_streams(PyThreadState *tstate); static void wait_for_thread_shutdown(PyThreadState *tstate); static void call_ll_exitfuncs(_PyRuntimeState *runtime); /* The following places the `_PyRuntime` structure in a location that can be * found without any external information. This is meant to ease access to the * interpreter state for various runtime debugging tools, but is *not* an * officially supported feature */ /* Suppress deprecation warning for PyBytesObject.ob_shash */ _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS #if defined(MS_WINDOWS) #pragma section("PyRuntime", read, write) __declspec(allocate("PyRuntime")) #elif defined(__APPLE__) __attribute__(( section(SEG_DATA ",PyRuntime") )) #endif _PyRuntimeState _PyRuntime #if defined(__linux__) && (defined(__GNUC__) || defined(__clang__)) __attribute__ ((section (".PyRuntime"))) #endif = _PyRuntimeState_INIT(_PyRuntime); _Py_COMP_DIAG_POP static int runtime_initialized = 0; PyStatus _PyRuntime_Initialize(void) { /* XXX We only initialize once in the process, which aligns with the static initialization of the former globals now found in _PyRuntime. However, _PyRuntime *should* be initialized with every Py_Initialize() call, but doing so breaks the runtime. This is because the runtime state is not properly finalized currently. */ if (runtime_initialized) { return _PyStatus_OK(); } runtime_initialized = 1; return _PyRuntimeState_Init(&_PyRuntime); } void _PyRuntime_Finalize(void) { _PyRuntimeState_Fini(&_PyRuntime); runtime_initialized = 0; } int _Py_IsFinalizing(void) { return _PyRuntimeState_GetFinalizing(&_PyRuntime) != NULL; } /* Hack to force loading of object files */ int (*_PyOS_mystrnicmp_hack)(const char *, const char *, Py_ssize_t) = \ PyOS_mystrnicmp; /* Python/pystrcmp.o */ /* APIs to access the initialization flags * * Can be called prior to Py_Initialize. */ int _Py_IsCoreInitialized(void) { return _PyRuntime.core_initialized; } int Py_IsInitialized(void) { return _PyRuntime.initialized; } /* Helper functions to better handle the legacy C locale * * The legacy C locale assumes ASCII as the default text encoding, which * causes problems not only for the CPython runtime, but also other * components like GNU readline. * * Accordingly, when the CLI detects it, it attempts to coerce it to a * more capable UTF-8 based alternative as follows: * * if (_Py_LegacyLocaleDetected()) { * _Py_CoerceLegacyLocale(); * } * * See the documentation of the PYTHONCOERCECLOCALE setting for more details. * * Locale coercion also impacts the default error handler for the standard * streams: while the usual default is "strict", the default for the legacy * C locale and for any of the coercion target locales is "surrogateescape". */ int _Py_LegacyLocaleDetected(int warn) { #ifndef MS_WINDOWS if (!warn) { const char *locale_override = getenv("LC_ALL"); if (locale_override != NULL && *locale_override != '\0') { /* Don't coerce C locale if the LC_ALL environment variable is set */ return 0; } } /* On non-Windows systems, the C locale is considered a legacy locale */ /* XXX (ncoghlan): some platforms (notably Mac OS X) don't appear to treat * the POSIX locale as a simple alias for the C locale, so * we may also want to check for that explicitly. */ const char *ctype_loc = setlocale(LC_CTYPE, NULL); return ctype_loc != NULL && strcmp(ctype_loc, "C") == 0; #else /* Windows uses code pages instead of locales, so no locale is legacy */ return 0; #endif } #ifndef MS_WINDOWS static const char *_C_LOCALE_WARNING = "Python runtime initialized with LC_CTYPE=C (a locale with default ASCII " "encoding), which may cause Unicode compatibility problems. Using C.UTF-8, " "C.utf8, or UTF-8 (if available) as alternative Unicode-compatible " "locales is recommended.\n"; static void emit_stderr_warning_for_legacy_locale(_PyRuntimeState *runtime) { const PyPreConfig *preconfig = &runtime->preconfig; if (preconfig->coerce_c_locale_warn && _Py_LegacyLocaleDetected(1)) { PySys_FormatStderr("%s", _C_LOCALE_WARNING); } } #endif /* !defined(MS_WINDOWS) */ typedef struct _CandidateLocale { const char *locale_name; /* The locale to try as a coercion target */ } _LocaleCoercionTarget; static _LocaleCoercionTarget _TARGET_LOCALES[] = { {"C.UTF-8"}, {"C.utf8"}, {"UTF-8"}, {NULL} }; int _Py_IsLocaleCoercionTarget(const char *ctype_loc) { const _LocaleCoercionTarget *target = NULL; for (target = _TARGET_LOCALES; target->locale_name; target++) { if (strcmp(ctype_loc, target->locale_name) == 0) { return 1; } } return 0; } #ifdef PY_COERCE_C_LOCALE static const char C_LOCALE_COERCION_WARNING[] = "Python detected LC_CTYPE=C: LC_CTYPE coerced to %.20s (set another locale " "or PYTHONCOERCECLOCALE=0 to disable this locale coercion behavior).\n"; static int _coerce_default_locale_settings(int warn, const _LocaleCoercionTarget *target) { const char *newloc = target->locale_name; /* Reset locale back to currently configured defaults */ _Py_SetLocaleFromEnv(LC_ALL); /* Set the relevant locale environment variable */ if (setenv("LC_CTYPE", newloc, 1)) { fprintf(stderr, "Error setting LC_CTYPE, skipping C locale coercion\n"); return 0; } if (warn) { fprintf(stderr, C_LOCALE_COERCION_WARNING, newloc); } /* Reconfigure with the overridden environment variables */ _Py_SetLocaleFromEnv(LC_ALL); return 1; } #endif int _Py_CoerceLegacyLocale(int warn) { int coerced = 0; #ifdef PY_COERCE_C_LOCALE char *oldloc = NULL; oldloc = _PyMem_RawStrdup(setlocale(LC_CTYPE, NULL)); if (oldloc == NULL) { return coerced; } const char *locale_override = getenv("LC_ALL"); if (locale_override == NULL || *locale_override == '\0') { /* LC_ALL is also not set (or is set to an empty string) */ const _LocaleCoercionTarget *target = NULL; for (target = _TARGET_LOCALES; target->locale_name; target++) { const char *new_locale = setlocale(LC_CTYPE, target->locale_name); if (new_locale != NULL) { #if !defined(_Py_FORCE_UTF8_LOCALE) && defined(HAVE_LANGINFO_H) && defined(CODESET) /* Also ensure that nl_langinfo works in this locale */ char *codeset = nl_langinfo(CODESET); if (!codeset || *codeset == '\0') { /* CODESET is not set or empty, so skip coercion */ new_locale = NULL; _Py_SetLocaleFromEnv(LC_CTYPE); continue; } #endif /* Successfully configured locale, so make it the default */ coerced = _coerce_default_locale_settings(warn, target); goto done; } } } /* No C locale warning here, as Py_Initialize will emit one later */ setlocale(LC_CTYPE, oldloc); done: PyMem_RawFree(oldloc); #endif return coerced; } /* _Py_SetLocaleFromEnv() is a wrapper around setlocale(category, "") to * isolate the idiosyncrasies of different libc implementations. It reads the * appropriate environment variable and uses its value to select the locale for * 'category'. */ char * _Py_SetLocaleFromEnv(int category) { char *res; #ifdef __ANDROID__ const char *locale; const char **pvar; #ifdef PY_COERCE_C_LOCALE const char *coerce_c_locale; #endif const char *utf8_locale = "C.UTF-8"; const char *env_var_set[] = { "LC_ALL", "LC_CTYPE", "LANG", NULL, }; /* Android setlocale(category, "") doesn't check the environment variables * and incorrectly sets the "C" locale at API 24 and older APIs. We only * check the environment variables listed in env_var_set. */ for (pvar=env_var_set; *pvar; pvar++) { locale = getenv(*pvar); if (locale != NULL && *locale != '\0') { if (strcmp(locale, utf8_locale) == 0 || strcmp(locale, "en_US.UTF-8") == 0) { return setlocale(category, utf8_locale); } return setlocale(category, "C"); } } /* Android uses UTF-8, so explicitly set the locale to C.UTF-8 if none of * LC_ALL, LC_CTYPE, or LANG is set to a non-empty string. * Quote from POSIX section "8.2 Internationalization Variables": * "4. If the LANG environment variable is not set or is set to the empty * string, the implementation-defined default locale shall be used." */ #ifdef PY_COERCE_C_LOCALE coerce_c_locale = getenv("PYTHONCOERCECLOCALE"); if (coerce_c_locale == NULL || strcmp(coerce_c_locale, "0") != 0) { /* Some other ported code may check the environment variables (e.g. in * extension modules), so we make sure that they match the locale * configuration */ if (setenv("LC_CTYPE", utf8_locale, 1)) { fprintf(stderr, "Warning: failed setting the LC_CTYPE " "environment variable to %s\n", utf8_locale); } } #endif res = setlocale(category, utf8_locale); #else /* !defined(__ANDROID__) */ res = setlocale(category, ""); #endif _Py_ResetForceASCII(); return res; } static int interpreter_update_config(PyThreadState *tstate, int only_update_path_config) { const PyConfig *config = &tstate->interp->config; if (!only_update_path_config) { PyStatus status = _PyConfig_Write(config, tstate->interp->runtime); if (_PyStatus_EXCEPTION(status)) { _PyErr_SetFromPyStatus(status); return -1; } } if (_Py_IsMainInterpreter(tstate->interp)) { PyStatus status = _PyPathConfig_UpdateGlobal(config); if (_PyStatus_EXCEPTION(status)) { _PyErr_SetFromPyStatus(status); return -1; } } tstate->interp->long_state.max_str_digits = config->int_max_str_digits; // Update the sys module for the new configuration if (_PySys_UpdateConfig(tstate) < 0) { return -1; } return 0; } int _PyInterpreterState_SetConfig(const PyConfig *src_config) { PyThreadState *tstate = _PyThreadState_GET(); int res = -1; PyConfig config; PyConfig_InitPythonConfig(&config); PyStatus status = _PyConfig_Copy(&config, src_config); if (_PyStatus_EXCEPTION(status)) { _PyErr_SetFromPyStatus(status); goto done; } status = _PyConfig_Read(&config, 1); if (_PyStatus_EXCEPTION(status)) { _PyErr_SetFromPyStatus(status); goto done; } status = _PyConfig_Copy(&tstate->interp->config, &config); if (_PyStatus_EXCEPTION(status)) { _PyErr_SetFromPyStatus(status); goto done; } res = interpreter_update_config(tstate, 0); done: PyConfig_Clear(&config); return res; } /* Global initializations. Can be undone by Py_Finalize(). Don't call this twice without an intervening Py_Finalize() call. Every call to Py_InitializeFromConfig, Py_Initialize or Py_InitializeEx must have a corresponding call to Py_Finalize. Locking: you must hold the interpreter lock while calling these APIs. (If the lock has not yet been initialized, that's equivalent to having the lock, but you cannot use multiple threads.) */ static PyStatus pyinit_core_reconfigure(_PyRuntimeState *runtime, PyThreadState **tstate_p, const PyConfig *config) { PyStatus status; PyThreadState *tstate = _PyThreadState_GET(); if (!tstate) { return _PyStatus_ERR("failed to read thread state"); } *tstate_p = tstate; PyInterpreterState *interp = tstate->interp; if (interp == NULL) { return _PyStatus_ERR("can't make main interpreter"); } status = _PyConfig_Write(config, runtime); if (_PyStatus_EXCEPTION(status)) { return status; } status = _PyConfig_Copy(&interp->config, config); if (_PyStatus_EXCEPTION(status)) { return status; } config = _PyInterpreterState_GetConfig(interp); if (config->_install_importlib) { status = _PyPathConfig_UpdateGlobal(config); if (_PyStatus_EXCEPTION(status)) { return status; } } return _PyStatus_OK(); } static PyStatus pycore_init_runtime(_PyRuntimeState *runtime, const PyConfig *config) { if (runtime->initialized) { return _PyStatus_ERR("main interpreter already initialized"); } PyStatus status = _PyConfig_Write(config, runtime); if (_PyStatus_EXCEPTION(status)) { return status; } /* Py_Finalize leaves _Py_Finalizing set in order to help daemon * threads behave a little more gracefully at interpreter shutdown. * We clobber it here so the new interpreter can start with a clean * slate. * * However, this may still lead to misbehaviour if there are daemon * threads still hanging around from a previous Py_Initialize/Finalize * pair :( */ _PyRuntimeState_SetFinalizing(runtime, NULL); _Py_InitVersion(); status = _Py_HashRandomization_Init(config); if (_PyStatus_EXCEPTION(status)) { return status; } status = _PyTime_Init(); if (_PyStatus_EXCEPTION(status)) { return status; } status = _PyImport_Init(); if (_PyStatus_EXCEPTION(status)) { return status; } status = _PyInterpreterState_Enable(runtime); if (_PyStatus_EXCEPTION(status)) { return status; } return _PyStatus_OK(); } static PyStatus init_interp_settings(PyInterpreterState *interp, const PyInterpreterConfig *config) { assert(interp->feature_flags == 0); if (config->use_main_obmalloc) { interp->feature_flags |= Py_RTFLAGS_USE_MAIN_OBMALLOC; } else if (!config->check_multi_interp_extensions) { /* The reason: PyModuleDef.m_base.m_copy leaks objects between interpreters. */ return _PyStatus_ERR("per-interpreter obmalloc does not support " "single-phase init extension modules"); } if (config->allow_fork) { interp->feature_flags |= Py_RTFLAGS_FORK; } if (config->allow_exec) { interp->feature_flags |= Py_RTFLAGS_EXEC; } // Note that fork+exec is always allowed. if (config->allow_threads) { interp->feature_flags |= Py_RTFLAGS_THREADS; } if (config->allow_daemon_threads) { interp->feature_flags |= Py_RTFLAGS_DAEMON_THREADS; } if (config->check_multi_interp_extensions) { interp->feature_flags |= Py_RTFLAGS_MULTI_INTERP_EXTENSIONS; } return _PyStatus_OK(); } static PyStatus init_interp_create_gil(PyThreadState *tstate, int own_gil) { PyStatus status; /* finalize_interp_delete() comment explains why _PyEval_FiniGIL() is only called here. */ // XXX This is broken with a per-interpreter GIL. _PyEval_FiniGIL(tstate->interp); /* Auto-thread-state API */ status = _PyGILState_SetTstate(tstate); if (_PyStatus_EXCEPTION(status)) { return status; } /* Create the GIL and take it */ status = _PyEval_InitGIL(tstate, own_gil); if (_PyStatus_EXCEPTION(status)) { return status; } return _PyStatus_OK(); } static PyStatus pycore_create_interpreter(_PyRuntimeState *runtime, const PyConfig *src_config, PyThreadState **tstate_p) { PyStatus status; PyInterpreterState *interp = PyInterpreterState_New(); if (interp == NULL) { return _PyStatus_ERR("can't make main interpreter"); } assert(_Py_IsMainInterpreter(interp)); status = _PyConfig_Copy(&interp->config, src_config); if (_PyStatus_EXCEPTION(status)) { return status; } /* Auto-thread-state API */ status = _PyGILState_Init(interp); if (_PyStatus_EXCEPTION(status)) { return status; } PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; // The main interpreter always has its own GIL. config.own_gil = 1; status = init_interp_settings(interp, &config); if (_PyStatus_EXCEPTION(status)) { return status; } PyThreadState *tstate = _PyThreadState_New(interp); if (tstate == NULL) { return _PyStatus_ERR("can't make first thread"); } _PyThreadState_Bind(tstate); // XXX For now we do this before the GIL is created. (void) _PyThreadState_SwapNoGIL(tstate); status = init_interp_create_gil(tstate, config.own_gil); if (_PyStatus_EXCEPTION(status)) { return status; } *tstate_p = tstate; return _PyStatus_OK(); } static PyStatus pycore_init_global_objects(PyInterpreterState *interp) { PyStatus status; _PyFloat_InitState(interp); status = _PyUnicode_InitGlobalObjects(interp); if (_PyStatus_EXCEPTION(status)) { return status; } _PyUnicode_InitState(interp); return _PyStatus_OK(); } static PyStatus pycore_init_types(PyInterpreterState *interp) { PyStatus status; status = _PyTypes_InitTypes(interp); if (_PyStatus_EXCEPTION(status)) { return status; } status = _PyLong_InitTypes(interp); if (_PyStatus_EXCEPTION(status)) { return status; } status = _PyUnicode_InitTypes(interp); if (_PyStatus_EXCEPTION(status)) { return status; } status = _PyFloat_InitTypes(interp); if (_PyStatus_EXCEPTION(status)) { return status; } if (_PyExc_InitTypes(interp) < 0) { return _PyStatus_ERR("failed to initialize an exception type"); } status = _PyExc_InitGlobalObjects(interp); if (_PyStatus_EXCEPTION(status)) { return status; } status = _PyExc_InitState(interp); if (_PyStatus_EXCEPTION(status)) { return status; } status = _PyErr_InitTypes(interp); if (_PyStatus_EXCEPTION(status)) { return status; } status = _PyContext_Init(interp); if (_PyStatus_EXCEPTION(status)) { return status; } return _PyStatus_OK(); } static const uint8_t INTERPRETER_TRAMPOLINE_INSTRUCTIONS[] = { /* Put a NOP at the start, so that the IP points into * the code, rather than before it */ NOP, 0, INTERPRETER_EXIT, 0, /* RESUME at end makes sure that the frame appears incomplete */ RESUME, 0 }; static const _PyShimCodeDef INTERPRETER_TRAMPOLINE_CODEDEF = { INTERPRETER_TRAMPOLINE_INSTRUCTIONS, sizeof(INTERPRETER_TRAMPOLINE_INSTRUCTIONS), 1, "" }; static PyStatus pycore_init_builtins(PyThreadState *tstate) { PyInterpreterState *interp = tstate->interp; PyObject *bimod = _PyBuiltin_Init(interp); if (bimod == NULL) { goto error; } PyObject *modules = _PyImport_GetModules(interp); if (_PyImport_FixupBuiltin(bimod, "builtins", modules) < 0) { goto error; } PyObject *builtins_dict = PyModule_GetDict(bimod); if (builtins_dict == NULL) { goto error; } interp->builtins = Py_NewRef(builtins_dict); PyObject *isinstance = PyDict_GetItem(builtins_dict, &_Py_ID(isinstance)); assert(isinstance); interp->callable_cache.isinstance = isinstance; PyObject *len = PyDict_GetItem(builtins_dict, &_Py_ID(len)); assert(len); interp->callable_cache.len = len; PyObject *list_append = _PyType_Lookup(&PyList_Type, &_Py_ID(append)); assert(list_append); interp->callable_cache.list_append = list_append; PyObject *object__getattribute__ = _PyType_Lookup(&PyBaseObject_Type, &_Py_ID(__getattribute__)); assert(object__getattribute__); interp->callable_cache.object__getattribute__ = object__getattribute__; interp->interpreter_trampoline = _Py_MakeShimCode(&INTERPRETER_TRAMPOLINE_CODEDEF); if (interp->interpreter_trampoline == NULL) { return _PyStatus_ERR("failed to create interpreter trampoline."); } if (_PyBuiltins_AddExceptions(bimod) < 0) { return _PyStatus_ERR("failed to add exceptions to builtins"); } interp->builtins_copy = PyDict_Copy(interp->builtins); if (interp->builtins_copy == NULL) { goto error; } Py_DECREF(bimod); if (_PyImport_InitDefaultImportFunc(interp) < 0) { goto error; } assert(!_PyErr_Occurred(tstate)); return _PyStatus_OK(); error: Py_XDECREF(bimod); return _PyStatus_ERR("can't initialize builtins module"); } static PyStatus pycore_interp_init(PyThreadState *tstate) { PyInterpreterState *interp = tstate->interp; PyStatus status; PyObject *sysmod = NULL; // Create singletons before the first PyType_Ready() call, since // PyType_Ready() uses singletons like the Unicode empty string (tp_doc) // and the empty tuple singletons (tp_bases). status = pycore_init_global_objects(interp); if (_PyStatus_EXCEPTION(status)) { return status; } // The GC must be initialized before the first GC collection. status = _PyGC_Init(interp); if (_PyStatus_EXCEPTION(status)) { return status; } // Intern strings in deep-frozen modules first so that others // can use it instead of creating a heap allocated string. if (_Py_Deepfreeze_Init() < 0) { return _PyStatus_ERR("failed to initialize deep-frozen modules"); } status = pycore_init_types(interp); if (_PyStatus_EXCEPTION(status)) { goto done; } if (_PyWarnings_InitState(interp) < 0) { return _PyStatus_ERR("can't initialize warnings"); } status = _PyAtExit_Init(interp); if (_PyStatus_EXCEPTION(status)) { return status; } status = _PySys_Create(tstate, &sysmod); if (_PyStatus_EXCEPTION(status)) { goto done; } status = pycore_init_builtins(tstate); if (_PyStatus_EXCEPTION(status)) { goto done; } const PyConfig *config = _PyInterpreterState_GetConfig(interp); status = _PyImport_InitCore(tstate, sysmod, config->_install_importlib); if (_PyStatus_EXCEPTION(status)) { goto done; } done: /* sys.modules['sys'] contains a strong reference to the module */ Py_XDECREF(sysmod); return status; } static PyStatus pyinit_config(_PyRuntimeState *runtime, PyThreadState **tstate_p, const PyConfig *config) { PyStatus status = pycore_init_runtime(runtime, config); if (_PyStatus_EXCEPTION(status)) { return status; } PyThreadState *tstate; status = pycore_create_interpreter(runtime, config, &tstate); if (_PyStatus_EXCEPTION(status)) { return status; } *tstate_p = tstate; status = pycore_interp_init(tstate); if (_PyStatus_EXCEPTION(status)) { return status; } /* Only when we get here is the runtime core fully initialized */ runtime->core_initialized = 1; return _PyStatus_OK(); } PyStatus _Py_PreInitializeFromPyArgv(const PyPreConfig *src_config, const _PyArgv *args) { PyStatus status; if (src_config == NULL) { return _PyStatus_ERR("preinitialization config is NULL"); } status = _PyRuntime_Initialize(); if (_PyStatus_EXCEPTION(status)) { return status; } _PyRuntimeState *runtime = &_PyRuntime; if (runtime->preinitialized) { /* If it's already configured: ignored the new configuration */ return _PyStatus_OK(); } /* Note: preinitialized remains 1 on error, it is only set to 0 at exit on success. */ runtime->preinitializing = 1; PyPreConfig config; status = _PyPreConfig_InitFromPreConfig(&config, src_config); if (_PyStatus_EXCEPTION(status)) { return status; } status = _PyPreConfig_Read(&config, args); if (_PyStatus_EXCEPTION(status)) { return status; } status = _PyPreConfig_Write(&config); if (_PyStatus_EXCEPTION(status)) { return status; } runtime->preinitializing = 0; runtime->preinitialized = 1; return _PyStatus_OK(); } PyStatus Py_PreInitializeFromBytesArgs(const PyPreConfig *src_config, Py_ssize_t argc, char **argv) { _PyArgv args = {.use_bytes_argv = 1, .argc = argc, .bytes_argv = argv}; return _Py_PreInitializeFromPyArgv(src_config, &args); } PyStatus Py_PreInitializeFromArgs(const PyPreConfig *src_config, Py_ssize_t argc, wchar_t **argv) { _PyArgv args = {.use_bytes_argv = 0, .argc = argc, .wchar_argv = argv}; return _Py_PreInitializeFromPyArgv(src_config, &args); } PyStatus Py_PreInitialize(const PyPreConfig *src_config) { return _Py_PreInitializeFromPyArgv(src_config, NULL); } PyStatus _Py_PreInitializeFromConfig(const PyConfig *config, const _PyArgv *args) { assert(config != NULL); PyStatus status = _PyRuntime_Initialize(); if (_PyStatus_EXCEPTION(status)) { return status; } _PyRuntimeState *runtime = &_PyRuntime; if (runtime->preinitialized) { /* Already initialized: do nothing */ return _PyStatus_OK(); } PyPreConfig preconfig; _PyPreConfig_InitFromConfig(&preconfig, config); if (!config->parse_argv) { return Py_PreInitialize(&preconfig); } else if (args == NULL) { _PyArgv config_args = { .use_bytes_argv = 0, .argc = config->argv.length, .wchar_argv = config->argv.items}; return _Py_PreInitializeFromPyArgv(&preconfig, &config_args); } else { return _Py_PreInitializeFromPyArgv(&preconfig, args); } } /* Begin interpreter initialization * * On return, the first thread and interpreter state have been created, * but the compiler, signal handling, multithreading and * multiple interpreter support, and codec infrastructure are not yet * available. * * The import system will support builtin and frozen modules only. * The only supported io is writing to sys.stderr * * If any operation invoked by this function fails, a fatal error is * issued and the function does not return. * * Any code invoked from this function should *not* assume it has access * to the Python C API (unless the API is explicitly listed as being * safe to call without calling Py_Initialize first) */ static PyStatus pyinit_core(_PyRuntimeState *runtime, const PyConfig *src_config, PyThreadState **tstate_p) { PyStatus status; status = _Py_PreInitializeFromConfig(src_config, NULL); if (_PyStatus_EXCEPTION(status)) { return status; } PyConfig config; PyConfig_InitPythonConfig(&config); status = _PyConfig_Copy(&config, src_config); if (_PyStatus_EXCEPTION(status)) { goto done; } // Read the configuration, but don't compute the path configuration // (it is computed in the main init). status = _PyConfig_Read(&config, 0); if (_PyStatus_EXCEPTION(status)) { goto done; } if (!runtime->core_initialized) { status = pyinit_config(runtime, tstate_p, &config); } else { status = pyinit_core_reconfigure(runtime, tstate_p, &config); } if (_PyStatus_EXCEPTION(status)) { goto done; } done: PyConfig_Clear(&config); return status; } /* Py_Initialize() has already been called: update the main interpreter configuration. Example of bpo-34008: Py_Main() called after Py_Initialize(). */ static PyStatus pyinit_main_reconfigure(PyThreadState *tstate) { if (interpreter_update_config(tstate, 0) < 0) { return _PyStatus_ERR("fail to reconfigure Python"); } return _PyStatus_OK(); } static PyStatus init_interp_main(PyThreadState *tstate) { assert(!_PyErr_Occurred(tstate)); PyStatus status; int is_main_interp = _Py_IsMainInterpreter(tstate->interp); PyInterpreterState *interp = tstate->interp; const PyConfig *config = _PyInterpreterState_GetConfig(interp); if (!config->_install_importlib) { /* Special mode for freeze_importlib: run with no import system * * This means anything which needs support from extension modules * or pure Python code in the standard library won't work. */ if (is_main_interp) { interp->runtime->initialized = 1; } return _PyStatus_OK(); } // Initialize the import-related configuration. status = _PyConfig_InitImportConfig(&interp->config); if (_PyStatus_EXCEPTION(status)) { return status; } if (interpreter_update_config(tstate, 1) < 0) { return _PyStatus_ERR("failed to update the Python config"); } status = _PyImport_InitExternal(tstate); if (_PyStatus_EXCEPTION(status)) { return status; } if (is_main_interp) { /* initialize the faulthandler module */ status = _PyFaulthandler_Init(config->faulthandler); if (_PyStatus_EXCEPTION(status)) { return status; } } status = _PyUnicode_InitEncodings(tstate); if (_PyStatus_EXCEPTION(status)) { return status; } if (is_main_interp) { if (_PySignal_Init(config->install_signal_handlers) < 0) { return _PyStatus_ERR("can't initialize signals"); } if (config->tracemalloc) { if (_PyTraceMalloc_Start(config->tracemalloc) < 0) { return _PyStatus_ERR("can't start tracemalloc"); } } #ifdef PY_HAVE_PERF_TRAMPOLINE if (config->perf_profiling) { if (_PyPerfTrampoline_SetCallbacks(&_Py_perfmap_callbacks) < 0 || _PyPerfTrampoline_Init(config->perf_profiling) < 0) { return _PyStatus_ERR("can't initialize the perf trampoline"); } } #endif } status = init_sys_streams(tstate); if (_PyStatus_EXCEPTION(status)) { return status; } status = init_set_builtins_open(); if (_PyStatus_EXCEPTION(status)) { return status; } status = add_main_module(interp); if (_PyStatus_EXCEPTION(status)) { return status; } if (is_main_interp) { /* Initialize warnings. */ PyObject *warnoptions = PySys_GetObject("warnoptions"); if (warnoptions != NULL && PyList_Size(warnoptions) > 0) { PyObject *warnings_module = PyImport_ImportModule("warnings"); if (warnings_module == NULL) { fprintf(stderr, "'import warnings' failed; traceback:\n"); _PyErr_Print(tstate); } Py_XDECREF(warnings_module); } interp->runtime->initialized = 1; } if (config->site_import) { status = init_import_site(); if (_PyStatus_EXCEPTION(status)) { return status; } } if (is_main_interp) { #ifndef MS_WINDOWS emit_stderr_warning_for_legacy_locale(interp->runtime); #endif } assert(!_PyErr_Occurred(tstate)); return _PyStatus_OK(); } /* Update interpreter state based on supplied configuration settings * * After calling this function, most of the restrictions on the interpreter * are lifted. The only remaining incomplete settings are those related * to the main module (sys.argv[0], __main__ metadata) * * Calling this when the interpreter is not initializing, is already * initialized or without a valid current thread state is a fatal error. * Other errors should be reported as normal Python exceptions with a * non-zero return code. */ static PyStatus pyinit_main(PyThreadState *tstate) { PyInterpreterState *interp = tstate->interp; if (!interp->runtime->core_initialized) { return _PyStatus_ERR("runtime core not initialized"); } if (interp->runtime->initialized) { return pyinit_main_reconfigure(tstate); } PyStatus status = init_interp_main(tstate); if (_PyStatus_EXCEPTION(status)) { return status; } return _PyStatus_OK(); } PyStatus Py_InitializeFromConfig(const PyConfig *config) { if (config == NULL) { return _PyStatus_ERR("initialization config is NULL"); } PyStatus status; status = _PyRuntime_Initialize(); if (_PyStatus_EXCEPTION(status)) { return status; } _PyRuntimeState *runtime = &_PyRuntime; PyThreadState *tstate = NULL; status = pyinit_core(runtime, config, &tstate); if (_PyStatus_EXCEPTION(status)) { return status; } config = _PyInterpreterState_GetConfig(tstate->interp); if (config->_init_main) { status = pyinit_main(tstate); if (_PyStatus_EXCEPTION(status)) { return status; } } return _PyStatus_OK(); } void Py_InitializeEx(int install_sigs) { PyStatus status; status = _PyRuntime_Initialize(); if (_PyStatus_EXCEPTION(status)) { Py_ExitStatusException(status); } _PyRuntimeState *runtime = &_PyRuntime; if (runtime->initialized) { /* bpo-33932: Calling Py_Initialize() twice does nothing. */ return; } PyConfig config; _PyConfig_InitCompatConfig(&config); config.install_signal_handlers = install_sigs; status = Py_InitializeFromConfig(&config); PyConfig_Clear(&config); if (_PyStatus_EXCEPTION(status)) { Py_ExitStatusException(status); } } void Py_Initialize(void) { Py_InitializeEx(1); } PyStatus _Py_InitializeMain(void) { PyStatus status = _PyRuntime_Initialize(); if (_PyStatus_EXCEPTION(status)) { return status; } PyThreadState *tstate = _PyThreadState_GET(); return pyinit_main(tstate); } static void finalize_modules_delete_special(PyThreadState *tstate, int verbose) { // List of names to clear in sys static const char * const sys_deletes[] = { "path", "argv", "ps1", "ps2", "last_exc", "last_type", "last_value", "last_traceback", "__interactivehook__", // path_hooks and path_importer_cache are cleared // by _PyImport_FiniExternal(). // XXX Clear meta_path in _PyImport_FiniCore(). "meta_path", NULL }; static const char * const sys_files[] = { "stdin", "__stdin__", "stdout", "__stdout__", "stderr", "__stderr__", NULL }; PyInterpreterState *interp = tstate->interp; if (verbose) { PySys_WriteStderr("# clear builtins._\n"); } if (PyDict_SetItemString(interp->builtins, "_", Py_None) < 0) { PyErr_WriteUnraisable(NULL); } const char * const *p; for (p = sys_deletes; *p != NULL; p++) { if (_PySys_ClearAttrString(interp, *p, verbose) < 0) { PyErr_WriteUnraisable(NULL); } } for (p = sys_files; *p != NULL; p+=2) { const char *name = p[0]; const char *orig_name = p[1]; if (verbose) { PySys_WriteStderr("# restore sys.%s\n", name); } PyObject *value = _PyDict_GetItemStringWithError(interp->sysdict, orig_name); if (value == NULL) { if (_PyErr_Occurred(tstate)) { PyErr_WriteUnraisable(NULL); } value = Py_None; } if (PyDict_SetItemString(interp->sysdict, name, value) < 0) { PyErr_WriteUnraisable(NULL); } } } static PyObject* finalize_remove_modules(PyObject *modules, int verbose) { PyObject *weaklist = PyList_New(0); if (weaklist == NULL) { PyErr_WriteUnraisable(NULL); } #define STORE_MODULE_WEAKREF(name, mod) \ if (weaklist != NULL) { \ PyObject *wr = PyWeakref_NewRef(mod, NULL); \ if (wr) { \ PyObject *tup = PyTuple_Pack(2, name, wr); \ if (!tup || PyList_Append(weaklist, tup) < 0) { \ PyErr_WriteUnraisable(NULL); \ } \ Py_XDECREF(tup); \ Py_DECREF(wr); \ } \ else { \ PyErr_WriteUnraisable(NULL); \ } \ } #define CLEAR_MODULE(name, mod) \ if (PyModule_Check(mod)) { \ if (verbose && PyUnicode_Check(name)) { \ PySys_FormatStderr("# cleanup[2] removing %U\n", name); \ } \ STORE_MODULE_WEAKREF(name, mod); \ if (PyObject_SetItem(modules, name, Py_None) < 0) { \ PyErr_WriteUnraisable(NULL); \ } \ } if (PyDict_CheckExact(modules)) { Py_ssize_t pos = 0; PyObject *key, *value; while (PyDict_Next(modules, &pos, &key, &value)) { CLEAR_MODULE(key, value); } } else { PyObject *iterator = PyObject_GetIter(modules); if (iterator == NULL) { PyErr_WriteUnraisable(NULL); } else { PyObject *key; while ((key = PyIter_Next(iterator))) { PyObject *value = PyObject_GetItem(modules, key); if (value == NULL) { PyErr_WriteUnraisable(NULL); continue; } CLEAR_MODULE(key, value); Py_DECREF(value); Py_DECREF(key); } if (PyErr_Occurred()) { PyErr_WriteUnraisable(NULL); } Py_DECREF(iterator); } } #undef CLEAR_MODULE #undef STORE_MODULE_WEAKREF return weaklist; } static void finalize_clear_modules_dict(PyObject *modules) { if (PyDict_CheckExact(modules)) { PyDict_Clear(modules); } else { if (PyObject_CallMethodNoArgs(modules, &_Py_ID(clear)) == NULL) { PyErr_WriteUnraisable(NULL); } } } static void finalize_restore_builtins(PyThreadState *tstate) { PyInterpreterState *interp = tstate->interp; PyObject *dict = PyDict_Copy(interp->builtins); if (dict == NULL) { PyErr_WriteUnraisable(NULL); } PyDict_Clear(interp->builtins); if (PyDict_Update(interp->builtins, interp->builtins_copy)) { PyErr_WriteUnraisable(NULL); } Py_XDECREF(dict); } static void finalize_modules_clear_weaklist(PyInterpreterState *interp, PyObject *weaklist, int verbose) { // First clear modules imported later for (Py_ssize_t i = PyList_GET_SIZE(weaklist) - 1; i >= 0; i--) { PyObject *tup = PyList_GET_ITEM(weaklist, i); PyObject *name = PyTuple_GET_ITEM(tup, 0); PyObject *mod = PyWeakref_GET_OBJECT(PyTuple_GET_ITEM(tup, 1)); if (mod == Py_None) { continue; } assert(PyModule_Check(mod)); PyObject *dict = PyModule_GetDict(mod); if (dict == interp->builtins || dict == interp->sysdict) { continue; } Py_INCREF(mod); if (verbose && PyUnicode_Check(name)) { PySys_FormatStderr("# cleanup[3] wiping %U\n", name); } _PyModule_Clear(mod); Py_DECREF(mod); } } static void finalize_clear_sys_builtins_dict(PyInterpreterState *interp, int verbose) { // Clear sys dict if (verbose) { PySys_FormatStderr("# cleanup[3] wiping sys\n"); } _PyModule_ClearDict(interp->sysdict); // Clear builtins dict if (verbose) { PySys_FormatStderr("# cleanup[3] wiping builtins\n"); } _PyModule_ClearDict(interp->builtins); } /* Clear modules, as good as we can */ // XXX Move most of this to import.c. static void finalize_modules(PyThreadState *tstate) { PyInterpreterState *interp = tstate->interp; PyObject *modules = _PyImport_GetModules(interp); if (modules == NULL) { // Already done return; } int verbose = _PyInterpreterState_GetConfig(interp)->verbose; // Delete some special builtins._ and sys attributes first. These are // common places where user values hide and people complain when their // destructors fail. Since the modules containing them are // deleted *last* of all, they would come too late in the normal // destruction order. Sigh. // // XXX Perhaps these precautions are obsolete. Who knows? finalize_modules_delete_special(tstate, verbose); // Remove all modules from sys.modules, hoping that garbage collection // can reclaim most of them: set all sys.modules values to None. // // We prepare a list which will receive (name, weakref) tuples of // modules when they are removed from sys.modules. The name is used // for diagnosis messages (in verbose mode), while the weakref helps // detect those modules which have been held alive. PyObject *weaklist = finalize_remove_modules(modules, verbose); // Clear the modules dict finalize_clear_modules_dict(modules); // Restore the original builtins dict, to ensure that any // user data gets cleared. finalize_restore_builtins(tstate); // Collect garbage _PyGC_CollectNoFail(tstate); // Dump GC stats before it's too late, since it uses the warnings // machinery. _PyGC_DumpShutdownStats(interp); if (weaklist != NULL) { // Now, if there are any modules left alive, clear their globals to // minimize potential leaks. All C extension modules actually end // up here, since they are kept alive in the interpreter state. // // The special treatment of "builtins" here is because even // when it's not referenced as a module, its dictionary is // referenced by almost every module's __builtins__. Since // deleting a module clears its dictionary (even if there are // references left to it), we need to delete the "builtins" // module last. Likewise, we don't delete sys until the very // end because it is implicitly referenced (e.g. by print). // // Since dict is ordered in CPython 3.6+, modules are saved in // importing order. First clear modules imported later. finalize_modules_clear_weaklist(interp, weaklist, verbose); Py_DECREF(weaklist); } // Clear sys and builtins modules dict finalize_clear_sys_builtins_dict(interp, verbose); // Clear module dict copies stored in the interpreter state: // clear PyInterpreterState.modules_by_index and // clear PyModuleDef.m_base.m_copy (of extensions not using the multi-phase // initialization API) _PyImport_ClearModulesByIndex(interp); // Clear and delete the modules directory. Actual modules will // still be there only if imported during the execution of some // destructor. _PyImport_ClearModules(interp); // Collect garbage once more _PyGC_CollectNoFail(tstate); } /* Flush stdout and stderr */ static int file_is_closed(PyObject *fobj) { int r; PyObject *tmp = PyObject_GetAttrString(fobj, "closed"); if (tmp == NULL) { PyErr_Clear(); return 0; } r = PyObject_IsTrue(tmp); Py_DECREF(tmp); if (r < 0) PyErr_Clear(); return r > 0; } static int flush_std_files(void) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *fout = _PySys_GetAttr(tstate, &_Py_ID(stdout)); PyObject *ferr = _PySys_GetAttr(tstate, &_Py_ID(stderr)); PyObject *tmp; int status = 0; if (fout != NULL && fout != Py_None && !file_is_closed(fout)) { tmp = PyObject_CallMethodNoArgs(fout, &_Py_ID(flush)); if (tmp == NULL) { PyErr_WriteUnraisable(fout); status = -1; } else Py_DECREF(tmp); } if (ferr != NULL && ferr != Py_None && !file_is_closed(ferr)) { tmp = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush)); if (tmp == NULL) { PyErr_Clear(); status = -1; } else Py_DECREF(tmp); } return status; } /* Undo the effect of Py_Initialize(). Beware: if multiple interpreter and/or thread states exist, these are not wiped out; only the current thread and interpreter state are deleted. But since everything else is deleted, those other interpreter and thread states should no longer be used. (XXX We should do better, e.g. wipe out all interpreters and threads.) Locking: as above. */ static void finalize_interp_types(PyInterpreterState *interp) { _PyUnicode_FiniTypes(interp); _PySys_FiniTypes(interp); _PyExc_Fini(interp); _PyAsyncGen_Fini(interp); _PyContext_Fini(interp); _PyFloat_FiniType(interp); _PyLong_FiniTypes(interp); _PyThread_FiniType(interp); // XXX fini collections module static types (_PyStaticType_Dealloc()) // XXX fini IO module static types (_PyStaticType_Dealloc()) _PyErr_FiniTypes(interp); _PyTypes_FiniTypes(interp); _PyTypes_Fini(interp); // Call _PyUnicode_ClearInterned() before _PyDict_Fini() since it uses // a dict internally. _PyUnicode_ClearInterned(interp); _PyDict_Fini(interp); _PyList_Fini(interp); _PyTuple_Fini(interp); _PySlice_Fini(interp); _PyUnicode_Fini(interp); _PyFloat_Fini(interp); #ifdef Py_DEBUG _PyStaticObjects_CheckRefcnt(interp); #endif } static void finalize_interp_clear(PyThreadState *tstate) { int is_main_interp = _Py_IsMainInterpreter(tstate->interp); _PyExc_ClearExceptionGroupType(tstate->interp); _Py_clear_generic_types(tstate->interp); /* Clear interpreter state and all thread states */ _PyInterpreterState_Clear(tstate); /* Clear all loghooks */ /* Both _PySys_Audit function and users still need PyObject, such as tuple. Call _PySys_ClearAuditHooks when PyObject available. */ if (is_main_interp) { _PySys_ClearAuditHooks(tstate); } if (is_main_interp) { _Py_HashRandomization_Fini(); _PyArg_Fini(); _Py_ClearFileSystemEncoding(); _Py_Deepfreeze_Fini(); _PyPerfTrampoline_Fini(); } finalize_interp_types(tstate->interp); } static void finalize_interp_delete(PyInterpreterState *interp) { /* Cleanup auto-thread-state */ _PyGILState_Fini(interp); /* We can't call _PyEval_FiniGIL() here because destroying the GIL lock can fail when it is being awaited by another running daemon thread (see bpo-9901). Instead pycore_create_interpreter() destroys the previously created GIL, which ensures that Py_Initialize / Py_FinalizeEx can be called multiple times. */ PyInterpreterState_Delete(interp); } int Py_FinalizeEx(void) { int status = 0; _PyRuntimeState *runtime = &_PyRuntime; if (!runtime->initialized) { return status; } /* Get current thread state and interpreter pointer */ PyThreadState *tstate = _PyThreadState_GET(); // XXX assert(_Py_IsMainInterpreter(tstate->interp)); // XXX assert(_Py_IsMainThread()); // Block some operations. tstate->interp->finalizing = 1; // Wrap up existing "threading"-module-created, non-daemon threads. wait_for_thread_shutdown(tstate); // Make any remaining pending calls. _Py_FinishPendingCalls(tstate); /* The interpreter is still entirely intact at this point, and the * exit funcs may be relying on that. In particular, if some thread * or exit func is still waiting to do an import, the import machinery * expects Py_IsInitialized() to return true. So don't say the * runtime is uninitialized until after the exit funcs have run. * Note that Threading.py uses an exit func to do a join on all the * threads created thru it, so this also protects pending imports in * the threads created via Threading. */ _PyAtExit_Call(tstate->interp); PyUnstable_PerfMapState_Fini(); /* Copy the core config, PyInterpreterState_Delete() free the core config memory */ #ifdef Py_REF_DEBUG int show_ref_count = tstate->interp->config.show_ref_count; #endif #ifdef Py_TRACE_REFS int dump_refs = tstate->interp->config.dump_refs; wchar_t *dump_refs_file = tstate->interp->config.dump_refs_file; #endif #ifdef WITH_PYMALLOC int malloc_stats = tstate->interp->config.malloc_stats; #endif /* Remaining daemon threads will automatically exit when they attempt to take the GIL (ex: PyEval_RestoreThread()). */ _PyInterpreterState_SetFinalizing(tstate->interp, tstate); _PyRuntimeState_SetFinalizing(runtime, tstate); runtime->initialized = 0; runtime->core_initialized = 0; // XXX Call something like _PyImport_Disable() here? /* Destroy the state of all threads of the interpreter, except of the current thread. In practice, only daemon threads should still be alive, except if wait_for_thread_shutdown() has been cancelled by CTRL+C. Clear frames of other threads to call objects destructors. Destructors will be called in the current Python thread. Since _PyRuntimeState_SetFinalizing() has been called, no other Python thread can take the GIL at this point: if they try, they will exit immediately. */ _PyThreadState_DeleteExcept(tstate); /* At this point no Python code should be running at all. The only thread state left should be the main thread of the main interpreter (AKA tstate), in which this code is running right now. There may be other OS threads running but none of them will have thread states associated with them, nor will be able to create new thread states. Thus tstate is the only possible thread state from here on out. It may still be used during finalization to run Python code as needed or provide runtime state (e.g. sys.modules) but that will happen sparingly. Furthermore, the order of finalization aims to not need a thread (or interpreter) state as soon as possible. */ // XXX Make sure we are preventing the creating of any new thread states // (or interpreters). /* Flush sys.stdout and sys.stderr */ if (flush_std_files() < 0) { status = -1; } /* Disable signal handling */ _PySignal_Fini(); /* Collect garbage. This may call finalizers; it's nice to call these * before all modules are destroyed. * XXX If a __del__ or weakref callback is triggered here, and tries to * XXX import a module, bad things can happen, because Python no * XXX longer believes it's initialized. * XXX Fatal Python error: Interpreter not initialized (version mismatch?) * XXX is easy to provoke that way. I've also seen, e.g., * XXX Exception exceptions.ImportError: 'No module named sha' * XXX in ignored * XXX but I'm unclear on exactly how that one happens. In any case, * XXX I haven't seen a real-life report of either of these. */ PyGC_Collect(); /* Destroy all modules */ _PyImport_FiniExternal(tstate->interp); finalize_modules(tstate); /* Print debug stats if any */ _PyEval_Fini(); /* Flush sys.stdout and sys.stderr (again, in case more was printed) */ if (flush_std_files() < 0) { status = -1; } /* Collect final garbage. This disposes of cycles created by * class definitions, for example. * XXX This is disabled because it caused too many problems. If * XXX a __del__ or weakref callback triggers here, Python code has * XXX a hard time running, because even the sys module has been * XXX cleared out (sys.stdout is gone, sys.excepthook is gone, etc). * XXX One symptom is a sequence of information-free messages * XXX coming from threads (if a __del__ or callback is invoked, * XXX other threads can execute too, and any exception they encounter * XXX triggers a comedy of errors as subsystem after subsystem * XXX fails to find what it *expects* to find in sys to help report * XXX the exception and consequent unexpected failures). I've also * XXX seen segfaults then, after adding print statements to the * XXX Python code getting called. */ #if 0 _PyGC_CollectIfEnabled(); #endif /* Disable tracemalloc after all Python objects have been destroyed, so it is possible to use tracemalloc in objects destructor. */ _PyTraceMalloc_Fini(); /* Finalize any remaining import state */ // XXX Move these up to where finalize_modules() is currently. _PyImport_FiniCore(tstate->interp); _PyImport_Fini(); /* unload faulthandler module */ _PyFaulthandler_Fini(); /* dump hash stats */ _PyHash_Fini(); #ifdef Py_TRACE_REFS /* Display all objects still alive -- this can invoke arbitrary * __repr__ overrides, so requires a mostly-intact interpreter. * Alas, a lot of stuff may still be alive now that will be cleaned * up later. */ FILE *dump_refs_fp = NULL; if (dump_refs_file != NULL) { dump_refs_fp = _Py_wfopen(dump_refs_file, L"w"); if (dump_refs_fp == NULL) { fprintf(stderr, "PYTHONDUMPREFSFILE: cannot create file: %ls\n", dump_refs_file); } } if (dump_refs) { _Py_PrintReferences(stderr); } if (dump_refs_fp != NULL) { _Py_PrintReferences(dump_refs_fp); } #endif /* Py_TRACE_REFS */ /* At this point there's almost no other Python code that will run, nor interpreter state needed. The only possibility is the finalizers of the objects stored on tstate (and tstate->interp), which are triggered via finalize_interp_clear(). For now we operate as though none of those finalizers actually need an operational thread state or interpreter. In reality, those finalizers may rely on some part of tstate or tstate->interp, and/or may raise exceptions or otherwise fail. */ // XXX Do this sooner during finalization. // XXX Ensure finalizer errors are handled properly. finalize_interp_clear(tstate); finalize_interp_delete(tstate->interp); #ifdef Py_REF_DEBUG if (show_ref_count) { _PyDebug_PrintTotalRefs(); } _Py_FinalizeRefTotal(runtime); #endif _Py_FinalizeAllocatedBlocks(runtime); #ifdef Py_TRACE_REFS /* Display addresses (& refcnts) of all objects still alive. * An address can be used to find the repr of the object, printed * above by _Py_PrintReferences. */ if (dump_refs) { _Py_PrintReferenceAddresses(stderr); } if (dump_refs_fp != NULL) { _Py_PrintReferenceAddresses(dump_refs_fp); fclose(dump_refs_fp); } #endif /* Py_TRACE_REFS */ #ifdef WITH_PYMALLOC if (malloc_stats) { _PyObject_DebugMallocStats(stderr); } #endif call_ll_exitfuncs(runtime); _PyRuntime_Finalize(); return status; } void Py_Finalize(void) { Py_FinalizeEx(); } /* Create and initialize a new interpreter and thread, and return the new thread. This requires that Py_Initialize() has been called first. Unsuccessful initialization yields a NULL pointer. Note that *no* exception information is available even in this case -- the exception information is held in the thread, and there is no thread. Locking: as above. */ static PyStatus new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config) { PyStatus status; status = _PyRuntime_Initialize(); if (_PyStatus_EXCEPTION(status)) { return status; } _PyRuntimeState *runtime = &_PyRuntime; if (!runtime->initialized) { return _PyStatus_ERR("Py_Initialize must be called first"); } /* Issue #10915, #15751: The GIL API doesn't work with multiple interpreters: disable PyGILState_Check(). */ runtime->gilstate.check_enabled = 0; PyInterpreterState *interp = PyInterpreterState_New(); if (interp == NULL) { *tstate_p = NULL; return _PyStatus_OK(); } PyThreadState *tstate = _PyThreadState_New(interp); if (tstate == NULL) { PyInterpreterState_Delete(interp); *tstate_p = NULL; return _PyStatus_OK(); } _PyThreadState_Bind(tstate); // XXX For now we do this before the GIL is created. PyThreadState *save_tstate = _PyThreadState_SwapNoGIL(tstate); int has_gil = 0; /* From this point until the init_interp_create_gil() call, we must not do anything that requires that the GIL be held (or otherwise exist). That applies whether or not the new interpreter has its own GIL (e.g. the main interpreter). */ /* Copy the current interpreter config into the new interpreter */ const PyConfig *src_config; if (save_tstate != NULL) { // XXX Might new_interpreter() have been called without the GIL held? _PyEval_ReleaseLock(save_tstate); src_config = _PyInterpreterState_GetConfig(save_tstate->interp); } else { /* No current thread state, copy from the main interpreter */ PyInterpreterState *main_interp = _PyInterpreterState_Main(); src_config = _PyInterpreterState_GetConfig(main_interp); } /* This does not require that the GIL be held. */ status = _PyConfig_Copy(&interp->config, src_config); if (_PyStatus_EXCEPTION(status)) { goto error; } /* This does not require that the GIL be held. */ status = init_interp_settings(interp, config); if (_PyStatus_EXCEPTION(status)) { goto error; } status = init_interp_create_gil(tstate, config->own_gil); if (_PyStatus_EXCEPTION(status)) { goto error; } has_gil = 1; status = pycore_interp_init(tstate); if (_PyStatus_EXCEPTION(status)) { goto error; } status = init_interp_main(tstate); if (_PyStatus_EXCEPTION(status)) { goto error; } *tstate_p = tstate; return _PyStatus_OK(); error: *tstate_p = NULL; /* Oops, it didn't work. Undo it all. */ PyErr_PrintEx(0); if (has_gil) { PyThreadState_Swap(save_tstate); } else { _PyThreadState_SwapNoGIL(save_tstate); } PyThreadState_Clear(tstate); PyThreadState_Delete(tstate); PyInterpreterState_Delete(interp); return status; } PyStatus Py_NewInterpreterFromConfig(PyThreadState **tstate_p, const PyInterpreterConfig *config) { return new_interpreter(tstate_p, config); } PyThreadState * Py_NewInterpreter(void) { PyThreadState *tstate = NULL; const PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; PyStatus status = new_interpreter(&tstate, &config); if (_PyStatus_EXCEPTION(status)) { Py_ExitStatusException(status); } return tstate; } /* Delete an interpreter and its last thread. This requires that the given thread state is current, that the thread has no remaining frames, and that it is its interpreter's only remaining thread. It is a fatal error to violate these constraints. (Py_FinalizeEx() doesn't have these constraints -- it zaps everything, regardless.) Locking: as above. */ void Py_EndInterpreter(PyThreadState *tstate) { PyInterpreterState *interp = tstate->interp; if (tstate != _PyThreadState_GET()) { Py_FatalError("thread is not current"); } if (tstate->cframe->current_frame != NULL) { Py_FatalError("thread still has a frame"); } interp->finalizing = 1; // Wrap up existing "threading"-module-created, non-daemon threads. wait_for_thread_shutdown(tstate); _PyAtExit_Call(tstate->interp); if (tstate != interp->threads.head || tstate->next != NULL) { Py_FatalError("not the last thread"); } /* Remaining daemon threads will automatically exit when they attempt to take the GIL (ex: PyEval_RestoreThread()). */ _PyInterpreterState_SetFinalizing(interp, tstate); // XXX Call something like _PyImport_Disable() here? _PyImport_FiniExternal(tstate->interp); finalize_modules(tstate); _PyImport_FiniCore(tstate->interp); finalize_interp_clear(tstate); finalize_interp_delete(tstate->interp); } int _Py_IsInterpreterFinalizing(PyInterpreterState *interp) { /* We check the runtime first since, in a daemon thread, interp might be dangling pointer. */ PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(&_PyRuntime); if (finalizing == NULL) { finalizing = _PyInterpreterState_GetFinalizing(interp); } return finalizing != NULL; } /* Add the __main__ module */ static PyStatus add_main_module(PyInterpreterState *interp) { PyObject *m, *d, *loader, *ann_dict; m = PyImport_AddModule("__main__"); if (m == NULL) return _PyStatus_ERR("can't create __main__ module"); d = PyModule_GetDict(m); ann_dict = PyDict_New(); if ((ann_dict == NULL) || (PyDict_SetItemString(d, "__annotations__", ann_dict) < 0)) { return _PyStatus_ERR("Failed to initialize __main__.__annotations__"); } Py_DECREF(ann_dict); if (_PyDict_GetItemStringWithError(d, "__builtins__") == NULL) { if (PyErr_Occurred()) { return _PyStatus_ERR("Failed to test __main__.__builtins__"); } PyObject *bimod = PyImport_ImportModule("builtins"); if (bimod == NULL) { return _PyStatus_ERR("Failed to retrieve builtins module"); } if (PyDict_SetItemString(d, "__builtins__", bimod) < 0) { return _PyStatus_ERR("Failed to initialize __main__.__builtins__"); } Py_DECREF(bimod); } /* Main is a little special - BuiltinImporter is the most appropriate * initial setting for its __loader__ attribute. A more suitable value * will be set if __main__ gets further initialized later in the startup * process. */ loader = _PyDict_GetItemStringWithError(d, "__loader__"); if (loader == NULL || loader == Py_None) { if (PyErr_Occurred()) { return _PyStatus_ERR("Failed to test __main__.__loader__"); } PyObject *loader = _PyImport_GetImportlibLoader(interp, "BuiltinImporter"); if (loader == NULL) { return _PyStatus_ERR("Failed to retrieve BuiltinImporter"); } if (PyDict_SetItemString(d, "__loader__", loader) < 0) { return _PyStatus_ERR("Failed to initialize __main__.__loader__"); } Py_DECREF(loader); } return _PyStatus_OK(); } /* Import the site module (not into __main__ though) */ static PyStatus init_import_site(void) { PyObject *m; m = PyImport_ImportModule("site"); if (m == NULL) { return _PyStatus_ERR("Failed to import the site module"); } Py_DECREF(m); return _PyStatus_OK(); } /* Check if a file descriptor is valid or not. Return 0 if the file descriptor is invalid, return non-zero otherwise. */ static int is_valid_fd(int fd) { /* dup() is faster than fstat(): fstat() can require input/output operations, whereas dup() doesn't. There is a low risk of EMFILE/ENFILE at Python startup. Problem: dup() doesn't check if the file descriptor is valid on some platforms. fcntl(fd, F_GETFD) is even faster, because it only checks the process table. It is preferred over dup() when available, since it cannot fail with the "too many open files" error (EMFILE). bpo-30225: On macOS Tiger, when stdout is redirected to a pipe and the other side of the pipe is closed, dup(1) succeed, whereas fstat(1, &st) fails with EBADF. FreeBSD has similar issue (bpo-32849). Only use dup() on Linux where dup() is enough to detect invalid FD (bpo-32849). */ if (fd < 0) { return 0; } #if defined(F_GETFD) && ( \ defined(__linux__) || \ defined(__APPLE__) || \ defined(__wasm__)) return fcntl(fd, F_GETFD) >= 0; #elif defined(__linux__) int fd2 = dup(fd); if (fd2 >= 0) { close(fd2); } return (fd2 >= 0); #elif defined(MS_WINDOWS) HANDLE hfile; _Py_BEGIN_SUPPRESS_IPH hfile = (HANDLE)_get_osfhandle(fd); _Py_END_SUPPRESS_IPH return (hfile != INVALID_HANDLE_VALUE && GetFileType(hfile) != FILE_TYPE_UNKNOWN); #else struct stat st; return (fstat(fd, &st) == 0); #endif } /* returns Py_None if the fd is not valid */ static PyObject* create_stdio(const PyConfig *config, PyObject* io, int fd, int write_mode, const char* name, const wchar_t* encoding, const wchar_t* errors) { PyObject *buf = NULL, *stream = NULL, *text = NULL, *raw = NULL, *res; const char* mode; const char* newline; PyObject *line_buffering, *write_through; int buffering, isatty; const int buffered_stdio = config->buffered_stdio; if (!is_valid_fd(fd)) Py_RETURN_NONE; /* stdin is always opened in buffered mode, first because it shouldn't make a difference in common use cases, second because TextIOWrapper depends on the presence of a read1() method which only exists on buffered streams. */ if (!buffered_stdio && write_mode) buffering = 0; else buffering = -1; if (write_mode) mode = "wb"; else mode = "rb"; buf = _PyObject_CallMethod(io, &_Py_ID(open), "isiOOOO", fd, mode, buffering, Py_None, Py_None, /* encoding, errors */ Py_None, Py_False); /* newline, closefd */ if (buf == NULL) goto error; if (buffering) { raw = PyObject_GetAttr(buf, &_Py_ID(raw)); if (raw == NULL) goto error; } else { raw = Py_NewRef(buf); } #ifdef HAVE_WINDOWS_CONSOLE_IO /* Windows console IO is always UTF-8 encoded */ PyTypeObject *winconsoleio_type = (PyTypeObject *)_PyImport_GetModuleAttr( &_Py_ID(_io), &_Py_ID(_WindowsConsoleIO)); if (winconsoleio_type == NULL) { goto error; } int is_subclass = PyObject_TypeCheck(raw, winconsoleio_type); Py_DECREF(winconsoleio_type); if (is_subclass) { encoding = L"utf-8"; } #endif text = PyUnicode_FromString(name); if (text == NULL || PyObject_SetAttr(raw, &_Py_ID(name), text) < 0) goto error; res = PyObject_CallMethodNoArgs(raw, &_Py_ID(isatty)); if (res == NULL) goto error; isatty = PyObject_IsTrue(res); Py_DECREF(res); if (isatty == -1) goto error; if (!buffered_stdio) write_through = Py_True; else write_through = Py_False; if (buffered_stdio && (isatty || fd == fileno(stderr))) line_buffering = Py_True; else line_buffering = Py_False; Py_CLEAR(raw); Py_CLEAR(text); #ifdef MS_WINDOWS /* sys.stdin: enable universal newline mode, translate "\r\n" and "\r" newlines to "\n". sys.stdout and sys.stderr: translate "\n" to "\r\n". */ newline = NULL; #else /* sys.stdin: split lines at "\n". sys.stdout and sys.stderr: don't translate newlines (use "\n"). */ newline = "\n"; #endif PyObject *encoding_str = PyUnicode_FromWideChar(encoding, -1); if (encoding_str == NULL) { Py_CLEAR(buf); goto error; } PyObject *errors_str = PyUnicode_FromWideChar(errors, -1); if (errors_str == NULL) { Py_CLEAR(buf); Py_CLEAR(encoding_str); goto error; } stream = _PyObject_CallMethod(io, &_Py_ID(TextIOWrapper), "OOOsOO", buf, encoding_str, errors_str, newline, line_buffering, write_through); Py_CLEAR(buf); Py_CLEAR(encoding_str); Py_CLEAR(errors_str); if (stream == NULL) goto error; if (write_mode) mode = "w"; else mode = "r"; text = PyUnicode_FromString(mode); if (!text || PyObject_SetAttr(stream, &_Py_ID(mode), text) < 0) goto error; Py_CLEAR(text); return stream; error: Py_XDECREF(buf); Py_XDECREF(stream); Py_XDECREF(text); Py_XDECREF(raw); if (PyErr_ExceptionMatches(PyExc_OSError) && !is_valid_fd(fd)) { /* Issue #24891: the file descriptor was closed after the first is_valid_fd() check was called. Ignore the OSError and set the stream to None. */ PyErr_Clear(); Py_RETURN_NONE; } return NULL; } /* Set builtins.open to io.open */ static PyStatus init_set_builtins_open(void) { PyObject *wrapper; PyObject *bimod = NULL; PyStatus res = _PyStatus_OK(); if (!(bimod = PyImport_ImportModule("builtins"))) { goto error; } if (!(wrapper = _PyImport_GetModuleAttrString("io", "open"))) { goto error; } /* Set builtins.open */ if (PyObject_SetAttrString(bimod, "open", wrapper) == -1) { Py_DECREF(wrapper); goto error; } Py_DECREF(wrapper); goto done; error: res = _PyStatus_ERR("can't initialize io.open"); done: Py_XDECREF(bimod); return res; } /* Create sys.stdin, sys.stdout and sys.stderr */ static PyStatus init_sys_streams(PyThreadState *tstate) { PyObject *iomod = NULL; PyObject *std = NULL; int fd; PyObject * encoding_attr; PyStatus res = _PyStatus_OK(); const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp); /* Check that stdin is not a directory Using shell redirection, you can redirect stdin to a directory, crashing the Python interpreter. Catch this common mistake here and output a useful error message. Note that under MS Windows, the shell already prevents that. */ #ifndef MS_WINDOWS struct _Py_stat_struct sb; if (_Py_fstat_noraise(fileno(stdin), &sb) == 0 && S_ISDIR(sb.st_mode)) { return _PyStatus_ERR(" is a directory, cannot continue"); } #endif if (!(iomod = PyImport_ImportModule("io"))) { goto error; } /* Set sys.stdin */ fd = fileno(stdin); /* Under some conditions stdin, stdout and stderr may not be connected * and fileno() may point to an invalid file descriptor. For example * GUI apps don't have valid standard streams by default. */ std = create_stdio(config, iomod, fd, 0, "", config->stdio_encoding, config->stdio_errors); if (std == NULL) goto error; PySys_SetObject("__stdin__", std); _PySys_SetAttr(&_Py_ID(stdin), std); Py_DECREF(std); /* Set sys.stdout */ fd = fileno(stdout); std = create_stdio(config, iomod, fd, 1, "", config->stdio_encoding, config->stdio_errors); if (std == NULL) goto error; PySys_SetObject("__stdout__", std); _PySys_SetAttr(&_Py_ID(stdout), std); Py_DECREF(std); #if 1 /* Disable this if you have trouble debugging bootstrap stuff */ /* Set sys.stderr, replaces the preliminary stderr */ fd = fileno(stderr); std = create_stdio(config, iomod, fd, 1, "", config->stdio_encoding, L"backslashreplace"); if (std == NULL) goto error; /* Same as hack above, pre-import stderr's codec to avoid recursion when import.c tries to write to stderr in verbose mode. */ encoding_attr = PyObject_GetAttrString(std, "encoding"); if (encoding_attr != NULL) { const char *std_encoding = PyUnicode_AsUTF8(encoding_attr); if (std_encoding != NULL) { PyObject *codec_info = _PyCodec_Lookup(std_encoding); Py_XDECREF(codec_info); } Py_DECREF(encoding_attr); } _PyErr_Clear(tstate); /* Not a fatal error if codec isn't available */ if (PySys_SetObject("__stderr__", std) < 0) { Py_DECREF(std); goto error; } if (_PySys_SetAttr(&_Py_ID(stderr), std) < 0) { Py_DECREF(std); goto error; } Py_DECREF(std); #endif goto done; error: res = _PyStatus_ERR("can't initialize sys standard streams"); done: Py_XDECREF(iomod); return res; } static void _Py_FatalError_DumpTracebacks(int fd, PyInterpreterState *interp, PyThreadState *tstate) { PUTS(fd, "\n"); /* display the current Python stack */ _Py_DumpTracebackThreads(fd, interp, tstate); } /* Print the current exception (if an exception is set) with its traceback, or display the current Python stack. Don't call PyErr_PrintEx() and the except hook, because Py_FatalError() is called on catastrophic cases. Return 1 if the traceback was displayed, 0 otherwise. */ static int _Py_FatalError_PrintExc(PyThreadState *tstate) { PyObject *exc = _PyErr_GetRaisedException(tstate); if (exc == NULL) { /* No current exception */ return 0; } PyObject *ferr = _PySys_GetAttr(tstate, &_Py_ID(stderr)); if (ferr == NULL || ferr == Py_None) { /* sys.stderr is not set yet or set to None, no need to try to display the exception */ Py_DECREF(exc); return 0; } PyErr_DisplayException(exc); PyObject *tb = PyException_GetTraceback(exc); int has_tb = (tb != NULL) && (tb != Py_None); Py_XDECREF(tb); Py_DECREF(exc); /* sys.stderr may be buffered: call sys.stderr.flush() */ PyObject *res = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush)); if (res == NULL) { _PyErr_Clear(tstate); } else { Py_DECREF(res); } return has_tb; } /* Print fatal error message and abort */ #ifdef MS_WINDOWS static void fatal_output_debug(const char *msg) { /* buffer of 256 bytes allocated on the stack */ WCHAR buffer[256 / sizeof(WCHAR)]; size_t buflen = Py_ARRAY_LENGTH(buffer) - 1; size_t msglen; OutputDebugStringW(L"Fatal Python error: "); msglen = strlen(msg); while (msglen) { size_t i; if (buflen > msglen) { buflen = msglen; } /* Convert the message to wchar_t. This uses a simple one-to-one conversion, assuming that the this error message actually uses ASCII only. If this ceases to be true, we will have to convert. */ for (i=0; i < buflen; ++i) { buffer[i] = msg[i]; } buffer[i] = L'\0'; OutputDebugStringW(buffer); msg += buflen; msglen -= buflen; } OutputDebugStringW(L"\n"); } #endif static void fatal_error_dump_runtime(int fd, _PyRuntimeState *runtime) { PUTS(fd, "Python runtime state: "); PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(runtime); if (finalizing) { PUTS(fd, "finalizing (tstate=0x"); _Py_DumpHexadecimal(fd, (uintptr_t)finalizing, sizeof(finalizing) * 2); PUTS(fd, ")"); } else if (runtime->initialized) { PUTS(fd, "initialized"); } else if (runtime->core_initialized) { PUTS(fd, "core initialized"); } else if (runtime->preinitialized) { PUTS(fd, "preinitialized"); } else if (runtime->preinitializing) { PUTS(fd, "preinitializing"); } else { PUTS(fd, "unknown"); } PUTS(fd, "\n"); } static inline void _Py_NO_RETURN fatal_error_exit(int status) { if (status < 0) { #if defined(MS_WINDOWS) && defined(_DEBUG) DebugBreak(); #endif abort(); } else { exit(status); } } // Dump the list of extension modules of sys.modules, excluding stdlib modules // (sys.stdlib_module_names), into fd file descriptor. // // This function is called by a signal handler in faulthandler: avoid memory // allocations and keep the implementation simple. For example, the list is not // sorted on purpose. void _Py_DumpExtensionModules(int fd, PyInterpreterState *interp) { if (interp == NULL) { return; } PyObject *modules = _PyImport_GetModules(interp); if (modules == NULL || !PyDict_Check(modules)) { return; } Py_ssize_t pos; PyObject *key, *value; // Avoid PyDict_GetItemString() which calls PyUnicode_FromString(), // memory cannot be allocated on the heap in a signal handler. // Iterate on the dict instead. PyObject *stdlib_module_names = NULL; if (interp->sysdict != NULL) { pos = 0; while (PyDict_Next(interp->sysdict, &pos, &key, &value)) { if (PyUnicode_Check(key) && PyUnicode_CompareWithASCIIString(key, "stdlib_module_names") == 0) { stdlib_module_names = value; break; } } } // If we failed to get sys.stdlib_module_names or it's not a frozenset, // don't exclude stdlib modules. if (stdlib_module_names != NULL && !PyFrozenSet_Check(stdlib_module_names)) { stdlib_module_names = NULL; } // List extensions int header = 1; Py_ssize_t count = 0; pos = 0; while (PyDict_Next(modules, &pos, &key, &value)) { if (!PyUnicode_Check(key)) { continue; } if (!_PyModule_IsExtension(value)) { continue; } // Use the module name from the sys.modules key, // don't attempt to get the module object name. if (stdlib_module_names != NULL) { int is_stdlib_ext = 0; Py_ssize_t i = 0; PyObject *item; Py_hash_t hash; while (_PySet_NextEntry(stdlib_module_names, &i, &item, &hash)) { if (PyUnicode_Check(item) && PyUnicode_Compare(key, item) == 0) { is_stdlib_ext = 1; break; } } if (is_stdlib_ext) { // Ignore stdlib extension continue; } } if (header) { PUTS(fd, "\nExtension modules: "); header = 0; } else { PUTS(fd, ", "); } _Py_DumpASCII(fd, key); count++; } if (count) { PUTS(fd, " (total: "); _Py_DumpDecimal(fd, count); PUTS(fd, ")"); PUTS(fd, "\n"); } } static void _Py_NO_RETURN fatal_error(int fd, int header, const char *prefix, const char *msg, int status) { static int reentrant = 0; if (reentrant) { /* Py_FatalError() caused a second fatal error. Example: flush_std_files() raises a recursion error. */ fatal_error_exit(status); } reentrant = 1; if (header) { PUTS(fd, "Fatal Python error: "); if (prefix) { PUTS(fd, prefix); PUTS(fd, ": "); } if (msg) { PUTS(fd, msg); } else { PUTS(fd, ""); } PUTS(fd, "\n"); } _PyRuntimeState *runtime = &_PyRuntime; fatal_error_dump_runtime(fd, runtime); /* Check if the current thread has a Python thread state and holds the GIL. tss_tstate is NULL if Py_FatalError() is called from a C thread which has no Python thread state. tss_tstate != tstate if the current Python thread does not hold the GIL. */ PyThreadState *tstate = _PyThreadState_GET(); PyInterpreterState *interp = NULL; PyThreadState *tss_tstate = PyGILState_GetThisThreadState(); if (tstate != NULL) { interp = tstate->interp; } else if (tss_tstate != NULL) { interp = tss_tstate->interp; } int has_tstate_and_gil = (tss_tstate != NULL && tss_tstate == tstate); if (has_tstate_and_gil) { /* If an exception is set, print the exception with its traceback */ if (!_Py_FatalError_PrintExc(tss_tstate)) { /* No exception is set, or an exception is set without traceback */ _Py_FatalError_DumpTracebacks(fd, interp, tss_tstate); } } else { _Py_FatalError_DumpTracebacks(fd, interp, tss_tstate); } _Py_DumpExtensionModules(fd, interp); /* The main purpose of faulthandler is to display the traceback. This function already did its best to display a traceback. Disable faulthandler to prevent writing a second traceback on abort(). */ _PyFaulthandler_Fini(); /* Check if the current Python thread hold the GIL */ if (has_tstate_and_gil) { /* Flush sys.stdout and sys.stderr */ flush_std_files(); } #ifdef MS_WINDOWS fatal_output_debug(msg); #endif /* MS_WINDOWS */ fatal_error_exit(status); } #undef Py_FatalError void _Py_NO_RETURN Py_FatalError(const char *msg) { fatal_error(fileno(stderr), 1, NULL, msg, -1); } void _Py_NO_RETURN _Py_FatalErrorFunc(const char *func, const char *msg) { fatal_error(fileno(stderr), 1, func, msg, -1); } void _Py_NO_RETURN _Py_FatalErrorFormat(const char *func, const char *format, ...) { static int reentrant = 0; if (reentrant) { /* _Py_FatalErrorFormat() caused a second fatal error */ fatal_error_exit(-1); } reentrant = 1; FILE *stream = stderr; const int fd = fileno(stream); PUTS(fd, "Fatal Python error: "); if (func) { PUTS(fd, func); PUTS(fd, ": "); } va_list vargs; va_start(vargs, format); vfprintf(stream, format, vargs); va_end(vargs); fputs("\n", stream); fflush(stream); fatal_error(fd, 0, NULL, NULL, -1); } void _Py_NO_RETURN _Py_FatalRefcountErrorFunc(const char *func, const char *msg) { _Py_FatalErrorFormat(func, "%s: bug likely caused by a refcount error " "in a C extension", msg); } void _Py_NO_RETURN Py_ExitStatusException(PyStatus status) { if (_PyStatus_IS_EXIT(status)) { exit(status.exitcode); } else if (_PyStatus_IS_ERROR(status)) { fatal_error(fileno(stderr), 1, status.func, status.err_msg, 1); } else { Py_FatalError("Py_ExitStatusException() must not be called on success"); } } /* Wait until threading._shutdown completes, provided the threading module was imported in the first place. The shutdown routine will wait until all non-daemon "threading" threads have completed. */ static void wait_for_thread_shutdown(PyThreadState *tstate) { PyObject *result; PyObject *threading = PyImport_GetModule(&_Py_ID(threading)); if (threading == NULL) { if (_PyErr_Occurred(tstate)) { PyErr_WriteUnraisable(NULL); } /* else: threading not imported */ return; } result = PyObject_CallMethodNoArgs(threading, &_Py_ID(_shutdown)); if (result == NULL) { PyErr_WriteUnraisable(threading); } else { Py_DECREF(result); } Py_DECREF(threading); } int Py_AtExit(void (*func)(void)) { if (_PyRuntime.atexit.ncallbacks >= NEXITFUNCS) return -1; _PyRuntime.atexit.callbacks[_PyRuntime.atexit.ncallbacks++] = func; return 0; } static void call_ll_exitfuncs(_PyRuntimeState *runtime) { struct _atexit_runtime_state *state = &runtime->atexit; while (state->ncallbacks > 0) { /* pop last function from the list */ state->ncallbacks--; atexit_callbackfunc exitfunc = state->callbacks[state->ncallbacks]; state->callbacks[state->ncallbacks] = NULL; exitfunc(); } fflush(stdout); fflush(stderr); } void _Py_NO_RETURN Py_Exit(int sts) { if (Py_FinalizeEx() < 0) { sts = 120; } exit(sts); } /* * The file descriptor fd is considered ``interactive'' if either * a) isatty(fd) is TRUE, or * b) the -i flag was given, and the filename associated with * the descriptor is NULL or "" or "???". */ int Py_FdIsInteractive(FILE *fp, const char *filename) { if (isatty(fileno(fp))) { return 1; } if (!_Py_GetConfig()->interactive) { return 0; } return ((filename == NULL) || (strcmp(filename, "") == 0) || (strcmp(filename, "???") == 0)); } int _Py_FdIsInteractive(FILE *fp, PyObject *filename) { if (isatty(fileno(fp))) { return 1; } if (!_Py_GetConfig()->interactive) { return 0; } return ((filename == NULL) || (PyUnicode_CompareWithASCIIString(filename, "") == 0) || (PyUnicode_CompareWithASCIIString(filename, "???") == 0)); } /* Wrappers around sigaction() or signal(). */ PyOS_sighandler_t PyOS_getsig(int sig) { #ifdef HAVE_SIGACTION struct sigaction context; if (sigaction(sig, NULL, &context) == -1) return SIG_ERR; return context.sa_handler; #else PyOS_sighandler_t handler; /* Special signal handling for the secure CRT in Visual Studio 2005 */ #if defined(_MSC_VER) && _MSC_VER >= 1400 switch (sig) { /* Only these signals are valid */ case SIGINT: case SIGILL: case SIGFPE: case SIGSEGV: case SIGTERM: case SIGBREAK: case SIGABRT: break; /* Don't call signal() with other values or it will assert */ default: return SIG_ERR; } #endif /* _MSC_VER && _MSC_VER >= 1400 */ handler = signal(sig, SIG_IGN); if (handler != SIG_ERR) signal(sig, handler); return handler; #endif } /* * All of the code in this function must only use async-signal-safe functions, * listed at `man 7 signal` or * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html. */ PyOS_sighandler_t PyOS_setsig(int sig, PyOS_sighandler_t handler) { #ifdef HAVE_SIGACTION /* Some code in Modules/signalmodule.c depends on sigaction() being * used here if HAVE_SIGACTION is defined. Fix that if this code * changes to invalidate that assumption. */ struct sigaction context, ocontext; context.sa_handler = handler; sigemptyset(&context.sa_mask); /* Using SA_ONSTACK is friendlier to other C/C++/Golang-VM code that * extension module or embedding code may use where tiny thread stacks * are used. https://bugs.python.org/issue43390 */ context.sa_flags = SA_ONSTACK; if (sigaction(sig, &context, &ocontext) == -1) return SIG_ERR; return ocontext.sa_handler; #else PyOS_sighandler_t oldhandler; oldhandler = signal(sig, handler); #ifdef HAVE_SIGINTERRUPT siginterrupt(sig, 1); #endif return oldhandler; #endif } #ifdef __cplusplus } #endif ================================================ FILE: PyMath.c ================================================ #include "Python.h" #ifdef HAVE_GCC_ASM_FOR_X87 // Inline assembly for getting and setting the 387 FPU control word on // GCC/x86. #ifdef _Py_MEMORY_SANITIZER __attribute__((no_sanitize_memory)) #endif unsigned short _Py_get_387controlword(void) { unsigned short cw; __asm__ __volatile__ ("fnstcw %0" : "=m" (cw)); return cw; } void _Py_set_387controlword(unsigned short cw) { __asm__ __volatile__ ("fldcw %0" : : "m" (cw)); } #endif // HAVE_GCC_ASM_FOR_X87 ================================================ FILE: PyState.c ================================================ /* Thread and interpreter state structures and their interfaces */ #include "Python.h" #include "pycore_ceval.h" #include "pycore_code.h" // stats #include "pycore_dtoa.h" // _dtoa_state_INIT() #include "pycore_frame.h" #include "pycore_initconfig.h" #include "pycore_object.h" // _PyType_InitCache() #include "pycore_pyerrors.h" #include "pycore_pylifecycle.h" #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator() #include "pycore_pystate.h" #include "pycore_runtime_init.h" // _PyRuntimeState_INIT #include "pycore_sysmodule.h" /* -------------------------------------------------------------------------- CAUTION Always use PyMem_RawMalloc() and PyMem_RawFree() directly in this file. A number of these functions are advertised as safe to call when the GIL isn't held, and in a debug build Python redirects (e.g.) PyMem_NEW (etc) to Python's debugging obmalloc functions. Those aren't thread-safe (they rely on the GIL to avoid the expense of doing their own locking). -------------------------------------------------------------------------- */ #ifdef HAVE_DLOPEN #ifdef HAVE_DLFCN_H #include #endif #if !HAVE_DECL_RTLD_LAZY #define RTLD_LAZY 1 #endif #endif #ifdef __cplusplus extern "C" { #endif /****************************************/ /* helpers for the current thread state */ /****************************************/ // API for the current thread state is further down. /* "current" means one of: - bound to the current OS thread - holds the GIL */ //------------------------------------------------- // a highly efficient lookup for the current thread //------------------------------------------------- /* The stored thread state is set by PyThreadState_Swap(). For each of these functions, the GIL must be held by the current thread. */ #ifdef HAVE_THREAD_LOCAL _Py_thread_local PyThreadState *_Py_tss_tstate = NULL; #endif static inline PyThreadState * current_fast_get(_PyRuntimeState *Py_UNUSED(runtime)) { #ifdef HAVE_THREAD_LOCAL return _Py_tss_tstate; #else // XXX Fall back to the PyThread_tss_*() API. # error "no supported thread-local variable storage classifier" #endif } static inline void current_fast_set(_PyRuntimeState *Py_UNUSED(runtime), PyThreadState *tstate) { assert(tstate != NULL); #ifdef HAVE_THREAD_LOCAL _Py_tss_tstate = tstate; #else // XXX Fall back to the PyThread_tss_*() API. # error "no supported thread-local variable storage classifier" #endif } static inline void current_fast_clear(_PyRuntimeState *Py_UNUSED(runtime)) { #ifdef HAVE_THREAD_LOCAL _Py_tss_tstate = NULL; #else // XXX Fall back to the PyThread_tss_*() API. # error "no supported thread-local variable storage classifier" #endif } #define tstate_verify_not_active(tstate) \ if (tstate == current_fast_get((tstate)->interp->runtime)) { \ _Py_FatalErrorFormat(__func__, "tstate %p is still current", tstate); \ } PyThreadState * _PyThreadState_GetCurrent(void) { return current_fast_get(&_PyRuntime); } //------------------------------------------------ // the thread state bound to the current OS thread //------------------------------------------------ static inline int tstate_tss_initialized(Py_tss_t *key) { return PyThread_tss_is_created(key); } static inline int tstate_tss_init(Py_tss_t *key) { assert(!tstate_tss_initialized(key)); return PyThread_tss_create(key); } static inline void tstate_tss_fini(Py_tss_t *key) { assert(tstate_tss_initialized(key)); PyThread_tss_delete(key); } static inline PyThreadState * tstate_tss_get(Py_tss_t *key) { assert(tstate_tss_initialized(key)); return (PyThreadState *)PyThread_tss_get(key); } static inline int tstate_tss_set(Py_tss_t *key, PyThreadState *tstate) { assert(tstate != NULL); assert(tstate_tss_initialized(key)); return PyThread_tss_set(key, (void *)tstate); } static inline int tstate_tss_clear(Py_tss_t *key) { assert(tstate_tss_initialized(key)); return PyThread_tss_set(key, (void *)NULL); } #ifdef HAVE_FORK /* Reset the TSS key - called by PyOS_AfterFork_Child(). * This should not be necessary, but some - buggy - pthread implementations * don't reset TSS upon fork(), see issue #10517. */ static PyStatus tstate_tss_reinit(Py_tss_t *key) { if (!tstate_tss_initialized(key)) { return _PyStatus_OK(); } PyThreadState *tstate = tstate_tss_get(key); tstate_tss_fini(key); if (tstate_tss_init(key) != 0) { return _PyStatus_NO_MEMORY(); } /* If the thread had an associated auto thread state, reassociate it with * the new key. */ if (tstate && tstate_tss_set(key, tstate) != 0) { return _PyStatus_ERR("failed to re-set autoTSSkey"); } return _PyStatus_OK(); } #endif /* The stored thread state is set by bind_tstate() (AKA PyThreadState_Bind(). The GIL does no need to be held for these. */ #define gilstate_tss_initialized(runtime) \ tstate_tss_initialized(&(runtime)->autoTSSkey) #define gilstate_tss_init(runtime) \ tstate_tss_init(&(runtime)->autoTSSkey) #define gilstate_tss_fini(runtime) \ tstate_tss_fini(&(runtime)->autoTSSkey) #define gilstate_tss_get(runtime) \ tstate_tss_get(&(runtime)->autoTSSkey) #define _gilstate_tss_set(runtime, tstate) \ tstate_tss_set(&(runtime)->autoTSSkey, tstate) #define _gilstate_tss_clear(runtime) \ tstate_tss_clear(&(runtime)->autoTSSkey) #define gilstate_tss_reinit(runtime) \ tstate_tss_reinit(&(runtime)->autoTSSkey) static inline void gilstate_tss_set(_PyRuntimeState *runtime, PyThreadState *tstate) { assert(tstate != NULL && tstate->interp->runtime == runtime); if (_gilstate_tss_set(runtime, tstate) != 0) { Py_FatalError("failed to set current tstate (TSS)"); } } static inline void gilstate_tss_clear(_PyRuntimeState *runtime) { if (_gilstate_tss_clear(runtime) != 0) { Py_FatalError("failed to clear current tstate (TSS)"); } } #ifndef NDEBUG static inline int tstate_is_alive(PyThreadState *tstate); static inline int tstate_is_bound(PyThreadState *tstate) { return tstate->_status.bound && !tstate->_status.unbound; } #endif // !NDEBUG static void bind_gilstate_tstate(PyThreadState *); static void unbind_gilstate_tstate(PyThreadState *); static void bind_tstate(PyThreadState *tstate) { assert(tstate != NULL); assert(tstate_is_alive(tstate) && !tstate->_status.bound); assert(!tstate->_status.unbound); // just in case assert(!tstate->_status.bound_gilstate); assert(tstate != gilstate_tss_get(tstate->interp->runtime)); assert(!tstate->_status.active); assert(tstate->thread_id == 0); assert(tstate->native_thread_id == 0); // Currently we don't necessarily store the thread state // in thread-local storage (e.g. per-interpreter). tstate->thread_id = PyThread_get_thread_ident(); #ifdef PY_HAVE_THREAD_NATIVE_ID tstate->native_thread_id = PyThread_get_thread_native_id(); #endif tstate->_status.bound = 1; } static void unbind_tstate(PyThreadState *tstate) { assert(tstate != NULL); // XXX assert(tstate_is_alive(tstate)); assert(tstate_is_bound(tstate)); // XXX assert(!tstate->_status.active); assert(tstate->thread_id > 0); #ifdef PY_HAVE_THREAD_NATIVE_ID assert(tstate->native_thread_id > 0); #endif // We leave thread_id and native_thread_id alone // since they can be useful for debugging. // Check the `_status` field to know if these values // are still valid. // We leave tstate->_status.bound set to 1 // to indicate it was previously bound. tstate->_status.unbound = 1; } /* Stick the thread state for this thread in thread specific storage. When a thread state is created for a thread by some mechanism other than PyGILState_Ensure(), it's important that the GILState machinery knows about it so it doesn't try to create another thread state for the thread. (This is a better fix for SF bug #1010677 than the first one attempted.) The only situation where you can legitimately have more than one thread state for an OS level thread is when there are multiple interpreters. Before 3.12, the PyGILState_*() APIs didn't work with multiple interpreters (see bpo-10915 and bpo-15751), so this function used to set TSS only once. Thus, the first thread state created for that given OS level thread would "win", which seemed reasonable behaviour. */ static void bind_gilstate_tstate(PyThreadState *tstate) { assert(tstate != NULL); assert(tstate_is_alive(tstate)); assert(tstate_is_bound(tstate)); // XXX assert(!tstate->_status.active); assert(!tstate->_status.bound_gilstate); _PyRuntimeState *runtime = tstate->interp->runtime; PyThreadState *tcur = gilstate_tss_get(runtime); assert(tstate != tcur); if (tcur != NULL) { tcur->_status.bound_gilstate = 0; } gilstate_tss_set(runtime, tstate); tstate->_status.bound_gilstate = 1; } static void unbind_gilstate_tstate(PyThreadState *tstate) { assert(tstate != NULL); // XXX assert(tstate_is_alive(tstate)); assert(tstate_is_bound(tstate)); // XXX assert(!tstate->_status.active); assert(tstate->_status.bound_gilstate); assert(tstate == gilstate_tss_get(tstate->interp->runtime)); gilstate_tss_clear(tstate->interp->runtime); tstate->_status.bound_gilstate = 0; } //---------------------------------------------- // the thread state that currently holds the GIL //---------------------------------------------- /* This is not exported, as it is not reliable! It can only ever be compared to the state for the *current* thread. * If not equal, then it doesn't matter that the actual value may change immediately after comparison, as it can't possibly change to the current thread's state. * If equal, then the current thread holds the lock, so the value can't change until we yield the lock. */ static int holds_gil(PyThreadState *tstate) { // XXX Fall back to tstate->interp->runtime->ceval.gil.last_holder // (and tstate->interp->runtime->ceval.gil.locked). assert(tstate != NULL); _PyRuntimeState *runtime = tstate->interp->runtime; /* Must be the tstate for this thread */ assert(tstate == gilstate_tss_get(runtime)); return tstate == current_fast_get(runtime); } /****************************/ /* the global runtime state */ /****************************/ //---------- // lifecycle //---------- /* Suppress deprecation warning for PyBytesObject.ob_shash */ _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS /* We use "initial" if the runtime gets re-used (e.g. Py_Finalize() followed by Py_Initialize(). Note that we initialize "initial" relative to _PyRuntime, to ensure pre-initialized pointers point to the active runtime state (and not "initial"). */ static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime); _Py_COMP_DIAG_POP #define NUMLOCKS 5 static int alloc_for_runtime(PyThread_type_lock locks[NUMLOCKS]) { /* Force default allocator, since _PyRuntimeState_Fini() must use the same allocator than this function. */ PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); for (int i = 0; i < NUMLOCKS; i++) { PyThread_type_lock lock = PyThread_allocate_lock(); if (lock == NULL) { for (int j = 0; j < i; j++) { PyThread_free_lock(locks[j]); locks[j] = NULL; } break; } locks[i] = lock; } PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); return 0; } static void init_runtime(_PyRuntimeState *runtime, void *open_code_hook, void *open_code_userdata, _Py_AuditHookEntry *audit_hook_head, Py_ssize_t unicode_next_index, PyThread_type_lock locks[NUMLOCKS]) { if (runtime->_initialized) { Py_FatalError("runtime already initialized"); } assert(!runtime->preinitializing && !runtime->preinitialized && !runtime->core_initialized && !runtime->initialized); runtime->open_code_hook = open_code_hook; runtime->open_code_userdata = open_code_userdata; runtime->audit_hook_head = audit_hook_head; PyPreConfig_InitPythonConfig(&runtime->preconfig); PyThread_type_lock *lockptrs[NUMLOCKS] = { &runtime->interpreters.mutex, &runtime->xidregistry.mutex, &runtime->getargs.mutex, &runtime->unicode_state.ids.lock, &runtime->imports.extensions.mutex, }; for (int i = 0; i < NUMLOCKS; i++) { assert(locks[i] != NULL); *lockptrs[i] = locks[i]; } // Set it to the ID of the main thread of the main interpreter. runtime->main_thread = PyThread_get_thread_ident(); runtime->unicode_state.ids.next_index = unicode_next_index; runtime->_initialized = 1; } PyStatus _PyRuntimeState_Init(_PyRuntimeState *runtime) { /* We preserve the hook across init, because there is currently no public API to set it between runtime initialization and interpreter initialization. */ void *open_code_hook = runtime->open_code_hook; void *open_code_userdata = runtime->open_code_userdata; _Py_AuditHookEntry *audit_hook_head = runtime->audit_hook_head; // bpo-42882: Preserve next_index value if Py_Initialize()/Py_Finalize() // is called multiple times. Py_ssize_t unicode_next_index = runtime->unicode_state.ids.next_index; PyThread_type_lock locks[NUMLOCKS]; if (alloc_for_runtime(locks) != 0) { return _PyStatus_NO_MEMORY(); } if (runtime->_initialized) { // Py_Initialize() must be running again. // Reset to _PyRuntimeState_INIT. memcpy(runtime, &initial, sizeof(*runtime)); } if (gilstate_tss_init(runtime) != 0) { _PyRuntimeState_Fini(runtime); return _PyStatus_NO_MEMORY(); } if (PyThread_tss_create(&runtime->trashTSSkey) != 0) { _PyRuntimeState_Fini(runtime); return _PyStatus_NO_MEMORY(); } init_runtime(runtime, open_code_hook, open_code_userdata, audit_hook_head, unicode_next_index, locks); return _PyStatus_OK(); } void _PyRuntimeState_Fini(_PyRuntimeState *runtime) { #ifdef Py_REF_DEBUG /* The count is cleared by _Py_FinalizeRefTotal(). */ assert(runtime->object_state.interpreter_leaks == 0); #endif if (gilstate_tss_initialized(runtime)) { gilstate_tss_fini(runtime); } if (PyThread_tss_is_created(&runtime->trashTSSkey)) { PyThread_tss_delete(&runtime->trashTSSkey); } /* Force the allocator used by _PyRuntimeState_Init(). */ PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); #define FREE_LOCK(LOCK) \ if (LOCK != NULL) { \ PyThread_free_lock(LOCK); \ LOCK = NULL; \ } PyThread_type_lock *lockptrs[NUMLOCKS] = { &runtime->interpreters.mutex, &runtime->xidregistry.mutex, &runtime->getargs.mutex, &runtime->unicode_state.ids.lock, &runtime->imports.extensions.mutex, }; for (int i = 0; i < NUMLOCKS; i++) { FREE_LOCK(*lockptrs[i]); } #undef FREE_LOCK PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); } #ifdef HAVE_FORK /* This function is called from PyOS_AfterFork_Child to ensure that newly created child processes do not share locks with the parent. */ PyStatus _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime) { // This was initially set in _PyRuntimeState_Init(). runtime->main_thread = PyThread_get_thread_ident(); /* Force default allocator, since _PyRuntimeState_Fini() must use the same allocator than this function. */ PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); PyThread_type_lock *lockptrs[NUMLOCKS] = { &runtime->interpreters.mutex, &runtime->xidregistry.mutex, &runtime->getargs.mutex, &runtime->unicode_state.ids.lock, &runtime->imports.extensions.mutex, }; int reinit_err = 0; for (int i = 0; i < NUMLOCKS; i++) { reinit_err += _PyThread_at_fork_reinit(lockptrs[i]); } PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); /* bpo-42540: id_mutex is freed by _PyInterpreterState_Delete, which does * not force the default allocator. */ reinit_err += _PyThread_at_fork_reinit(&runtime->interpreters.main->id_mutex); if (reinit_err < 0) { return _PyStatus_ERR("Failed to reinitialize runtime locks"); } PyStatus status = gilstate_tss_reinit(runtime); if (_PyStatus_EXCEPTION(status)) { return status; } if (PyThread_tss_is_created(&runtime->trashTSSkey)) { PyThread_tss_delete(&runtime->trashTSSkey); } if (PyThread_tss_create(&runtime->trashTSSkey) != 0) { return _PyStatus_NO_MEMORY(); } return _PyStatus_OK(); } #endif /*************************************/ /* the per-interpreter runtime state */ /*************************************/ //---------- // lifecycle //---------- /* Calling this indicates that the runtime is ready to create interpreters. */ PyStatus _PyInterpreterState_Enable(_PyRuntimeState *runtime) { struct pyinterpreters *interpreters = &runtime->interpreters; interpreters->next_id = 0; /* Py_Finalize() calls _PyRuntimeState_Fini() which clears the mutex. Create a new mutex if needed. */ if (interpreters->mutex == NULL) { /* Force default allocator, since _PyRuntimeState_Fini() must use the same allocator than this function. */ PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); interpreters->mutex = PyThread_allocate_lock(); PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); if (interpreters->mutex == NULL) { return _PyStatus_ERR("Can't initialize threads for interpreter"); } } return _PyStatus_OK(); } static PyInterpreterState * alloc_interpreter(void) { return PyMem_RawCalloc(1, sizeof(PyInterpreterState)); } static void free_interpreter(PyInterpreterState *interp) { // The main interpreter is statically allocated so // should not be freed. if (interp != &_PyRuntime._main_interpreter) { PyMem_RawFree(interp); } } /* Get the interpreter state to a minimal consistent state. Further init happens in pylifecycle.c before it can be used. All fields not initialized here are expected to be zeroed out, e.g. by PyMem_RawCalloc() or memset(), or otherwise pre-initialized. The runtime state is not manipulated. Instead it is assumed that the interpreter is getting added to the runtime. Note that the main interpreter was statically initialized as part of the runtime and most state is already set properly. That leaves a small number of fields to initialize dynamically, as well as some that are initialized lazily. For subinterpreters we memcpy() the main interpreter in PyInterpreterState_New(), leaving it in the same mostly-initialized state. The only difference is that the interpreter has some self-referential state that is statically initializexd to the main interpreter. We fix those fields here, in addition to the other dynamically initialized fields. */ static void init_interpreter(PyInterpreterState *interp, _PyRuntimeState *runtime, int64_t id, PyInterpreterState *next, PyThread_type_lock pending_lock) { if (interp->_initialized) { Py_FatalError("interpreter already initialized"); } assert(runtime != NULL); interp->runtime = runtime; assert(id > 0 || (id == 0 && interp == runtime->interpreters.main)); interp->id = id; assert(runtime->interpreters.head == interp); assert(next != NULL || (interp == runtime->interpreters.main)); interp->next = next; /* Initialize obmalloc, but only for subinterpreters, since the main interpreter is initialized statically. */ if (interp != &runtime->_main_interpreter) { poolp temp[OBMALLOC_USED_POOLS_SIZE] = \ _obmalloc_pools_INIT(interp->obmalloc.pools); memcpy(&interp->obmalloc.pools.used, temp, sizeof(temp)); } _PyEval_InitState(interp, pending_lock); _PyGC_InitState(&interp->gc); PyConfig_InitPythonConfig(&interp->config); _PyType_InitCache(interp); for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { interp->monitors.tools[i] = 0; } for (int t = 0; t < PY_MONITORING_TOOL_IDS; t++) { for (int e = 0; e < PY_MONITORING_EVENTS; e++) { interp->monitoring_callables[t][e] = NULL; } } interp->sys_profile_initialized = false; interp->sys_trace_initialized = false; if (interp != &runtime->_main_interpreter) { /* Fix the self-referential, statically initialized fields. */ interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp); } interp->f_opcode_trace_set = false; interp->_initialized = 1; } PyInterpreterState * PyInterpreterState_New(void) { PyInterpreterState *interp; _PyRuntimeState *runtime = &_PyRuntime; PyThreadState *tstate = current_fast_get(runtime); /* tstate is NULL when Py_InitializeFromConfig() calls PyInterpreterState_New() to create the main interpreter. */ if (_PySys_Audit(tstate, "cpython.PyInterpreterState_New", NULL) < 0) { return NULL; } PyThread_type_lock pending_lock = PyThread_allocate_lock(); if (pending_lock == NULL) { if (tstate != NULL) { _PyErr_NoMemory(tstate); } return NULL; } /* Don't get runtime from tstate since tstate can be NULL. */ struct pyinterpreters *interpreters = &runtime->interpreters; /* We completely serialize creation of multiple interpreters, since it simplifies things here and blocking concurrent calls isn't a problem. Regardless, we must fully block subinterpreter creation until after the main interpreter is created. */ HEAD_LOCK(runtime); int64_t id = interpreters->next_id; interpreters->next_id += 1; // Allocate the interpreter and add it to the runtime state. PyInterpreterState *old_head = interpreters->head; if (old_head == NULL) { // We are creating the main interpreter. assert(interpreters->main == NULL); assert(id == 0); interp = &runtime->_main_interpreter; assert(interp->id == 0); assert(interp->next == NULL); interpreters->main = interp; } else { assert(interpreters->main != NULL); assert(id != 0); interp = alloc_interpreter(); if (interp == NULL) { goto error; } // Set to _PyInterpreterState_INIT. memcpy(interp, &initial._main_interpreter, sizeof(*interp)); if (id < 0) { /* overflow or Py_Initialize() not called yet! */ if (tstate != NULL) { _PyErr_SetString(tstate, PyExc_RuntimeError, "failed to get an interpreter ID"); } goto error; } } interpreters->head = interp; init_interpreter(interp, runtime, id, old_head, pending_lock); HEAD_UNLOCK(runtime); return interp; error: HEAD_UNLOCK(runtime); PyThread_free_lock(pending_lock); if (interp != NULL) { free_interpreter(interp); } return NULL; } static void interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) { assert(interp != NULL); assert(tstate != NULL); _PyRuntimeState *runtime = interp->runtime; /* XXX Conditions we need to enforce: * the GIL must be held by the current thread * tstate must be the "current" thread state (current_fast_get()) * tstate->interp must be interp * for the main interpreter, tstate must be the main thread */ // XXX Ideally, we would not rely on any thread state in this function // (and we would drop the "tstate" argument). if (_PySys_Audit(tstate, "cpython.PyInterpreterState_Clear", NULL) < 0) { _PyErr_Clear(tstate); } // Clear the current/main thread state last. HEAD_LOCK(runtime); PyThreadState *p = interp->threads.head; HEAD_UNLOCK(runtime); while (p != NULL) { // See https://github.com/python/cpython/issues/102126 // Must be called without HEAD_LOCK held as it can deadlock // if any finalizer tries to acquire that lock. PyThreadState_Clear(p); HEAD_LOCK(runtime); p = p->next; HEAD_UNLOCK(runtime); } /* It is possible that any of the objects below have a finalizer that runs Python code or otherwise relies on a thread state or even the interpreter state. For now we trust that isn't a problem. */ // XXX Make sure we properly deal with problematic finalizers. Py_CLEAR(interp->audit_hooks); for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) { interp->monitors.tools[i] = 0; } for (int t = 0; t < PY_MONITORING_TOOL_IDS; t++) { for (int e = 0; e < PY_MONITORING_EVENTS; e++) { Py_CLEAR(interp->monitoring_callables[t][e]); } } interp->sys_profile_initialized = false; interp->sys_trace_initialized = false; for (int t = 0; t < PY_MONITORING_TOOL_IDS; t++) { Py_CLEAR(interp->monitoring_tool_names[t]); } PyConfig_Clear(&interp->config); Py_CLEAR(interp->codec_search_path); Py_CLEAR(interp->codec_search_cache); Py_CLEAR(interp->codec_error_registry); assert(interp->imports.modules == NULL); assert(interp->imports.modules_by_index == NULL); assert(interp->imports.importlib == NULL); assert(interp->imports.import_func == NULL); Py_CLEAR(interp->sysdict_copy); Py_CLEAR(interp->builtins_copy); Py_CLEAR(interp->dict); #ifdef HAVE_FORK Py_CLEAR(interp->before_forkers); Py_CLEAR(interp->after_forkers_parent); Py_CLEAR(interp->after_forkers_child); #endif _PyAST_Fini(interp); _PyWarnings_Fini(interp); _PyAtExit_Fini(interp); // All Python types must be destroyed before the last GC collection. Python // types create a reference cycle to themselves in their in their // PyTypeObject.tp_mro member (the tuple contains the type). /* Last garbage collection on this interpreter */ _PyGC_CollectNoFail(tstate); _PyGC_Fini(interp); /* We don't clear sysdict and builtins until the end of this function. Because clearing other attributes can execute arbitrary Python code which requires sysdict and builtins. */ PyDict_Clear(interp->sysdict); PyDict_Clear(interp->builtins); Py_CLEAR(interp->sysdict); Py_CLEAR(interp->builtins); Py_CLEAR(interp->interpreter_trampoline); for (int i=0; i < DICT_MAX_WATCHERS; i++) { interp->dict_state.watchers[i] = NULL; } for (int i=0; i < TYPE_MAX_WATCHERS; i++) { interp->type_watchers[i] = NULL; } for (int i=0; i < FUNC_MAX_WATCHERS; i++) { interp->func_watchers[i] = NULL; } interp->active_func_watchers = 0; for (int i=0; i < CODE_MAX_WATCHERS; i++) { interp->code_watchers[i] = NULL; } interp->active_code_watchers = 0; interp->f_opcode_trace_set = false; // XXX Once we have one allocator per interpreter (i.e. // per-interpreter GC) we must ensure that all of the interpreter's // objects have been cleaned up at the point. } void PyInterpreterState_Clear(PyInterpreterState *interp) { // Use the current Python thread state to call audit hooks and to collect // garbage. It can be different than the current Python thread state // of 'interp'. PyThreadState *current_tstate = current_fast_get(interp->runtime); _PyImport_ClearCore(interp); interpreter_clear(interp, current_tstate); } void _PyInterpreterState_Clear(PyThreadState *tstate) { _PyImport_ClearCore(tstate->interp); interpreter_clear(tstate->interp, tstate); } static void zapthreads(PyInterpreterState *interp); void PyInterpreterState_Delete(PyInterpreterState *interp) { _PyRuntimeState *runtime = interp->runtime; struct pyinterpreters *interpreters = &runtime->interpreters; // XXX Clearing the "current" thread state should happen before // we start finalizing the interpreter (or the current thread state). PyThreadState *tcur = current_fast_get(runtime); if (tcur != NULL && interp == tcur->interp) { /* Unset current thread. After this, many C API calls become crashy. */ _PyThreadState_Swap(runtime, NULL); } zapthreads(interp); _PyEval_FiniState(&interp->ceval); // XXX These two calls should be done at the end of clear_interpreter(), // but currently some objects get decref'ed after that. #ifdef Py_REF_DEBUG _PyInterpreterState_FinalizeRefTotal(interp); #endif _PyInterpreterState_FinalizeAllocatedBlocks(interp); HEAD_LOCK(runtime); PyInterpreterState **p; for (p = &interpreters->head; ; p = &(*p)->next) { if (*p == NULL) { Py_FatalError("NULL interpreter"); } if (*p == interp) { break; } } if (interp->threads.head != NULL) { Py_FatalError("remaining threads"); } *p = interp->next; if (interpreters->main == interp) { interpreters->main = NULL; if (interpreters->head != NULL) { Py_FatalError("remaining subinterpreters"); } } HEAD_UNLOCK(runtime); if (interp->id_mutex != NULL) { PyThread_free_lock(interp->id_mutex); } free_interpreter(interp); } #ifdef HAVE_FORK /* * Delete all interpreter states except the main interpreter. If there * is a current interpreter state, it *must* be the main interpreter. */ PyStatus _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime) { struct pyinterpreters *interpreters = &runtime->interpreters; PyThreadState *tstate = _PyThreadState_Swap(runtime, NULL); if (tstate != NULL && tstate->interp != interpreters->main) { return _PyStatus_ERR("not main interpreter"); } HEAD_LOCK(runtime); PyInterpreterState *interp = interpreters->head; interpreters->head = NULL; while (interp != NULL) { if (interp == interpreters->main) { interpreters->main->next = NULL; interpreters->head = interp; interp = interp->next; continue; } // XXX Won't this fail since PyInterpreterState_Clear() requires // the "current" tstate to be set? PyInterpreterState_Clear(interp); // XXX must activate? zapthreads(interp); if (interp->id_mutex != NULL) { PyThread_free_lock(interp->id_mutex); } PyInterpreterState *prev_interp = interp; interp = interp->next; free_interpreter(prev_interp); } HEAD_UNLOCK(runtime); if (interpreters->head == NULL) { return _PyStatus_ERR("missing main interpreter"); } _PyThreadState_Swap(runtime, tstate); return _PyStatus_OK(); } #endif //---------- // accessors //---------- int64_t PyInterpreterState_GetID(PyInterpreterState *interp) { if (interp == NULL) { PyErr_SetString(PyExc_RuntimeError, "no interpreter provided"); return -1; } return interp->id; } int _PyInterpreterState_IDInitref(PyInterpreterState *interp) { if (interp->id_mutex != NULL) { return 0; } interp->id_mutex = PyThread_allocate_lock(); if (interp->id_mutex == NULL) { PyErr_SetString(PyExc_RuntimeError, "failed to create init interpreter ID mutex"); return -1; } interp->id_refcount = 0; return 0; } int _PyInterpreterState_IDIncref(PyInterpreterState *interp) { if (_PyInterpreterState_IDInitref(interp) < 0) { return -1; } PyThread_acquire_lock(interp->id_mutex, WAIT_LOCK); interp->id_refcount += 1; PyThread_release_lock(interp->id_mutex); return 0; } void _PyInterpreterState_IDDecref(PyInterpreterState *interp) { assert(interp->id_mutex != NULL); _PyRuntimeState *runtime = interp->runtime; PyThread_acquire_lock(interp->id_mutex, WAIT_LOCK); assert(interp->id_refcount != 0); interp->id_refcount -= 1; int64_t refcount = interp->id_refcount; PyThread_release_lock(interp->id_mutex); if (refcount == 0 && interp->requires_idref) { // XXX Using the "head" thread isn't strictly correct. PyThreadState *tstate = PyInterpreterState_ThreadHead(interp); // XXX Possible GILState issues? PyThreadState *save_tstate = _PyThreadState_Swap(runtime, tstate); Py_EndInterpreter(tstate); _PyThreadState_Swap(runtime, save_tstate); } } int _PyInterpreterState_RequiresIDRef(PyInterpreterState *interp) { return interp->requires_idref; } void _PyInterpreterState_RequireIDRef(PyInterpreterState *interp, int required) { interp->requires_idref = required ? 1 : 0; } PyObject * _PyInterpreterState_GetMainModule(PyInterpreterState *interp) { PyObject *modules = _PyImport_GetModules(interp); if (modules == NULL) { PyErr_SetString(PyExc_RuntimeError, "interpreter not initialized"); return NULL; } return PyMapping_GetItemString(modules, "__main__"); } PyObject * PyInterpreterState_GetDict(PyInterpreterState *interp) { if (interp->dict == NULL) { interp->dict = PyDict_New(); if (interp->dict == NULL) { PyErr_Clear(); } } /* Returning NULL means no per-interpreter dict is available. */ return interp->dict; } //----------------------------- // look up an interpreter state //----------------------------- /* Return the interpreter associated with the current OS thread. The GIL must be held. */ PyInterpreterState * PyInterpreterState_Get(void) { PyThreadState *tstate = current_fast_get(&_PyRuntime); _Py_EnsureTstateNotNULL(tstate); PyInterpreterState *interp = tstate->interp; if (interp == NULL) { Py_FatalError("no current interpreter"); } return interp; } static PyInterpreterState * interp_look_up_id(_PyRuntimeState *runtime, int64_t requested_id) { PyInterpreterState *interp = runtime->interpreters.head; while (interp != NULL) { int64_t id = PyInterpreterState_GetID(interp); if (id < 0) { return NULL; } if (requested_id == id) { return interp; } interp = PyInterpreterState_Next(interp); } return NULL; } /* Return the interpreter state with the given ID. Fail with RuntimeError if the interpreter is not found. */ PyInterpreterState * _PyInterpreterState_LookUpID(int64_t requested_id) { PyInterpreterState *interp = NULL; if (requested_id >= 0) { _PyRuntimeState *runtime = &_PyRuntime; HEAD_LOCK(runtime); interp = interp_look_up_id(runtime, requested_id); HEAD_UNLOCK(runtime); } if (interp == NULL && !PyErr_Occurred()) { PyErr_Format(PyExc_RuntimeError, "unrecognized interpreter ID %lld", requested_id); } return interp; } /********************************/ /* the per-thread runtime state */ /********************************/ #ifndef NDEBUG static inline int tstate_is_alive(PyThreadState *tstate) { return (tstate->_status.initialized && !tstate->_status.finalized && !tstate->_status.cleared && !tstate->_status.finalizing); } #endif //---------- // lifecycle //---------- /* Minimum size of data stack chunk */ #define DATA_STACK_CHUNK_SIZE (16*1024) static _PyStackChunk* allocate_chunk(int size_in_bytes, _PyStackChunk* previous) { assert(size_in_bytes % sizeof(PyObject **) == 0); _PyStackChunk *res = _PyObject_VirtualAlloc(size_in_bytes); if (res == NULL) { return NULL; } res->previous = previous; res->size = size_in_bytes; res->top = 0; return res; } static PyThreadState * alloc_threadstate(void) { return PyMem_RawCalloc(1, sizeof(PyThreadState)); } static void free_threadstate(PyThreadState *tstate) { // The initial thread state of the interpreter is allocated // as part of the interpreter state so should not be freed. if (tstate != &tstate->interp->_initial_thread) { PyMem_RawFree(tstate); } } /* Get the thread state to a minimal consistent state. Further init happens in pylifecycle.c before it can be used. All fields not initialized here are expected to be zeroed out, e.g. by PyMem_RawCalloc() or memset(), or otherwise pre-initialized. The interpreter state is not manipulated. Instead it is assumed that the thread is getting added to the interpreter. */ static void init_threadstate(PyThreadState *tstate, PyInterpreterState *interp, uint64_t id) { if (tstate->_status.initialized) { Py_FatalError("thread state already initialized"); } assert(interp != NULL); tstate->interp = interp; // next/prev are set in add_threadstate(). assert(tstate->next == NULL); assert(tstate->prev == NULL); assert(id > 0); tstate->id = id; // thread_id and native_thread_id are set in bind_tstate(). tstate->py_recursion_limit = interp->ceval.recursion_limit, tstate->py_recursion_remaining = interp->ceval.recursion_limit, tstate->c_recursion_remaining = C_RECURSION_LIMIT; tstate->exc_info = &tstate->exc_state; // PyGILState_Release must not try to delete this thread state. // This is cleared when PyGILState_Ensure() creates the thread state. tstate->gilstate_counter = 1; tstate->cframe = &tstate->root_cframe; tstate->datastack_chunk = NULL; tstate->datastack_top = NULL; tstate->datastack_limit = NULL; tstate->what_event = -1; tstate->_status.initialized = 1; } static void add_threadstate(PyInterpreterState *interp, PyThreadState *tstate, PyThreadState *next) { assert(interp->threads.head != tstate); assert((next != NULL && tstate->id != 1) || (next == NULL && tstate->id == 1)); if (next != NULL) { assert(next->prev == NULL || next->prev == tstate); next->prev = tstate; } tstate->next = next; assert(tstate->prev == NULL); interp->threads.head = tstate; } static PyThreadState * new_threadstate(PyInterpreterState *interp) { PyThreadState *tstate; _PyRuntimeState *runtime = interp->runtime; // We don't need to allocate a thread state for the main interpreter // (the common case), but doing it later for the other case revealed a // reentrancy problem (deadlock). So for now we always allocate before // taking the interpreters lock. See GH-96071. PyThreadState *new_tstate = alloc_threadstate(); int used_newtstate; if (new_tstate == NULL) { return NULL; } /* We serialize concurrent creation to protect global state. */ HEAD_LOCK(runtime); interp->threads.next_unique_id += 1; uint64_t id = interp->threads.next_unique_id; // Allocate the thread state and add it to the interpreter. PyThreadState *old_head = interp->threads.head; if (old_head == NULL) { // It's the interpreter's initial thread state. assert(id == 1); used_newtstate = 0; tstate = &interp->_initial_thread; } else { // Every valid interpreter must have at least one thread. assert(id > 1); assert(old_head->prev == NULL); used_newtstate = 1; tstate = new_tstate; // Set to _PyThreadState_INIT. memcpy(tstate, &initial._main_interpreter._initial_thread, sizeof(*tstate)); } init_threadstate(tstate, interp, id); add_threadstate(interp, tstate, old_head); HEAD_UNLOCK(runtime); if (!used_newtstate) { // Must be called with lock unlocked to avoid re-entrancy deadlock. PyMem_RawFree(new_tstate); } return tstate; } PyThreadState * PyThreadState_New(PyInterpreterState *interp) { PyThreadState *tstate = new_threadstate(interp); if (tstate) { bind_tstate(tstate); // This makes sure there's a gilstate tstate bound // as soon as possible. if (gilstate_tss_get(tstate->interp->runtime) == NULL) { bind_gilstate_tstate(tstate); } } return tstate; } // This must be followed by a call to _PyThreadState_Bind(); PyThreadState * _PyThreadState_New(PyInterpreterState *interp) { return new_threadstate(interp); } // We keep this for stable ABI compabibility. PyThreadState * _PyThreadState_Prealloc(PyInterpreterState *interp) { return _PyThreadState_New(interp); } // We keep this around for (accidental) stable ABI compatibility. // Realistically, no extensions are using it. void _PyThreadState_Init(PyThreadState *tstate) { Py_FatalError("_PyThreadState_Init() is for internal use only"); } static void clear_datastack(PyThreadState *tstate) { _PyStackChunk *chunk = tstate->datastack_chunk; tstate->datastack_chunk = NULL; while (chunk != NULL) { _PyStackChunk *prev = chunk->previous; _PyObject_VirtualFree(chunk, chunk->size); chunk = prev; } } void PyThreadState_Clear(PyThreadState *tstate) { assert(tstate->_status.initialized && !tstate->_status.cleared); // XXX assert(!tstate->_status.bound || tstate->_status.unbound); tstate->_status.finalizing = 1; // just in case /* XXX Conditions we need to enforce: * the GIL must be held by the current thread * current_fast_get()->interp must match tstate->interp * for the main interpreter, current_fast_get() must be the main thread */ int verbose = _PyInterpreterState_GetConfig(tstate->interp)->verbose; if (verbose && tstate->cframe->current_frame != NULL) { /* bpo-20526: After the main thread calls _PyInterpreterState_SetFinalizing() in Py_FinalizeEx() (or in Py_EndInterpreter() for subinterpreters), threads must exit when trying to take the GIL. If a thread exit in the middle of _PyEval_EvalFrameDefault(), tstate->frame is not reset to its previous value. It is more likely with daemon threads, but it can happen with regular threads if threading._shutdown() fails (ex: interrupted by CTRL+C). */ fprintf(stderr, "PyThreadState_Clear: warning: thread still has a frame\n"); } /* At this point tstate shouldn't be used any more, neither to run Python code nor for other uses. This is tricky when current_fast_get() == tstate, in the same way as noted in interpreter_clear() above. The below finalizers can possibly run Python code or otherwise use the partially cleared thread state. For now we trust that isn't a problem in practice. */ // XXX Deal with the possibility of problematic finalizers. /* Don't clear tstate->pyframe: it is a borrowed reference */ Py_CLEAR(tstate->dict); Py_CLEAR(tstate->async_exc); Py_CLEAR(tstate->current_exception); Py_CLEAR(tstate->exc_state.exc_value); /* The stack of exception states should contain just this thread. */ if (verbose && tstate->exc_info != &tstate->exc_state) { fprintf(stderr, "PyThreadState_Clear: warning: thread still has a generator\n"); } if (tstate->c_profilefunc != NULL) { tstate->interp->sys_profiling_threads--; tstate->c_profilefunc = NULL; } if (tstate->c_tracefunc != NULL) { tstate->interp->sys_tracing_threads--; tstate->c_tracefunc = NULL; } Py_CLEAR(tstate->c_profileobj); Py_CLEAR(tstate->c_traceobj); Py_CLEAR(tstate->async_gen_firstiter); Py_CLEAR(tstate->async_gen_finalizer); Py_CLEAR(tstate->context); if (tstate->on_delete != NULL) { tstate->on_delete(tstate->on_delete_data); } tstate->_status.cleared = 1; // XXX Call _PyThreadStateSwap(runtime, NULL) here if "current". // XXX Do it as early in the function as possible. } /* Common code for PyThreadState_Delete() and PyThreadState_DeleteCurrent() */ static void tstate_delete_common(PyThreadState *tstate) { assert(tstate->_status.cleared && !tstate->_status.finalized); PyInterpreterState *interp = tstate->interp; if (interp == NULL) { Py_FatalError("NULL interpreter"); } _PyRuntimeState *runtime = interp->runtime; HEAD_LOCK(runtime); if (tstate->prev) { tstate->prev->next = tstate->next; } else { interp->threads.head = tstate->next; } if (tstate->next) { tstate->next->prev = tstate->prev; } HEAD_UNLOCK(runtime); // XXX Unbind in PyThreadState_Clear(), or earlier // (and assert not-equal here)? if (tstate->_status.bound_gilstate) { unbind_gilstate_tstate(tstate); } unbind_tstate(tstate); // XXX Move to PyThreadState_Clear()? clear_datastack(tstate); tstate->_status.finalized = 1; } static void zapthreads(PyInterpreterState *interp) { PyThreadState *tstate; /* No need to lock the mutex here because this should only happen when the threads are all really dead (XXX famous last words). */ while ((tstate = interp->threads.head) != NULL) { tstate_verify_not_active(tstate); tstate_delete_common(tstate); free_threadstate(tstate); } } void PyThreadState_Delete(PyThreadState *tstate) { _Py_EnsureTstateNotNULL(tstate); tstate_verify_not_active(tstate); tstate_delete_common(tstate); free_threadstate(tstate); } void _PyThreadState_DeleteCurrent(PyThreadState *tstate) { _Py_EnsureTstateNotNULL(tstate); tstate_delete_common(tstate); current_fast_clear(tstate->interp->runtime); _PyEval_ReleaseLock(tstate); free_threadstate(tstate); } void PyThreadState_DeleteCurrent(void) { PyThreadState *tstate = current_fast_get(&_PyRuntime); _PyThreadState_DeleteCurrent(tstate); } /* * Delete all thread states except the one passed as argument. * Note that, if there is a current thread state, it *must* be the one * passed as argument. Also, this won't touch any other interpreters * than the current one, since we don't know which thread state should * be kept in those other interpreters. */ void _PyThreadState_DeleteExcept(PyThreadState *tstate) { assert(tstate != NULL); PyInterpreterState *interp = tstate->interp; _PyRuntimeState *runtime = interp->runtime; HEAD_LOCK(runtime); /* Remove all thread states, except tstate, from the linked list of thread states. This will allow calling PyThreadState_Clear() without holding the lock. */ PyThreadState *list = interp->threads.head; if (list == tstate) { list = tstate->next; } if (tstate->prev) { tstate->prev->next = tstate->next; } if (tstate->next) { tstate->next->prev = tstate->prev; } tstate->prev = tstate->next = NULL; interp->threads.head = tstate; HEAD_UNLOCK(runtime); /* Clear and deallocate all stale thread states. Even if this executes Python code, we should be safe since it executes in the current thread, not one of the stale threads. */ PyThreadState *p, *next; for (p = list; p; p = next) { next = p->next; PyThreadState_Clear(p); free_threadstate(p); } } //------------------------- // "detached" thread states //------------------------- void _PyThreadState_InitDetached(PyThreadState *tstate, PyInterpreterState *interp) { _PyRuntimeState *runtime = interp->runtime; HEAD_LOCK(runtime); interp->threads.next_unique_id += 1; uint64_t id = interp->threads.next_unique_id; HEAD_UNLOCK(runtime); init_threadstate(tstate, interp, id); // We do not call add_threadstate(). } void _PyThreadState_ClearDetached(PyThreadState *tstate) { assert(!tstate->_status.bound); assert(!tstate->_status.bound_gilstate); assert(tstate->datastack_chunk == NULL); assert(tstate->thread_id == 0); assert(tstate->native_thread_id == 0); assert(tstate->next == NULL); assert(tstate->prev == NULL); PyThreadState_Clear(tstate); clear_datastack(tstate); } void _PyThreadState_BindDetached(PyThreadState *tstate) { assert(!_Py_IsMainInterpreter( current_fast_get(tstate->interp->runtime)->interp)); assert(_Py_IsMainInterpreter(tstate->interp)); bind_tstate(tstate); /* Unlike _PyThreadState_Bind(), we do not modify gilstate TSS. */ } void _PyThreadState_UnbindDetached(PyThreadState *tstate) { assert(!_Py_IsMainInterpreter( current_fast_get(tstate->interp->runtime)->interp)); assert(_Py_IsMainInterpreter(tstate->interp)); assert(tstate_is_alive(tstate)); assert(!tstate->_status.active); assert(gilstate_tss_get(tstate->interp->runtime) != tstate); unbind_tstate(tstate); /* This thread state may be bound/unbound repeatedly, so we must erase evidence that it was ever bound (or unbound). */ tstate->_status.bound = 0; tstate->_status.unbound = 0; /* We must fully unlink the thread state from any OS thread, to allow it to be bound more than once. */ tstate->thread_id = 0; #ifdef PY_HAVE_THREAD_NATIVE_ID tstate->native_thread_id = 0; #endif } //---------- // accessors //---------- /* An extension mechanism to store arbitrary additional per-thread state. PyThreadState_GetDict() returns a dictionary that can be used to hold such state; the caller should pick a unique key and store its state there. If PyThreadState_GetDict() returns NULL, an exception has *not* been raised and the caller should assume no per-thread state is available. */ PyObject * _PyThreadState_GetDict(PyThreadState *tstate) { assert(tstate != NULL); if (tstate->dict == NULL) { tstate->dict = PyDict_New(); if (tstate->dict == NULL) { _PyErr_Clear(tstate); } } return tstate->dict; } PyObject * PyThreadState_GetDict(void) { PyThreadState *tstate = current_fast_get(&_PyRuntime); if (tstate == NULL) { return NULL; } return _PyThreadState_GetDict(tstate); } PyInterpreterState * PyThreadState_GetInterpreter(PyThreadState *tstate) { assert(tstate != NULL); return tstate->interp; } PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate) { assert(tstate != NULL); _PyInterpreterFrame *f = _PyThreadState_GetFrame(tstate); if (f == NULL) { return NULL; } PyFrameObject *frame = _PyFrame_GetFrameObject(f); if (frame == NULL) { PyErr_Clear(); } return (PyFrameObject*)Py_XNewRef(frame); } uint64_t PyThreadState_GetID(PyThreadState *tstate) { assert(tstate != NULL); return tstate->id; } static inline void tstate_activate(PyThreadState *tstate) { assert(tstate != NULL); // XXX assert(tstate_is_alive(tstate)); assert(tstate_is_bound(tstate)); assert(!tstate->_status.active); assert(!tstate->_status.bound_gilstate || tstate == gilstate_tss_get((tstate->interp->runtime))); if (!tstate->_status.bound_gilstate) { bind_gilstate_tstate(tstate); } tstate->_status.active = 1; } static inline void tstate_deactivate(PyThreadState *tstate) { assert(tstate != NULL); // XXX assert(tstate_is_alive(tstate)); assert(tstate_is_bound(tstate)); assert(tstate->_status.active); tstate->_status.active = 0; // We do not unbind the gilstate tstate here. // It will still be used in PyGILState_Ensure(). } //---------- // other API //---------- /* Asynchronously raise an exception in a thread. Requested by Just van Rossum and Alex Martelli. To prevent naive misuse, you must write your own extension to call this, or use ctypes. Must be called with the GIL held. Returns the number of tstates modified (normally 1, but 0 if `id` didn't match any known thread id). Can be called with exc=NULL to clear an existing async exception. This raises no exceptions. */ // XXX Move this to Python/ceval_gil.c? // XXX Deprecate this. int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc) { _PyRuntimeState *runtime = &_PyRuntime; PyInterpreterState *interp = _PyInterpreterState_GET(); /* Although the GIL is held, a few C API functions can be called * without the GIL held, and in particular some that create and * destroy thread and interpreter states. Those can mutate the * list of thread states we're traversing, so to prevent that we lock * head_mutex for the duration. */ HEAD_LOCK(runtime); for (PyThreadState *tstate = interp->threads.head; tstate != NULL; tstate = tstate->next) { if (tstate->thread_id != id) { continue; } /* Tricky: we need to decref the current value * (if any) in tstate->async_exc, but that can in turn * allow arbitrary Python code to run, including * perhaps calls to this function. To prevent * deadlock, we need to release head_mutex before * the decref. */ PyObject *old_exc = tstate->async_exc; tstate->async_exc = Py_XNewRef(exc); HEAD_UNLOCK(runtime); Py_XDECREF(old_exc); _PyEval_SignalAsyncExc(tstate->interp); return 1; } HEAD_UNLOCK(runtime); return 0; } //--------------------------------- // API for the current thread state //--------------------------------- PyThreadState * _PyThreadState_UncheckedGet(void) { return current_fast_get(&_PyRuntime); } PyThreadState * PyThreadState_Get(void) { PyThreadState *tstate = current_fast_get(&_PyRuntime); _Py_EnsureTstateNotNULL(tstate); return tstate; } static void _swap_thread_states(_PyRuntimeState *runtime, PyThreadState *oldts, PyThreadState *newts) { // XXX Do this only if oldts != NULL? current_fast_clear(runtime); if (oldts != NULL) { // XXX assert(tstate_is_alive(oldts) && tstate_is_bound(oldts)); tstate_deactivate(oldts); } if (newts != NULL) { // XXX assert(tstate_is_alive(newts)); assert(tstate_is_bound(newts)); current_fast_set(runtime, newts); tstate_activate(newts); } } PyThreadState * _PyThreadState_SwapNoGIL(PyThreadState *newts) { #if defined(Py_DEBUG) /* This can be called from PyEval_RestoreThread(). Similar to it, we need to ensure errno doesn't change. */ int err = errno; #endif PyThreadState *oldts = current_fast_get(&_PyRuntime); _swap_thread_states(&_PyRuntime, oldts, newts); #if defined(Py_DEBUG) errno = err; #endif return oldts; } PyThreadState * _PyThreadState_Swap(_PyRuntimeState *runtime, PyThreadState *newts) { PyThreadState *oldts = current_fast_get(runtime); if (oldts != NULL) { _PyEval_ReleaseLock(oldts); } _swap_thread_states(runtime, oldts, newts); if (newts != NULL) { _PyEval_AcquireLock(newts); } return oldts; } PyThreadState * PyThreadState_Swap(PyThreadState *newts) { return _PyThreadState_Swap(&_PyRuntime, newts); } void _PyThreadState_Bind(PyThreadState *tstate) { bind_tstate(tstate); // This makes sure there's a gilstate tstate bound // as soon as possible. if (gilstate_tss_get(tstate->interp->runtime) == NULL) { bind_gilstate_tstate(tstate); } } /***********************************/ /* routines for advanced debuggers */ /***********************************/ // (requested by David Beazley) // Don't use unless you know what you are doing! PyInterpreterState * PyInterpreterState_Head(void) { return _PyRuntime.interpreters.head; } PyInterpreterState * PyInterpreterState_Main(void) { return _PyInterpreterState_Main(); } PyInterpreterState * PyInterpreterState_Next(PyInterpreterState *interp) { return interp->next; } PyThreadState * PyInterpreterState_ThreadHead(PyInterpreterState *interp) { return interp->threads.head; } PyThreadState * PyThreadState_Next(PyThreadState *tstate) { return tstate->next; } /********************************************/ /* reporting execution state of all threads */ /********************************************/ /* The implementation of sys._current_frames(). This is intended to be called with the GIL held, as it will be when called via sys._current_frames(). It's possible it would work fine even without the GIL held, but haven't thought enough about that. */ PyObject * _PyThread_CurrentFrames(void) { _PyRuntimeState *runtime = &_PyRuntime; PyThreadState *tstate = current_fast_get(runtime); if (_PySys_Audit(tstate, "sys._current_frames", NULL) < 0) { return NULL; } PyObject *result = PyDict_New(); if (result == NULL) { return NULL; } /* for i in all interpreters: * for t in all of i's thread states: * if t's frame isn't NULL, map t's id to its frame * Because these lists can mutate even when the GIL is held, we * need to grab head_mutex for the duration. */ HEAD_LOCK(runtime); PyInterpreterState *i; for (i = runtime->interpreters.head; i != NULL; i = i->next) { PyThreadState *t; for (t = i->threads.head; t != NULL; t = t->next) { _PyInterpreterFrame *frame = t->cframe->current_frame; frame = _PyFrame_GetFirstComplete(frame); if (frame == NULL) { continue; } PyObject *id = PyLong_FromUnsignedLong(t->thread_id); if (id == NULL) { goto fail; } PyObject *frameobj = (PyObject *)_PyFrame_GetFrameObject(frame); if (frameobj == NULL) { Py_DECREF(id); goto fail; } int stat = PyDict_SetItem(result, id, frameobj); Py_DECREF(id); if (stat < 0) { goto fail; } } } goto done; fail: Py_CLEAR(result); done: HEAD_UNLOCK(runtime); return result; } /* The implementation of sys._current_exceptions(). This is intended to be called with the GIL held, as it will be when called via sys._current_exceptions(). It's possible it would work fine even without the GIL held, but haven't thought enough about that. */ PyObject * _PyThread_CurrentExceptions(void) { _PyRuntimeState *runtime = &_PyRuntime; PyThreadState *tstate = current_fast_get(runtime); _Py_EnsureTstateNotNULL(tstate); if (_PySys_Audit(tstate, "sys._current_exceptions", NULL) < 0) { return NULL; } PyObject *result = PyDict_New(); if (result == NULL) { return NULL; } /* for i in all interpreters: * for t in all of i's thread states: * if t's frame isn't NULL, map t's id to its frame * Because these lists can mutate even when the GIL is held, we * need to grab head_mutex for the duration. */ HEAD_LOCK(runtime); PyInterpreterState *i; for (i = runtime->interpreters.head; i != NULL; i = i->next) { PyThreadState *t; for (t = i->threads.head; t != NULL; t = t->next) { _PyErr_StackItem *err_info = _PyErr_GetTopmostException(t); if (err_info == NULL) { continue; } PyObject *id = PyLong_FromUnsignedLong(t->thread_id); if (id == NULL) { goto fail; } PyObject *exc = err_info->exc_value; assert(exc == NULL || exc == Py_None || PyExceptionInstance_Check(exc)); int stat = PyDict_SetItem(result, id, exc == NULL ? Py_None : exc); Py_DECREF(id); if (stat < 0) { goto fail; } } } goto done; fail: Py_CLEAR(result); done: HEAD_UNLOCK(runtime); return result; } /***********************************/ /* Python "auto thread state" API. */ /***********************************/ /* Internal initialization/finalization functions called by Py_Initialize/Py_FinalizeEx */ PyStatus _PyGILState_Init(PyInterpreterState *interp) { if (!_Py_IsMainInterpreter(interp)) { /* Currently, PyGILState is shared by all interpreters. The main * interpreter is responsible to initialize it. */ return _PyStatus_OK(); } _PyRuntimeState *runtime = interp->runtime; assert(gilstate_tss_get(runtime) == NULL); assert(runtime->gilstate.autoInterpreterState == NULL); runtime->gilstate.autoInterpreterState = interp; return _PyStatus_OK(); } void _PyGILState_Fini(PyInterpreterState *interp) { if (!_Py_IsMainInterpreter(interp)) { /* Currently, PyGILState is shared by all interpreters. The main * interpreter is responsible to initialize it. */ return; } interp->runtime->gilstate.autoInterpreterState = NULL; } // XXX Drop this. PyStatus _PyGILState_SetTstate(PyThreadState *tstate) { /* must init with valid states */ assert(tstate != NULL); assert(tstate->interp != NULL); if (!_Py_IsMainInterpreter(tstate->interp)) { /* Currently, PyGILState is shared by all interpreters. The main * interpreter is responsible to initialize it. */ return _PyStatus_OK(); } #ifndef NDEBUG _PyRuntimeState *runtime = tstate->interp->runtime; assert(runtime->gilstate.autoInterpreterState == tstate->interp); assert(gilstate_tss_get(runtime) == tstate); assert(tstate->gilstate_counter == 1); #endif return _PyStatus_OK(); } PyInterpreterState * _PyGILState_GetInterpreterStateUnsafe(void) { return _PyRuntime.gilstate.autoInterpreterState; } /* The public functions */ PyThreadState * PyGILState_GetThisThreadState(void) { _PyRuntimeState *runtime = &_PyRuntime; if (!gilstate_tss_initialized(runtime)) { return NULL; } return gilstate_tss_get(runtime); } int PyGILState_Check(void) { _PyRuntimeState *runtime = &_PyRuntime; if (!runtime->gilstate.check_enabled) { return 1; } if (!gilstate_tss_initialized(runtime)) { return 1; } PyThreadState *tstate = current_fast_get(runtime); if (tstate == NULL) { return 0; } return (tstate == gilstate_tss_get(runtime)); } PyGILState_STATE PyGILState_Ensure(void) { _PyRuntimeState *runtime = &_PyRuntime; /* Note that we do not auto-init Python here - apart from potential races with 2 threads auto-initializing, pep-311 spells out other issues. Embedders are expected to have called Py_Initialize(). */ /* Ensure that _PyEval_InitThreads() and _PyGILState_Init() have been called by Py_Initialize() */ assert(_PyEval_ThreadsInitialized()); assert(gilstate_tss_initialized(runtime)); assert(runtime->gilstate.autoInterpreterState != NULL); PyThreadState *tcur = gilstate_tss_get(runtime); int has_gil; if (tcur == NULL) { /* Create a new Python thread state for this thread */ tcur = new_threadstate(runtime->gilstate.autoInterpreterState); if (tcur == NULL) { Py_FatalError("Couldn't create thread-state for new thread"); } bind_tstate(tcur); bind_gilstate_tstate(tcur); /* This is our thread state! We'll need to delete it in the matching call to PyGILState_Release(). */ assert(tcur->gilstate_counter == 1); tcur->gilstate_counter = 0; has_gil = 0; /* new thread state is never current */ } else { has_gil = holds_gil(tcur); } if (!has_gil) { PyEval_RestoreThread(tcur); } /* Update our counter in the thread-state - no need for locks: - tcur will remain valid as we hold the GIL. - the counter is safe as we are the only thread "allowed" to modify this value */ ++tcur->gilstate_counter; return has_gil ? PyGILState_LOCKED : PyGILState_UNLOCKED; } void PyGILState_Release(PyGILState_STATE oldstate) { _PyRuntimeState *runtime = &_PyRuntime; PyThreadState *tstate = gilstate_tss_get(runtime); if (tstate == NULL) { Py_FatalError("auto-releasing thread-state, " "but no thread-state for this thread"); } /* We must hold the GIL and have our thread state current */ /* XXX - remove the check - the assert should be fine, but while this is very new (April 2003), the extra check by release-only users can't hurt. */ if (!holds_gil(tstate)) { _Py_FatalErrorFormat(__func__, "thread state %p must be current when releasing", tstate); } assert(holds_gil(tstate)); --tstate->gilstate_counter; assert(tstate->gilstate_counter >= 0); /* illegal counter value */ /* If we're going to destroy this thread-state, we must * clear it while the GIL is held, as destructors may run. */ if (tstate->gilstate_counter == 0) { /* can't have been locked when we created it */ assert(oldstate == PyGILState_UNLOCKED); // XXX Unbind tstate here. PyThreadState_Clear(tstate); /* Delete the thread-state. Note this releases the GIL too! * It's vital that the GIL be held here, to avoid shutdown * races; see bugs 225673 and 1061968 (that nasty bug has a * habit of coming back). */ assert(current_fast_get(runtime) == tstate); _PyThreadState_DeleteCurrent(tstate); } /* Release the lock if necessary */ else if (oldstate == PyGILState_UNLOCKED) { PyEval_SaveThread(); } } /**************************/ /* cross-interpreter data */ /**************************/ /* cross-interpreter data */ static inline void _xidata_init(_PyCrossInterpreterData *data) { // If the value is being reused // then _xidata_clear() should have been called already. assert(data->data == NULL); assert(data->obj == NULL); *data = (_PyCrossInterpreterData){0}; data->interp = -1; } static inline void _xidata_clear(_PyCrossInterpreterData *data) { if (data->free != NULL) { data->free(data->data); } data->data = NULL; Py_CLEAR(data->obj); } void _PyCrossInterpreterData_Init(_PyCrossInterpreterData *data, PyInterpreterState *interp, void *shared, PyObject *obj, xid_newobjectfunc new_object) { assert(data != NULL); assert(new_object != NULL); _xidata_init(data); data->data = shared; if (obj != NULL) { assert(interp != NULL); // released in _PyCrossInterpreterData_Clear() data->obj = Py_NewRef(obj); } // Ideally every object would know its owning interpreter. // Until then, we have to rely on the caller to identify it // (but we don't need it in all cases). data->interp = (interp != NULL) ? interp->id : -1; data->new_object = new_object; } int _PyCrossInterpreterData_InitWithSize(_PyCrossInterpreterData *data, PyInterpreterState *interp, const size_t size, PyObject *obj, xid_newobjectfunc new_object) { assert(size > 0); // For now we always free the shared data in the same interpreter // where it was allocated, so the interpreter is required. assert(interp != NULL); _PyCrossInterpreterData_Init(data, interp, NULL, obj, new_object); data->data = PyMem_RawMalloc(size); if (data->data == NULL) { return -1; } data->free = PyMem_RawFree; return 0; } void _PyCrossInterpreterData_Clear(PyInterpreterState *interp, _PyCrossInterpreterData *data) { assert(data != NULL); // This must be called in the owning interpreter. assert(interp == NULL || data->interp == interp->id); _xidata_clear(data); } static int _check_xidata(PyThreadState *tstate, _PyCrossInterpreterData *data) { // data->data can be anything, including NULL, so we don't check it. // data->obj may be NULL, so we don't check it. if (data->interp < 0) { _PyErr_SetString(tstate, PyExc_SystemError, "missing interp"); return -1; } if (data->new_object == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, "missing new_object func"); return -1; } // data->free may be NULL, so we don't check it. return 0; } crossinterpdatafunc _PyCrossInterpreterData_Lookup(PyObject *); /* This is a separate func from _PyCrossInterpreterData_Lookup in order to keep the registry code separate. */ static crossinterpdatafunc _lookup_getdata(PyObject *obj) { crossinterpdatafunc getdata = _PyCrossInterpreterData_Lookup(obj); if (getdata == NULL && PyErr_Occurred() == 0) PyErr_Format(PyExc_ValueError, "%S does not support cross-interpreter data", obj); return getdata; } int _PyObject_CheckCrossInterpreterData(PyObject *obj) { crossinterpdatafunc getdata = _lookup_getdata(obj); if (getdata == NULL) { return -1; } return 0; } int _PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data) { _PyRuntimeState *runtime = &_PyRuntime; PyThreadState *tstate = current_fast_get(runtime); #ifdef Py_DEBUG // The caller must hold the GIL _Py_EnsureTstateNotNULL(tstate); #endif PyInterpreterState *interp = tstate->interp; // Reset data before re-populating. *data = (_PyCrossInterpreterData){0}; data->interp = -1; // Call the "getdata" func for the object. Py_INCREF(obj); crossinterpdatafunc getdata = _lookup_getdata(obj); if (getdata == NULL) { Py_DECREF(obj); return -1; } int res = getdata(tstate, obj, data); Py_DECREF(obj); if (res != 0) { return -1; } // Fill in the blanks and validate the result. data->interp = interp->id; if (_check_xidata(tstate, data) != 0) { (void)_PyCrossInterpreterData_Release(data); return -1; } return 0; } PyObject * _PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *data) { return data->new_object(data); } typedef void (*releasefunc)(PyInterpreterState *, void *); static void _call_in_interpreter(PyInterpreterState *interp, releasefunc func, void *arg) { /* We would use Py_AddPendingCall() if it weren't specific to the * main interpreter (see bpo-33608). In the meantime we take a * naive approach. */ _PyRuntimeState *runtime = interp->runtime; PyThreadState *save_tstate = NULL; if (interp != current_fast_get(runtime)->interp) { // XXX Using the "head" thread isn't strictly correct. PyThreadState *tstate = PyInterpreterState_ThreadHead(interp); // XXX Possible GILState issues? save_tstate = _PyThreadState_Swap(runtime, tstate); } // XXX Once the GIL is per-interpreter, this should be called with the // calling interpreter's GIL released and the target interpreter's held. func(interp, arg); // Switch back. if (save_tstate != NULL) { _PyThreadState_Swap(runtime, save_tstate); } } int _PyCrossInterpreterData_Release(_PyCrossInterpreterData *data) { if (data->free == NULL && data->obj == NULL) { // Nothing to release! data->data = NULL; return 0; } // Switch to the original interpreter. PyInterpreterState *interp = _PyInterpreterState_LookUpID(data->interp); if (interp == NULL) { // The interpreter was already destroyed. // This function shouldn't have been called. // XXX Someone leaked some memory... assert(PyErr_Occurred()); return -1; } // "Release" the data and/or the object. _call_in_interpreter(interp, (releasefunc)_PyCrossInterpreterData_Clear, data); return 0; } /* registry of {type -> crossinterpdatafunc} */ /* For now we use a global registry of shareable classes. An alternative would be to add a tp_* slot for a class's crossinterpdatafunc. It would be simpler and more efficient. */ static int _xidregistry_add_type(struct _xidregistry *xidregistry, PyTypeObject *cls, crossinterpdatafunc getdata) { // Note that we effectively replace already registered classes // rather than failing. struct _xidregitem *newhead = PyMem_RawMalloc(sizeof(struct _xidregitem)); if (newhead == NULL) { return -1; } // XXX Assign a callback to clear the entry from the registry? newhead->cls = PyWeakref_NewRef((PyObject *)cls, NULL); if (newhead->cls == NULL) { PyMem_RawFree(newhead); return -1; } newhead->getdata = getdata; newhead->prev = NULL; newhead->next = xidregistry->head; if (newhead->next != NULL) { newhead->next->prev = newhead; } xidregistry->head = newhead; return 0; } static struct _xidregitem * _xidregistry_remove_entry(struct _xidregistry *xidregistry, struct _xidregitem *entry) { struct _xidregitem *next = entry->next; if (entry->prev != NULL) { assert(entry->prev->next == entry); entry->prev->next = next; } else { assert(xidregistry->head == entry); xidregistry->head = next; } if (next != NULL) { next->prev = entry->prev; } Py_DECREF(entry->cls); PyMem_RawFree(entry); return next; } static struct _xidregitem * _xidregistry_find_type(struct _xidregistry *xidregistry, PyTypeObject *cls) { struct _xidregitem *cur = xidregistry->head; while (cur != NULL) { PyObject *registered = PyWeakref_GetObject(cur->cls); if (registered == Py_None) { // The weakly ref'ed object was freed. cur = _xidregistry_remove_entry(xidregistry, cur); } else { assert(PyType_Check(registered)); if (registered == (PyObject *)cls) { return cur; } cur = cur->next; } } return NULL; } static void _register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry); int _PyCrossInterpreterData_RegisterClass(PyTypeObject *cls, crossinterpdatafunc getdata) { if (!PyType_Check(cls)) { PyErr_Format(PyExc_ValueError, "only classes may be registered"); return -1; } if (getdata == NULL) { PyErr_Format(PyExc_ValueError, "missing 'getdata' func"); return -1; } struct _xidregistry *xidregistry = &_PyRuntime.xidregistry ; PyThread_acquire_lock(xidregistry->mutex, WAIT_LOCK); if (xidregistry->head == NULL) { _register_builtins_for_crossinterpreter_data(xidregistry); } int res = _xidregistry_add_type(xidregistry, cls, getdata); PyThread_release_lock(xidregistry->mutex); return res; } int _PyCrossInterpreterData_UnregisterClass(PyTypeObject *cls) { int res = 0; struct _xidregistry *xidregistry = &_PyRuntime.xidregistry ; PyThread_acquire_lock(xidregistry->mutex, WAIT_LOCK); struct _xidregitem *matched = _xidregistry_find_type(xidregistry, cls); if (matched != NULL) { (void)_xidregistry_remove_entry(xidregistry, matched); res = 1; } PyThread_release_lock(xidregistry->mutex); return res; } /* Cross-interpreter objects are looked up by exact match on the class. We can reassess this policy when we move from a global registry to a tp_* slot. */ crossinterpdatafunc _PyCrossInterpreterData_Lookup(PyObject *obj) { struct _xidregistry *xidregistry = &_PyRuntime.xidregistry ; PyObject *cls = PyObject_Type(obj); PyThread_acquire_lock(xidregistry->mutex, WAIT_LOCK); if (xidregistry->head == NULL) { _register_builtins_for_crossinterpreter_data(xidregistry); } struct _xidregitem *matched = _xidregistry_find_type(xidregistry, (PyTypeObject *)cls); Py_DECREF(cls); PyThread_release_lock(xidregistry->mutex); return matched != NULL ? matched->getdata : NULL; } /* cross-interpreter data for builtin types */ struct _shared_bytes_data { char *bytes; Py_ssize_t len; }; static PyObject * _new_bytes_object(_PyCrossInterpreterData *data) { struct _shared_bytes_data *shared = (struct _shared_bytes_data *)(data->data); return PyBytes_FromStringAndSize(shared->bytes, shared->len); } static int _bytes_shared(PyThreadState *tstate, PyObject *obj, _PyCrossInterpreterData *data) { if (_PyCrossInterpreterData_InitWithSize( data, tstate->interp, sizeof(struct _shared_bytes_data), obj, _new_bytes_object ) < 0) { return -1; } struct _shared_bytes_data *shared = (struct _shared_bytes_data *)data->data; if (PyBytes_AsStringAndSize(obj, &shared->bytes, &shared->len) < 0) { _PyCrossInterpreterData_Clear(tstate->interp, data); return -1; } return 0; } struct _shared_str_data { int kind; const void *buffer; Py_ssize_t len; }; static PyObject * _new_str_object(_PyCrossInterpreterData *data) { struct _shared_str_data *shared = (struct _shared_str_data *)(data->data); return PyUnicode_FromKindAndData(shared->kind, shared->buffer, shared->len); } static int _str_shared(PyThreadState *tstate, PyObject *obj, _PyCrossInterpreterData *data) { if (_PyCrossInterpreterData_InitWithSize( data, tstate->interp, sizeof(struct _shared_str_data), obj, _new_str_object ) < 0) { return -1; } struct _shared_str_data *shared = (struct _shared_str_data *)data->data; shared->kind = PyUnicode_KIND(obj); shared->buffer = PyUnicode_DATA(obj); shared->len = PyUnicode_GET_LENGTH(obj); return 0; } static PyObject * _new_long_object(_PyCrossInterpreterData *data) { return PyLong_FromSsize_t((Py_ssize_t)(data->data)); } static int _long_shared(PyThreadState *tstate, PyObject *obj, _PyCrossInterpreterData *data) { /* Note that this means the size of shareable ints is bounded by * sys.maxsize. Hence on 32-bit architectures that is half the * size of maximum shareable ints on 64-bit. */ Py_ssize_t value = PyLong_AsSsize_t(obj); if (value == -1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) { PyErr_SetString(PyExc_OverflowError, "try sending as bytes"); } return -1; } _PyCrossInterpreterData_Init(data, tstate->interp, (void *)value, NULL, _new_long_object); // data->obj and data->free remain NULL return 0; } static PyObject * _new_none_object(_PyCrossInterpreterData *data) { // XXX Singleton refcounts are problematic across interpreters... return Py_NewRef(Py_None); } static int _none_shared(PyThreadState *tstate, PyObject *obj, _PyCrossInterpreterData *data) { _PyCrossInterpreterData_Init(data, tstate->interp, NULL, NULL, _new_none_object); // data->data, data->obj and data->free remain NULL return 0; } static void _register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry) { // None if (_xidregistry_add_type(xidregistry, (PyTypeObject *)PyObject_Type(Py_None), _none_shared) != 0) { Py_FatalError("could not register None for cross-interpreter sharing"); } // int if (_xidregistry_add_type(xidregistry, &PyLong_Type, _long_shared) != 0) { Py_FatalError("could not register int for cross-interpreter sharing"); } // bytes if (_xidregistry_add_type(xidregistry, &PyBytes_Type, _bytes_shared) != 0) { Py_FatalError("could not register bytes for cross-interpreter sharing"); } // str if (_xidregistry_add_type(xidregistry, &PyUnicode_Type, _str_shared) != 0) { Py_FatalError("could not register str for cross-interpreter sharing"); } } _PyFrameEvalFunction _PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp) { if (interp->eval_frame == NULL) { return _PyEval_EvalFrameDefault; } return interp->eval_frame; } void _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, _PyFrameEvalFunction eval_frame) { if (eval_frame == _PyEval_EvalFrameDefault) { interp->eval_frame = NULL; } else { interp->eval_frame = eval_frame; } } const PyConfig* _PyInterpreterState_GetConfig(PyInterpreterState *interp) { return &interp->config; } int _PyInterpreterState_GetConfigCopy(PyConfig *config) { PyInterpreterState *interp = PyInterpreterState_Get(); PyStatus status = _PyConfig_Copy(config, &interp->config); if (PyStatus_Exception(status)) { _PyErr_SetFromPyStatus(status); return -1; } return 0; } const PyConfig* _Py_GetConfig(void) { _PyRuntimeState *runtime = &_PyRuntime; assert(PyGILState_Check()); PyThreadState *tstate = current_fast_get(runtime); _Py_EnsureTstateNotNULL(tstate); return _PyInterpreterState_GetConfig(tstate->interp); } int _PyInterpreterState_HasFeature(PyInterpreterState *interp, unsigned long feature) { return ((interp->feature_flags & feature) != 0); } #define MINIMUM_OVERHEAD 1000 static PyObject ** push_chunk(PyThreadState *tstate, int size) { int allocate_size = DATA_STACK_CHUNK_SIZE; while (allocate_size < (int)sizeof(PyObject*)*(size + MINIMUM_OVERHEAD)) { allocate_size *= 2; } _PyStackChunk *new = allocate_chunk(allocate_size, tstate->datastack_chunk); if (new == NULL) { return NULL; } if (tstate->datastack_chunk) { tstate->datastack_chunk->top = tstate->datastack_top - &tstate->datastack_chunk->data[0]; } tstate->datastack_chunk = new; tstate->datastack_limit = (PyObject **)(((char *)new) + allocate_size); // When new is the "root" chunk (i.e. new->previous == NULL), we can keep // _PyThreadState_PopFrame from freeing it later by "skipping" over the // first element: PyObject **res = &new->data[new->previous == NULL]; tstate->datastack_top = res + size; return res; } _PyInterpreterFrame * _PyThreadState_PushFrame(PyThreadState *tstate, size_t size) { assert(size < INT_MAX/sizeof(PyObject *)); if (_PyThreadState_HasStackSpace(tstate, (int)size)) { _PyInterpreterFrame *res = (_PyInterpreterFrame *)tstate->datastack_top; tstate->datastack_top += size; return res; } return (_PyInterpreterFrame *)push_chunk(tstate, (int)size); } void _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame * frame) { assert(tstate->datastack_chunk); PyObject **base = (PyObject **)frame; if (base == &tstate->datastack_chunk->data[0]) { _PyStackChunk *chunk = tstate->datastack_chunk; _PyStackChunk *previous = chunk->previous; // push_chunk ensures that the root chunk is never popped: assert(previous); tstate->datastack_top = &previous->data[previous->top]; tstate->datastack_chunk = previous; _PyObject_VirtualFree(chunk, chunk->size); tstate->datastack_limit = (PyObject **)(((char *)previous) + previous->size); } else { assert(tstate->datastack_top); assert(tstate->datastack_top >= base); tstate->datastack_top = base; } } #ifdef __cplusplus } #endif ================================================ FILE: PyStrcmp.c ================================================ /* Cross platform case insensitive string compare functions */ #include "Python.h" int PyOS_mystrnicmp(const char *s1, const char *s2, Py_ssize_t size) { const unsigned char *p1, *p2; if (size == 0) return 0; p1 = (const unsigned char *)s1; p2 = (const unsigned char *)s2; for (; (--size > 0) && *p1 && *p2 && (tolower(*p1) == tolower(*p2)); p1++, p2++) { ; } return tolower(*p1) - tolower(*p2); } int PyOS_mystricmp(const char *s1, const char *s2) { const unsigned char *p1 = (const unsigned char *)s1; const unsigned char *p2 = (const unsigned char *)s2; for (; *p1 && *p2 && (tolower(*p1) == tolower(*p2)); p1++, p2++) { ; } return (tolower(*p1) - tolower(*p2)); } ================================================ FILE: PyStrhex.c ================================================ /* Format bytes as hexadecimal */ #include "Python.h" #include "pycore_strhex.h" // _Py_strhex_with_sep() #include // abs() static PyObject *_Py_strhex_impl(const char* argbuf, const Py_ssize_t arglen, PyObject* sep, int bytes_per_sep_group, const int return_bytes) { assert(arglen >= 0); Py_UCS1 sep_char = 0; if (sep) { Py_ssize_t seplen = PyObject_Length((PyObject*)sep); if (seplen < 0) { return NULL; } if (seplen != 1) { PyErr_SetString(PyExc_ValueError, "sep must be length 1."); return NULL; } if (PyUnicode_Check(sep)) { if (PyUnicode_READY(sep)) return NULL; if (PyUnicode_KIND(sep) != PyUnicode_1BYTE_KIND) { PyErr_SetString(PyExc_ValueError, "sep must be ASCII."); return NULL; } sep_char = PyUnicode_READ_CHAR(sep, 0); } else if (PyBytes_Check(sep)) { sep_char = PyBytes_AS_STRING(sep)[0]; } else { PyErr_SetString(PyExc_TypeError, "sep must be str or bytes."); return NULL; } if (sep_char > 127 && !return_bytes) { PyErr_SetString(PyExc_ValueError, "sep must be ASCII."); return NULL; } } else { bytes_per_sep_group = 0; } unsigned int abs_bytes_per_sep = abs(bytes_per_sep_group); Py_ssize_t resultlen = 0; if (bytes_per_sep_group && arglen > 0) { /* How many sep characters we'll be inserting. */ resultlen = (arglen - 1) / abs_bytes_per_sep; } /* Bounds checking for our Py_ssize_t indices. */ if (arglen >= PY_SSIZE_T_MAX / 2 - resultlen) { return PyErr_NoMemory(); } resultlen += arglen * 2; if ((size_t)abs_bytes_per_sep >= (size_t)arglen) { bytes_per_sep_group = 0; abs_bytes_per_sep = 0; } PyObject *retval; Py_UCS1 *retbuf; if (return_bytes) { /* If _PyBytes_FromSize() were public we could avoid malloc+copy. */ retval = PyBytes_FromStringAndSize(NULL, resultlen); if (!retval) { return NULL; } retbuf = (Py_UCS1 *)PyBytes_AS_STRING(retval); } else { retval = PyUnicode_New(resultlen, 127); if (!retval) { return NULL; } retbuf = PyUnicode_1BYTE_DATA(retval); } /* Hexlify */ Py_ssize_t i, j; unsigned char c; if (bytes_per_sep_group == 0) { for (i = j = 0; i < arglen; ++i) { assert((j + 1) < resultlen); c = argbuf[i]; retbuf[j++] = Py_hexdigits[c >> 4]; retbuf[j++] = Py_hexdigits[c & 0x0f]; } assert(j == resultlen); } else { /* The number of complete chunk+sep periods */ Py_ssize_t chunks = (arglen - 1) / abs_bytes_per_sep; Py_ssize_t chunk; unsigned int k; if (bytes_per_sep_group < 0) { i = j = 0; for (chunk = 0; chunk < chunks; chunk++) { for (k = 0; k < abs_bytes_per_sep; k++) { c = argbuf[i++]; retbuf[j++] = Py_hexdigits[c >> 4]; retbuf[j++] = Py_hexdigits[c & 0x0f]; } retbuf[j++] = sep_char; } while (i < arglen) { c = argbuf[i++]; retbuf[j++] = Py_hexdigits[c >> 4]; retbuf[j++] = Py_hexdigits[c & 0x0f]; } assert(j == resultlen); } else { i = arglen - 1; j = resultlen - 1; for (chunk = 0; chunk < chunks; chunk++) { for (k = 0; k < abs_bytes_per_sep; k++) { c = argbuf[i--]; retbuf[j--] = Py_hexdigits[c & 0x0f]; retbuf[j--] = Py_hexdigits[c >> 4]; } retbuf[j--] = sep_char; } while (i >= 0) { c = argbuf[i--]; retbuf[j--] = Py_hexdigits[c & 0x0f]; retbuf[j--] = Py_hexdigits[c >> 4]; } assert(j == -1); } } #ifdef Py_DEBUG if (!return_bytes) { assert(_PyUnicode_CheckConsistency(retval, 1)); } #endif return retval; } PyObject * _Py_strhex(const char* argbuf, const Py_ssize_t arglen) { return _Py_strhex_impl(argbuf, arglen, NULL, 0, 0); } /* Same as above but returns a bytes() instead of str() to avoid the * need to decode the str() when bytes are needed. */ PyObject* _Py_strhex_bytes(const char* argbuf, const Py_ssize_t arglen) { return _Py_strhex_impl(argbuf, arglen, NULL, 0, 1); } /* These variants include support for a separator between every N bytes: */ PyObject* _Py_strhex_with_sep(const char* argbuf, const Py_ssize_t arglen, PyObject* sep, const int bytes_per_group) { return _Py_strhex_impl(argbuf, arglen, sep, bytes_per_group, 0); } /* Same as above but returns a bytes() instead of str() to avoid the * need to decode the str() when bytes are needed. */ PyObject* _Py_strhex_bytes_with_sep(const char* argbuf, const Py_ssize_t arglen, PyObject* sep, const int bytes_per_group) { return _Py_strhex_impl(argbuf, arglen, sep, bytes_per_group, 1); } ================================================ FILE: PyStrtod.c ================================================ /* -*- Mode: C; c-file-style: "python" -*- */ #include #include "pycore_dtoa.h" // _Py_dg_strtod() #include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR #include /* Case-insensitive string match used for nan and inf detection; t should be lower-case. Returns 1 for a successful match, 0 otherwise. */ static int case_insensitive_match(const char *s, const char *t) { while(*t && Py_TOLOWER(*s) == *t) { s++; t++; } return *t ? 0 : 1; } /* _Py_parse_inf_or_nan: Attempt to parse a string of the form "nan", "inf" or "infinity", with an optional leading sign of "+" or "-". On success, return the NaN or Infinity as a double and set *endptr to point just beyond the successfully parsed portion of the string. On failure, return -1.0 and set *endptr to point to the start of the string. */ double _Py_parse_inf_or_nan(const char *p, char **endptr) { double retval; const char *s; int negate = 0; s = p; if (*s == '-') { negate = 1; s++; } else if (*s == '+') { s++; } if (case_insensitive_match(s, "inf")) { s += 3; if (case_insensitive_match(s, "inity")) s += 5; retval = negate ? -Py_HUGE_VAL : Py_HUGE_VAL; } else if (case_insensitive_match(s, "nan")) { s += 3; retval = negate ? -fabs(Py_NAN) : fabs(Py_NAN); } else { s = p; retval = -1.0; } *endptr = (char *)s; return retval; } /** * _PyOS_ascii_strtod: * @nptr: the string to convert to a numeric value. * @endptr: if non-%NULL, it returns the character after * the last character used in the conversion. * * Converts a string to a #gdouble value. * This function behaves like the standard strtod() function * does in the C locale. It does this without actually * changing the current locale, since that would not be * thread-safe. * * This function is typically used when reading configuration * files or other non-user input that should be locale independent. * To handle input from the user you should normally use the * locale-sensitive system strtod() function. * * If the correct value would cause overflow, plus or minus %HUGE_VAL * is returned (according to the sign of the value), and %ERANGE is * stored in %errno. If the correct value would cause underflow, * zero is returned and %ERANGE is stored in %errno. * If memory allocation fails, %ENOMEM is stored in %errno. * * This function resets %errno before calling strtod() so that * you can reliably detect overflow and underflow. * * Return value: the #gdouble value. **/ #if _PY_SHORT_FLOAT_REPR == 1 static double _PyOS_ascii_strtod(const char *nptr, char **endptr) { double result; _Py_SET_53BIT_PRECISION_HEADER; assert(nptr != NULL); /* Set errno to zero, so that we can distinguish zero results and underflows */ errno = 0; _Py_SET_53BIT_PRECISION_START; result = _Py_dg_strtod(nptr, endptr); _Py_SET_53BIT_PRECISION_END; if (*endptr == nptr) /* string might represent an inf or nan */ result = _Py_parse_inf_or_nan(nptr, endptr); return result; } #else /* Use system strtod; since strtod is locale aware, we may have to first fix the decimal separator. Note that unlike _Py_dg_strtod, the system strtod may not always give correctly rounded results. */ static double _PyOS_ascii_strtod(const char *nptr, char **endptr) { char *fail_pos; double val; struct lconv *locale_data; const char *decimal_point; size_t decimal_point_len; const char *p, *decimal_point_pos; const char *end = NULL; /* Silence gcc */ const char *digits_pos = NULL; int negate = 0; assert(nptr != NULL); fail_pos = NULL; locale_data = localeconv(); decimal_point = locale_data->decimal_point; decimal_point_len = strlen(decimal_point); assert(decimal_point_len != 0); decimal_point_pos = NULL; /* Parse infinities and nans */ val = _Py_parse_inf_or_nan(nptr, endptr); if (*endptr != nptr) return val; /* Set errno to zero, so that we can distinguish zero results and underflows */ errno = 0; /* We process the optional sign manually, then pass the remainder to the system strtod. This ensures that the result of an underflow has the correct sign. (bug #1725) */ p = nptr; /* Process leading sign, if present */ if (*p == '-') { negate = 1; p++; } else if (*p == '+') { p++; } /* Some platform strtods accept hex floats; Python shouldn't (at the moment), so we check explicitly for strings starting with '0x'. */ if (*p == '0' && (*(p+1) == 'x' || *(p+1) == 'X')) goto invalid_string; /* Check that what's left begins with a digit or decimal point */ if (!Py_ISDIGIT(*p) && *p != '.') goto invalid_string; digits_pos = p; if (decimal_point[0] != '.' || decimal_point[1] != 0) { /* Look for a '.' in the input; if present, it'll need to be swapped for the current locale's decimal point before we call strtod. On the other hand, if we find the current locale's decimal point then the input is invalid. */ while (Py_ISDIGIT(*p)) p++; if (*p == '.') { decimal_point_pos = p++; /* locate end of number */ while (Py_ISDIGIT(*p)) p++; if (*p == 'e' || *p == 'E') p++; if (*p == '+' || *p == '-') p++; while (Py_ISDIGIT(*p)) p++; end = p; } else if (strncmp(p, decimal_point, decimal_point_len) == 0) /* Python bug #1417699 */ goto invalid_string; /* For the other cases, we need not convert the decimal point */ } if (decimal_point_pos) { char *copy, *c; /* Create a copy of the input, with the '.' converted to the locale-specific decimal point */ copy = (char *)PyMem_Malloc(end - digits_pos + 1 + decimal_point_len); if (copy == NULL) { *endptr = (char *)nptr; errno = ENOMEM; return val; } c = copy; memcpy(c, digits_pos, decimal_point_pos - digits_pos); c += decimal_point_pos - digits_pos; memcpy(c, decimal_point, decimal_point_len); c += decimal_point_len; memcpy(c, decimal_point_pos + 1, end - (decimal_point_pos + 1)); c += end - (decimal_point_pos + 1); *c = 0; val = strtod(copy, &fail_pos); if (fail_pos) { if (fail_pos > decimal_point_pos) fail_pos = (char *)digits_pos + (fail_pos - copy) - (decimal_point_len - 1); else fail_pos = (char *)digits_pos + (fail_pos - copy); } PyMem_Free(copy); } else { val = strtod(digits_pos, &fail_pos); } if (fail_pos == digits_pos) goto invalid_string; if (negate && fail_pos != nptr) val = -val; *endptr = fail_pos; return val; invalid_string: *endptr = (char*)nptr; errno = EINVAL; return -1.0; } #endif /* PyOS_string_to_double converts a null-terminated byte string s (interpreted as a string of ASCII characters) to a float. The string should not have leading or trailing whitespace. The conversion is independent of the current locale. If endptr is NULL, try to convert the whole string. Raise ValueError and return -1.0 if the string is not a valid representation of a floating-point number. If endptr is non-NULL, try to convert as much of the string as possible. If no initial segment of the string is the valid representation of a floating-point number then *endptr is set to point to the beginning of the string, -1.0 is returned and again ValueError is raised. On overflow (e.g., when trying to convert '1e500' on an IEEE 754 machine), if overflow_exception is NULL then +-Py_HUGE_VAL is returned, and no Python exception is raised. Otherwise, overflow_exception should point to a Python exception, this exception will be raised, -1.0 will be returned, and *endptr will point just past the end of the converted value. If any other failure occurs (for example lack of memory), -1.0 is returned and the appropriate Python exception will have been set. */ double PyOS_string_to_double(const char *s, char **endptr, PyObject *overflow_exception) { double x, result=-1.0; char *fail_pos; errno = 0; x = _PyOS_ascii_strtod(s, &fail_pos); if (errno == ENOMEM) { PyErr_NoMemory(); fail_pos = (char *)s; } else if (!endptr && (fail_pos == s || *fail_pos != '\0')) PyErr_Format(PyExc_ValueError, "could not convert string to float: " "'%.200s'", s); else if (fail_pos == s) PyErr_Format(PyExc_ValueError, "could not convert string to float: " "'%.200s'", s); else if (errno == ERANGE && fabs(x) >= 1.0 && overflow_exception) PyErr_Format(overflow_exception, "value too large to convert to float: " "'%.200s'", s); else result = x; if (endptr != NULL) *endptr = fail_pos; return result; } /* Remove underscores that follow the underscore placement rule from the string and then call the `innerfunc` function on the result. It should return a new object or NULL on exception. `what` is used for the error message emitted when underscores are detected that don't follow the rule. `arg` is an opaque pointer passed to the inner function. This is used to implement underscore-agnostic conversion for floats and complex numbers. */ PyObject * _Py_string_to_number_with_underscores( const char *s, Py_ssize_t orig_len, const char *what, PyObject *obj, void *arg, PyObject *(*innerfunc)(const char *, Py_ssize_t, void *)) { char prev; const char *p, *last; char *dup, *end; PyObject *result; assert(s[orig_len] == '\0'); if (strchr(s, '_') == NULL) { return innerfunc(s, orig_len, arg); } dup = PyMem_Malloc(orig_len + 1); if (dup == NULL) { return PyErr_NoMemory(); } end = dup; prev = '\0'; last = s + orig_len; for (p = s; *p; p++) { if (*p == '_') { /* Underscores are only allowed after digits. */ if (!(prev >= '0' && prev <= '9')) { goto error; } } else { *end++ = *p; /* Underscores are only allowed before digits. */ if (prev == '_' && !(*p >= '0' && *p <= '9')) { goto error; } } prev = *p; } /* Underscores are not allowed at the end. */ if (prev == '_') { goto error; } /* No embedded NULs allowed. */ if (p != last) { goto error; } *end = '\0'; result = innerfunc(dup, end - dup, arg); PyMem_Free(dup); return result; error: PyMem_Free(dup); PyErr_Format(PyExc_ValueError, "could not convert string to %s: " "%R", what, obj); return NULL; } #if _PY_SHORT_FLOAT_REPR == 0 /* Given a string that may have a decimal point in the current locale, change it back to a dot. Since the string cannot get longer, no need for a maximum buffer size parameter. */ Py_LOCAL_INLINE(void) change_decimal_from_locale_to_dot(char* buffer) { struct lconv *locale_data = localeconv(); const char *decimal_point = locale_data->decimal_point; if (decimal_point[0] != '.' || decimal_point[1] != 0) { size_t decimal_point_len = strlen(decimal_point); if (*buffer == '+' || *buffer == '-') buffer++; while (Py_ISDIGIT(*buffer)) buffer++; if (strncmp(buffer, decimal_point, decimal_point_len) == 0) { *buffer = '.'; buffer++; if (decimal_point_len > 1) { /* buffer needs to get smaller */ size_t rest_len = strlen(buffer + (decimal_point_len - 1)); memmove(buffer, buffer + (decimal_point_len - 1), rest_len); buffer[rest_len] = 0; } } } } /* From the C99 standard, section 7.19.6: The exponent always contains at least two digits, and only as many more digits as necessary to represent the exponent. */ #define MIN_EXPONENT_DIGITS 2 /* Ensure that any exponent, if present, is at least MIN_EXPONENT_DIGITS in length. */ Py_LOCAL_INLINE(void) ensure_minimum_exponent_length(char* buffer, size_t buf_size) { char *p = strpbrk(buffer, "eE"); if (p && (*(p + 1) == '-' || *(p + 1) == '+')) { char *start = p + 2; int exponent_digit_cnt = 0; int leading_zero_cnt = 0; int in_leading_zeros = 1; int significant_digit_cnt; /* Skip over the exponent and the sign. */ p += 2; /* Find the end of the exponent, keeping track of leading zeros. */ while (*p && Py_ISDIGIT(*p)) { if (in_leading_zeros && *p == '0') ++leading_zero_cnt; if (*p != '0') in_leading_zeros = 0; ++p; ++exponent_digit_cnt; } significant_digit_cnt = exponent_digit_cnt - leading_zero_cnt; if (exponent_digit_cnt == MIN_EXPONENT_DIGITS) { /* If there are 2 exactly digits, we're done, regardless of what they contain */ } else if (exponent_digit_cnt > MIN_EXPONENT_DIGITS) { int extra_zeros_cnt; /* There are more than 2 digits in the exponent. See if we can delete some of the leading zeros */ if (significant_digit_cnt < MIN_EXPONENT_DIGITS) significant_digit_cnt = MIN_EXPONENT_DIGITS; extra_zeros_cnt = exponent_digit_cnt - significant_digit_cnt; /* Delete extra_zeros_cnt worth of characters from the front of the exponent */ assert(extra_zeros_cnt >= 0); /* Add one to significant_digit_cnt to copy the trailing 0 byte, thus setting the length */ memmove(start, start + extra_zeros_cnt, significant_digit_cnt + 1); } else { /* If there are fewer than 2 digits, add zeros until there are 2, if there's enough room */ int zeros = MIN_EXPONENT_DIGITS - exponent_digit_cnt; if (start + zeros + exponent_digit_cnt + 1 < buffer + buf_size) { memmove(start + zeros, start, exponent_digit_cnt + 1); memset(start, '0', zeros); } } } } /* Remove trailing zeros after the decimal point from a numeric string; also remove the decimal point if all digits following it are zero. The numeric string must end in '\0', and should not have any leading or trailing whitespace. Assumes that the decimal point is '.'. */ Py_LOCAL_INLINE(void) remove_trailing_zeros(char *buffer) { char *old_fraction_end, *new_fraction_end, *end, *p; p = buffer; if (*p == '-' || *p == '+') /* Skip leading sign, if present */ ++p; while (Py_ISDIGIT(*p)) ++p; /* if there's no decimal point there's nothing to do */ if (*p++ != '.') return; /* scan any digits after the point */ while (Py_ISDIGIT(*p)) ++p; old_fraction_end = p; /* scan up to ending '\0' */ while (*p != '\0') p++; /* +1 to make sure that we move the null byte as well */ end = p+1; /* scan back from fraction_end, looking for removable zeros */ p = old_fraction_end; while (*(p-1) == '0') --p; /* and remove point if we've got that far */ if (*(p-1) == '.') --p; new_fraction_end = p; memmove(new_fraction_end, old_fraction_end, end-old_fraction_end); } /* Ensure that buffer has a decimal point in it. The decimal point will not be in the current locale, it will always be '.'. Don't add a decimal point if an exponent is present. Also, convert to exponential notation where adding a '.0' would produce too many significant digits (see issue 5864). Returns a pointer to the fixed buffer, or NULL on failure. */ Py_LOCAL_INLINE(char *) ensure_decimal_point(char* buffer, size_t buf_size, int precision) { int digit_count, insert_count = 0, convert_to_exp = 0; const char *chars_to_insert; char *digits_start; /* search for the first non-digit character */ char *p = buffer; if (*p == '-' || *p == '+') /* Skip leading sign, if present. I think this could only ever be '-', but it can't hurt to check for both. */ ++p; digits_start = p; while (*p && Py_ISDIGIT(*p)) ++p; digit_count = Py_SAFE_DOWNCAST(p - digits_start, Py_ssize_t, int); if (*p == '.') { if (Py_ISDIGIT(*(p+1))) { /* Nothing to do, we already have a decimal point and a digit after it */ } else { /* We have a decimal point, but no following digit. Insert a zero after the decimal. */ /* can't ever get here via PyOS_double_to_string */ assert(precision == -1); ++p; chars_to_insert = "0"; insert_count = 1; } } else if (!(*p == 'e' || *p == 'E')) { /* Don't add ".0" if we have an exponent. */ if (digit_count == precision) { /* issue 5864: don't add a trailing .0 in the case where the '%g'-formatted result already has as many significant digits as were requested. Switch to exponential notation instead. */ convert_to_exp = 1; /* no exponent, no point, and we shouldn't land here for infs and nans, so we must be at the end of the string. */ assert(*p == '\0'); } else { assert(precision == -1 || digit_count < precision); chars_to_insert = ".0"; insert_count = 2; } } if (insert_count) { size_t buf_len = strlen(buffer); if (buf_len + insert_count + 1 >= buf_size) { /* If there is not enough room in the buffer for the additional text, just skip it. It's not worth generating an error over. */ } else { memmove(p + insert_count, p, buffer + strlen(buffer) - p + 1); memcpy(p, chars_to_insert, insert_count); } } if (convert_to_exp) { int written; size_t buf_avail; p = digits_start; /* insert decimal point */ assert(digit_count >= 1); memmove(p+2, p+1, digit_count); /* safe, but overwrites nul */ p[1] = '.'; p += digit_count+1; assert(p <= buf_size+buffer); buf_avail = buf_size+buffer-p; if (buf_avail == 0) return NULL; /* Add exponent. It's okay to use lower case 'e': we only arrive here as a result of using the empty format code or repr/str builtins and those never want an upper case 'E' */ written = PyOS_snprintf(p, buf_avail, "e%+.02d", digit_count-1); if (!(0 <= written && written < Py_SAFE_DOWNCAST(buf_avail, size_t, int))) /* output truncated, or something else bad happened */ return NULL; remove_trailing_zeros(buffer); } return buffer; } /* see FORMATBUFLEN in unicodeobject.c */ #define FLOAT_FORMATBUFLEN 120 /** * _PyOS_ascii_formatd: * @buffer: A buffer to place the resulting string in * @buf_size: The length of the buffer. * @format: The printf()-style format to use for the * code to use for converting. * @d: The #gdouble to convert * @precision: The precision to use when formatting. * * Converts a #gdouble to a string, using the '.' as * decimal point. To format the number you pass in * a printf()-style format string. Allowed conversion * specifiers are 'e', 'E', 'f', 'F', 'g', 'G', and 'Z'. * * 'Z' is the same as 'g', except it always has a decimal and * at least one digit after the decimal. * * Return value: The pointer to the buffer with the converted string. * On failure returns NULL but does not set any Python exception. **/ static char * _PyOS_ascii_formatd(char *buffer, size_t buf_size, const char *format, double d, int precision) { char format_char; size_t format_len = strlen(format); /* Issue 2264: code 'Z' requires copying the format. 'Z' is 'g', but also with at least one character past the decimal. */ char tmp_format[FLOAT_FORMATBUFLEN]; /* The last character in the format string must be the format char */ format_char = format[format_len - 1]; if (format[0] != '%') return NULL; /* I'm not sure why this test is here. It's ensuring that the format string after the first character doesn't have a single quote, a lowercase l, or a percent. This is the reverse of the commented-out test about 10 lines ago. */ if (strpbrk(format + 1, "'l%")) return NULL; /* Also curious about this function is that it accepts format strings like "%xg", which are invalid for floats. In general, the interface to this function is not very good, but changing it is difficult because it's a public API. */ if (!(format_char == 'e' || format_char == 'E' || format_char == 'f' || format_char == 'F' || format_char == 'g' || format_char == 'G' || format_char == 'Z')) return NULL; /* Map 'Z' format_char to 'g', by copying the format string and replacing the final char with a 'g' */ if (format_char == 'Z') { if (format_len + 1 >= sizeof(tmp_format)) { /* The format won't fit in our copy. Error out. In practice, this will never happen and will be detected by returning NULL */ return NULL; } strcpy(tmp_format, format); tmp_format[format_len - 1] = 'g'; format = tmp_format; } /* Have PyOS_snprintf do the hard work */ PyOS_snprintf(buffer, buf_size, format, d); /* Do various fixups on the return string */ /* Get the current locale, and find the decimal point string. Convert that string back to a dot. */ change_decimal_from_locale_to_dot(buffer); /* If an exponent exists, ensure that the exponent is at least MIN_EXPONENT_DIGITS digits, providing the buffer is large enough for the extra zeros. Also, if there are more than MIN_EXPONENT_DIGITS, remove as many zeros as possible until we get back to MIN_EXPONENT_DIGITS */ ensure_minimum_exponent_length(buffer, buf_size); /* If format_char is 'Z', make sure we have at least one character after the decimal point (and make sure we have a decimal point); also switch to exponential notation in some edge cases where the extra character would produce more significant digits that we really want. */ if (format_char == 'Z') buffer = ensure_decimal_point(buffer, buf_size, precision); return buffer; } /* The fallback code to use if _Py_dg_dtoa is not available. */ char * PyOS_double_to_string(double val, char format_code, int precision, int flags, int *type) { char format[32]; Py_ssize_t bufsize; char *buf; int t, exp; int upper = 0; /* Validate format_code, and map upper and lower case */ switch (format_code) { case 'e': /* exponent */ case 'f': /* fixed */ case 'g': /* general */ break; case 'E': upper = 1; format_code = 'e'; break; case 'F': upper = 1; format_code = 'f'; break; case 'G': upper = 1; format_code = 'g'; break; case 'r': /* repr format */ /* Supplied precision is unused, must be 0. */ if (precision != 0) { PyErr_BadInternalCall(); return NULL; } /* The repr() precision (17 significant decimal digits) is the minimal number that is guaranteed to have enough precision so that if the number is read back in the exact same binary value is recreated. This is true for IEEE floating point by design, and also happens to work for all other modern hardware. */ precision = 17; format_code = 'g'; break; default: PyErr_BadInternalCall(); return NULL; } /* Here's a quick-and-dirty calculation to figure out how big a buffer we need. In general, for a finite float we need: 1 byte for each digit of the decimal significand, and 1 for a possible sign 1 for a possible decimal point 2 for a possible [eE][+-] 1 for each digit of the exponent; if we allow 19 digits total then we're safe up to exponents of 2**63. 1 for the trailing nul byte This gives a total of 24 + the number of digits in the significand, and the number of digits in the significand is: for 'g' format: at most precision, except possibly when precision == 0, when it's 1. for 'e' format: precision+1 for 'f' format: precision digits after the point, at least 1 before. To figure out how many digits appear before the point we have to examine the size of the number. If fabs(val) < 1.0 then there will be only one digit before the point. If fabs(val) >= 1.0, then there are at most 1+floor(log10(ceiling(fabs(val)))) digits before the point (where the 'ceiling' allows for the possibility that the rounding rounds the integer part of val up). A safe upper bound for the above quantity is 1+floor(exp/3), where exp is the unique integer such that 0.5 <= fabs(val)/2**exp < 1.0. This exp can be obtained from frexp. So we allow room for precision+1 digits for all formats, plus an extra floor(exp/3) digits for 'f' format. */ if (Py_IS_NAN(val) || Py_IS_INFINITY(val)) /* 3 for 'inf'/'nan', 1 for sign, 1 for '\0' */ bufsize = 5; else { bufsize = 25 + precision; if (format_code == 'f' && fabs(val) >= 1.0) { frexp(val, &exp); bufsize += exp/3; } } buf = PyMem_Malloc(bufsize); if (buf == NULL) { PyErr_NoMemory(); return NULL; } /* Handle nan and inf. */ if (Py_IS_NAN(val)) { strcpy(buf, "nan"); t = Py_DTST_NAN; } else if (Py_IS_INFINITY(val)) { if (copysign(1., val) == 1.) strcpy(buf, "inf"); else strcpy(buf, "-inf"); t = Py_DTST_INFINITE; } else { t = Py_DTST_FINITE; if (flags & Py_DTSF_ADD_DOT_0) format_code = 'Z'; PyOS_snprintf(format, sizeof(format), "%%%s.%i%c", (flags & Py_DTSF_ALT ? "#" : ""), precision, format_code); _PyOS_ascii_formatd(buf, bufsize, format, val, precision); if (flags & Py_DTSF_NO_NEG_0 && buf[0] == '-') { char *buf2 = buf + 1; while (*buf2 == '0' || *buf2 == '.') { ++buf2; } if (*buf2 == 0 || *buf2 == 'e') { size_t len = buf2 - buf + strlen(buf2); assert(buf[len] == 0); memmove(buf, buf+1, len); } } } /* Add sign when requested. It's convenient (esp. when formatting complex numbers) to include a sign even for inf and nan. */ if (flags & Py_DTSF_SIGN && buf[0] != '-') { size_t len = strlen(buf); /* the bufsize calculations above should ensure that we've got space to add a sign */ assert((size_t)bufsize >= len+2); memmove(buf+1, buf, len+1); buf[0] = '+'; } if (upper) { /* Convert to upper case. */ char *p1; for (p1 = buf; *p1; p1++) *p1 = Py_TOUPPER(*p1); } if (type) *type = t; return buf; } #else // _PY_SHORT_FLOAT_REPR == 1 /* _Py_dg_dtoa is available. */ /* I'm using a lookup table here so that I don't have to invent a non-locale specific way to convert to uppercase */ #define OFS_INF 0 #define OFS_NAN 1 #define OFS_E 2 /* The lengths of these are known to the code below, so don't change them */ static const char * const lc_float_strings[] = { "inf", "nan", "e", }; static const char * const uc_float_strings[] = { "INF", "NAN", "E", }; /* Convert a double d to a string, and return a PyMem_Malloc'd block of memory contain the resulting string. Arguments: d is the double to be converted format_code is one of 'e', 'f', 'g', 'r'. 'e', 'f' and 'g' correspond to '%e', '%f' and '%g'; 'r' corresponds to repr. mode is one of '0', '2' or '3', and is completely determined by format_code: 'e' and 'g' use mode 2; 'f' mode 3, 'r' mode 0. precision is the desired precision always_add_sign is nonzero if a '+' sign should be included for positive numbers add_dot_0_if_integer is nonzero if integers in non-exponential form should have ".0" added. Only applies to format codes 'r' and 'g'. use_alt_formatting is nonzero if alternative formatting should be used. Only applies to format codes 'e', 'f' and 'g'. For code 'g', at most one of use_alt_formatting and add_dot_0_if_integer should be nonzero. type, if non-NULL, will be set to one of these constants to identify the type of the 'd' argument: Py_DTST_FINITE Py_DTST_INFINITE Py_DTST_NAN Returns a PyMem_Malloc'd block of memory containing the resulting string, or NULL on error. If NULL is returned, the Python error has been set. */ static char * format_float_short(double d, char format_code, int mode, int precision, int always_add_sign, int add_dot_0_if_integer, int use_alt_formatting, int no_negative_zero, const char * const *float_strings, int *type) { char *buf = NULL; char *p = NULL; Py_ssize_t bufsize = 0; char *digits, *digits_end; int decpt_as_int, sign, exp_len, exp = 0, use_exp = 0; Py_ssize_t decpt, digits_len, vdigits_start, vdigits_end; _Py_SET_53BIT_PRECISION_HEADER; /* _Py_dg_dtoa returns a digit string (no decimal point or exponent). Must be matched by a call to _Py_dg_freedtoa. */ _Py_SET_53BIT_PRECISION_START; digits = _Py_dg_dtoa(d, mode, precision, &decpt_as_int, &sign, &digits_end); _Py_SET_53BIT_PRECISION_END; decpt = (Py_ssize_t)decpt_as_int; if (digits == NULL) { /* The only failure mode is no memory. */ PyErr_NoMemory(); goto exit; } assert(digits_end != NULL && digits_end >= digits); digits_len = digits_end - digits; if (no_negative_zero && sign == 1 && (digits_len == 0 || (digits_len == 1 && digits[0] == '0'))) { sign = 0; } if (digits_len && !Py_ISDIGIT(digits[0])) { /* Infinities and nans here; adapt Gay's output, so convert Infinity to inf and NaN to nan, and ignore sign of nan. Then return. */ /* ignore the actual sign of a nan */ if (digits[0] == 'n' || digits[0] == 'N') sign = 0; /* We only need 5 bytes to hold the result "+inf\0" . */ bufsize = 5; /* Used later in an assert. */ buf = (char *)PyMem_Malloc(bufsize); if (buf == NULL) { PyErr_NoMemory(); goto exit; } p = buf; if (sign == 1) { *p++ = '-'; } else if (always_add_sign) { *p++ = '+'; } if (digits[0] == 'i' || digits[0] == 'I') { strncpy(p, float_strings[OFS_INF], 3); p += 3; if (type) *type = Py_DTST_INFINITE; } else if (digits[0] == 'n' || digits[0] == 'N') { strncpy(p, float_strings[OFS_NAN], 3); p += 3; if (type) *type = Py_DTST_NAN; } else { /* shouldn't get here: Gay's code should always return something starting with a digit, an 'I', or 'N' */ Py_UNREACHABLE(); } goto exit; } /* The result must be finite (not inf or nan). */ if (type) *type = Py_DTST_FINITE; /* We got digits back, format them. We may need to pad 'digits' either on the left or right (or both) with extra zeros, so in general the resulting string has the form [][] where either of the pieces could be empty, and there's a decimal point that could appear either in or in the leading or trailing . Imagine an infinite 'virtual' string vdigits, consisting of the string 'digits' (starting at index 0) padded on both the left and right with infinite strings of zeros. We want to output a slice vdigits[vdigits_start : vdigits_end] of this virtual string. Thus if vdigits_start < 0 then we'll end up producing some leading zeros; if vdigits_end > digits_len there will be trailing zeros in the output. The next section of code determines whether to use an exponent or not, figures out the position 'decpt' of the decimal point, and computes 'vdigits_start' and 'vdigits_end'. */ vdigits_end = digits_len; switch (format_code) { case 'e': use_exp = 1; vdigits_end = precision; break; case 'f': vdigits_end = decpt + precision; break; case 'g': if (decpt <= -4 || decpt > (add_dot_0_if_integer ? precision-1 : precision)) use_exp = 1; if (use_alt_formatting) vdigits_end = precision; break; case 'r': /* convert to exponential format at 1e16. We used to convert at 1e17, but that gives odd-looking results for some values when a 16-digit 'shortest' repr is padded with bogus zeros. For example, repr(2e16+8) would give 20000000000000010.0; the true value is 20000000000000008.0. */ if (decpt <= -4 || decpt > 16) use_exp = 1; break; default: PyErr_BadInternalCall(); goto exit; } /* if using an exponent, reset decimal point position to 1 and adjust exponent accordingly.*/ if (use_exp) { exp = (int)decpt - 1; decpt = 1; } /* ensure vdigits_start < decpt <= vdigits_end, or vdigits_start < decpt < vdigits_end if add_dot_0_if_integer and no exponent */ vdigits_start = decpt <= 0 ? decpt-1 : 0; if (!use_exp && add_dot_0_if_integer) vdigits_end = vdigits_end > decpt ? vdigits_end : decpt + 1; else vdigits_end = vdigits_end > decpt ? vdigits_end : decpt; /* double check inequalities */ assert(vdigits_start <= 0 && 0 <= digits_len && digits_len <= vdigits_end); /* decimal point should be in (vdigits_start, vdigits_end] */ assert(vdigits_start < decpt && decpt <= vdigits_end); /* Compute an upper bound how much memory we need. This might be a few chars too long, but no big deal. */ bufsize = /* sign, decimal point and trailing 0 byte */ 3 + /* total digit count (including zero padding on both sides) */ (vdigits_end - vdigits_start) + /* exponent "e+100", max 3 numerical digits */ (use_exp ? 5 : 0); /* Now allocate the memory and initialize p to point to the start of it. */ buf = (char *)PyMem_Malloc(bufsize); if (buf == NULL) { PyErr_NoMemory(); goto exit; } p = buf; /* Add a negative sign if negative, and a plus sign if non-negative and always_add_sign is true. */ if (sign == 1) *p++ = '-'; else if (always_add_sign) *p++ = '+'; /* note that exactly one of the three 'if' conditions is true, so we include exactly one decimal point */ /* Zero padding on left of digit string */ if (decpt <= 0) { memset(p, '0', decpt-vdigits_start); p += decpt - vdigits_start; *p++ = '.'; memset(p, '0', 0-decpt); p += 0-decpt; } else { memset(p, '0', 0-vdigits_start); p += 0 - vdigits_start; } /* Digits, with included decimal point */ if (0 < decpt && decpt <= digits_len) { strncpy(p, digits, decpt-0); p += decpt-0; *p++ = '.'; strncpy(p, digits+decpt, digits_len-decpt); p += digits_len-decpt; } else { strncpy(p, digits, digits_len); p += digits_len; } /* And zeros on the right */ if (digits_len < decpt) { memset(p, '0', decpt-digits_len); p += decpt-digits_len; *p++ = '.'; memset(p, '0', vdigits_end-decpt); p += vdigits_end-decpt; } else { memset(p, '0', vdigits_end-digits_len); p += vdigits_end-digits_len; } /* Delete a trailing decimal pt unless using alternative formatting. */ if (p[-1] == '.' && !use_alt_formatting) p--; /* Now that we've done zero padding, add an exponent if needed. */ if (use_exp) { *p++ = float_strings[OFS_E][0]; exp_len = sprintf(p, "%+.02d", exp); p += exp_len; } exit: if (buf) { *p = '\0'; /* It's too late if this fails, as we've already stepped on memory that isn't ours. But it's an okay debugging test. */ assert(p-buf < bufsize); } if (digits) _Py_dg_freedtoa(digits); return buf; } char * PyOS_double_to_string(double val, char format_code, int precision, int flags, int *type) { const char * const *float_strings = lc_float_strings; int mode; /* Validate format_code, and map upper and lower case. Compute the mode and make any adjustments as needed. */ switch (format_code) { /* exponent */ case 'E': float_strings = uc_float_strings; format_code = 'e'; /* Fall through. */ case 'e': mode = 2; precision++; break; /* fixed */ case 'F': float_strings = uc_float_strings; format_code = 'f'; /* Fall through. */ case 'f': mode = 3; break; /* general */ case 'G': float_strings = uc_float_strings; format_code = 'g'; /* Fall through. */ case 'g': mode = 2; /* precision 0 makes no sense for 'g' format; interpret as 1 */ if (precision == 0) precision = 1; break; /* repr format */ case 'r': mode = 0; /* Supplied precision is unused, must be 0. */ if (precision != 0) { PyErr_BadInternalCall(); return NULL; } break; default: PyErr_BadInternalCall(); return NULL; } return format_float_short(val, format_code, mode, precision, flags & Py_DTSF_SIGN, flags & Py_DTSF_ADD_DOT_0, flags & Py_DTSF_ALT, flags & Py_DTSF_NO_NEG_0, float_strings, type); } #endif // _PY_SHORT_FLOAT_REPR == 1 ================================================ FILE: PyTime.c ================================================ #include "Python.h" #ifdef MS_WINDOWS # include // struct timeval #endif #if defined(__APPLE__) # include // mach_absolute_time(), mach_timebase_info() #if defined(__APPLE__) && defined(__has_builtin) # if __has_builtin(__builtin_available) # define HAVE_CLOCK_GETTIME_RUNTIME __builtin_available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *) # endif #endif #endif /* To millisecond (10^-3) */ #define SEC_TO_MS 1000 /* To microseconds (10^-6) */ #define MS_TO_US 1000 #define SEC_TO_US (SEC_TO_MS * MS_TO_US) /* To nanoseconds (10^-9) */ #define US_TO_NS 1000 #define MS_TO_NS (MS_TO_US * US_TO_NS) #define SEC_TO_NS (SEC_TO_MS * MS_TO_NS) /* Conversion from nanoseconds */ #define NS_TO_MS (1000 * 1000) #define NS_TO_US (1000) #define NS_TO_100NS (100) #if SIZEOF_TIME_T == SIZEOF_LONG_LONG # define PY_TIME_T_MAX LLONG_MAX # define PY_TIME_T_MIN LLONG_MIN #elif SIZEOF_TIME_T == SIZEOF_LONG # define PY_TIME_T_MAX LONG_MAX # define PY_TIME_T_MIN LONG_MIN #else # error "unsupported time_t size" #endif #if PY_TIME_T_MAX + PY_TIME_T_MIN != -1 # error "time_t is not a two's complement integer type" #endif #if _PyTime_MIN + _PyTime_MAX != -1 # error "_PyTime_t is not a two's complement integer type" #endif static void pytime_time_t_overflow(void) { PyErr_SetString(PyExc_OverflowError, "timestamp out of range for platform time_t"); } static void pytime_overflow(void) { PyErr_SetString(PyExc_OverflowError, "timestamp too large to convert to C _PyTime_t"); } static inline _PyTime_t pytime_from_nanoseconds(_PyTime_t t) { // _PyTime_t is a number of nanoseconds return t; } static inline _PyTime_t pytime_as_nanoseconds(_PyTime_t t) { // _PyTime_t is a number of nanoseconds: see pytime_from_nanoseconds() return t; } // Compute t1 + t2. Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow. static inline int pytime_add(_PyTime_t *t1, _PyTime_t t2) { if (t2 > 0 && *t1 > _PyTime_MAX - t2) { *t1 = _PyTime_MAX; return -1; } else if (t2 < 0 && *t1 < _PyTime_MIN - t2) { *t1 = _PyTime_MIN; return -1; } else { *t1 += t2; return 0; } } _PyTime_t _PyTime_Add(_PyTime_t t1, _PyTime_t t2) { (void)pytime_add(&t1, t2); return t1; } static inline int pytime_mul_check_overflow(_PyTime_t a, _PyTime_t b) { if (b != 0) { assert(b > 0); return ((a < _PyTime_MIN / b) || (_PyTime_MAX / b < a)); } else { return 0; } } // Compute t * k. Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow. static inline int pytime_mul(_PyTime_t *t, _PyTime_t k) { assert(k >= 0); if (pytime_mul_check_overflow(*t, k)) { *t = (*t >= 0) ? _PyTime_MAX : _PyTime_MIN; return -1; } else { *t *= k; return 0; } } // Compute t * k. Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow. static inline _PyTime_t _PyTime_Mul(_PyTime_t t, _PyTime_t k) { (void)pytime_mul(&t, k); return t; } _PyTime_t _PyTime_MulDiv(_PyTime_t ticks, _PyTime_t mul, _PyTime_t div) { /* Compute (ticks * mul / div) in two parts to reduce the risk of integer overflow: compute the integer part, and then the remaining part. (ticks * mul) / div == (ticks / div) * mul + (ticks % div) * mul / div */ _PyTime_t intpart, remaining; intpart = ticks / div; ticks %= div; remaining = _PyTime_Mul(ticks, mul) / div; // intpart * mul + remaining return _PyTime_Add(_PyTime_Mul(intpart, mul), remaining); } time_t _PyLong_AsTime_t(PyObject *obj) { #if SIZEOF_TIME_T == SIZEOF_LONG_LONG long long val = PyLong_AsLongLong(obj); #elif SIZEOF_TIME_T <= SIZEOF_LONG long val = PyLong_AsLong(obj); #else # error "unsupported time_t size" #endif if (val == -1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) { pytime_time_t_overflow(); } return -1; } return (time_t)val; } PyObject * _PyLong_FromTime_t(time_t t) { #if SIZEOF_TIME_T == SIZEOF_LONG_LONG return PyLong_FromLongLong((long long)t); #elif SIZEOF_TIME_T <= SIZEOF_LONG return PyLong_FromLong((long)t); #else # error "unsupported time_t size" #endif } // Convert _PyTime_t to time_t. // Return 0 on success. Return -1 and clamp the value on overflow. static int _PyTime_AsTime_t(_PyTime_t t, time_t *t2) { #if SIZEOF_TIME_T < _SIZEOF_PYTIME_T if ((_PyTime_t)PY_TIME_T_MAX < t) { *t2 = PY_TIME_T_MAX; return -1; } if (t < (_PyTime_t)PY_TIME_T_MIN) { *t2 = PY_TIME_T_MIN; return -1; } #endif *t2 = (time_t)t; return 0; } #ifdef MS_WINDOWS // Convert _PyTime_t to long. // Return 0 on success. Return -1 and clamp the value on overflow. static int _PyTime_AsLong(_PyTime_t t, long *t2) { #if SIZEOF_LONG < _SIZEOF_PYTIME_T if ((_PyTime_t)LONG_MAX < t) { *t2 = LONG_MAX; return -1; } if (t < (_PyTime_t)LONG_MIN) { *t2 = LONG_MIN; return -1; } #endif *t2 = (long)t; return 0; } #endif /* Round to nearest with ties going to nearest even integer (_PyTime_ROUND_HALF_EVEN) */ static double pytime_round_half_even(double x) { double rounded = round(x); if (fabs(x-rounded) == 0.5) { /* halfway case: round to even */ rounded = 2.0 * round(x / 2.0); } return rounded; } static double pytime_round(double x, _PyTime_round_t round) { /* volatile avoids optimization changing how numbers are rounded */ volatile double d; d = x; if (round == _PyTime_ROUND_HALF_EVEN) { d = pytime_round_half_even(d); } else if (round == _PyTime_ROUND_CEILING) { d = ceil(d); } else if (round == _PyTime_ROUND_FLOOR) { d = floor(d); } else { assert(round == _PyTime_ROUND_UP); d = (d >= 0.0) ? ceil(d) : floor(d); } return d; } static int pytime_double_to_denominator(double d, time_t *sec, long *numerator, long idenominator, _PyTime_round_t round) { double denominator = (double)idenominator; double intpart; /* volatile avoids optimization changing how numbers are rounded */ volatile double floatpart; floatpart = modf(d, &intpart); floatpart *= denominator; floatpart = pytime_round(floatpart, round); if (floatpart >= denominator) { floatpart -= denominator; intpart += 1.0; } else if (floatpart < 0) { floatpart += denominator; intpart -= 1.0; } assert(0.0 <= floatpart && floatpart < denominator); /* Conversion of an out-of-range value to time_t gives undefined behaviour (C99 §6.3.1.4p1), so we must guard against it. However, checking that `intpart` is in range is delicate: the obvious expression `intpart <= PY_TIME_T_MAX` will first convert the value `PY_TIME_T_MAX` to a double, potentially changing its value and leading to us failing to catch some UB-inducing values. The code below works correctly under the mild assumption that time_t is a two's complement integer type with no trap representation, and that `PY_TIME_T_MIN` is within the representable range of a C double. Note: we want the `if` condition below to be true for NaNs; therefore, resist any temptation to simplify by applying De Morgan's laws. */ if (!((double)PY_TIME_T_MIN <= intpart && intpart < -(double)PY_TIME_T_MIN)) { pytime_time_t_overflow(); return -1; } *sec = (time_t)intpart; *numerator = (long)floatpart; assert(0 <= *numerator && *numerator < idenominator); return 0; } static int pytime_object_to_denominator(PyObject *obj, time_t *sec, long *numerator, long denominator, _PyTime_round_t round) { assert(denominator >= 1); if (PyFloat_Check(obj)) { double d = PyFloat_AsDouble(obj); if (Py_IS_NAN(d)) { *numerator = 0; PyErr_SetString(PyExc_ValueError, "Invalid value NaN (not a number)"); return -1; } return pytime_double_to_denominator(d, sec, numerator, denominator, round); } else { *sec = _PyLong_AsTime_t(obj); *numerator = 0; if (*sec == (time_t)-1 && PyErr_Occurred()) { return -1; } return 0; } } int _PyTime_ObjectToTime_t(PyObject *obj, time_t *sec, _PyTime_round_t round) { if (PyFloat_Check(obj)) { double intpart; /* volatile avoids optimization changing how numbers are rounded */ volatile double d; d = PyFloat_AsDouble(obj); if (Py_IS_NAN(d)) { PyErr_SetString(PyExc_ValueError, "Invalid value NaN (not a number)"); return -1; } d = pytime_round(d, round); (void)modf(d, &intpart); /* See comments in pytime_double_to_denominator */ if (!((double)PY_TIME_T_MIN <= intpart && intpart < -(double)PY_TIME_T_MIN)) { pytime_time_t_overflow(); return -1; } *sec = (time_t)intpart; return 0; } else { *sec = _PyLong_AsTime_t(obj); if (*sec == (time_t)-1 && PyErr_Occurred()) { return -1; } return 0; } } int _PyTime_ObjectToTimespec(PyObject *obj, time_t *sec, long *nsec, _PyTime_round_t round) { return pytime_object_to_denominator(obj, sec, nsec, SEC_TO_NS, round); } int _PyTime_ObjectToTimeval(PyObject *obj, time_t *sec, long *usec, _PyTime_round_t round) { return pytime_object_to_denominator(obj, sec, usec, SEC_TO_US, round); } _PyTime_t _PyTime_FromSeconds(int seconds) { /* ensure that integer overflow cannot happen, int type should have 32 bits, whereas _PyTime_t type has at least 64 bits (SEC_TO_NS takes 30 bits). */ static_assert(INT_MAX <= _PyTime_MAX / SEC_TO_NS, "_PyTime_t overflow"); static_assert(INT_MIN >= _PyTime_MIN / SEC_TO_NS, "_PyTime_t underflow"); _PyTime_t t = (_PyTime_t)seconds; assert((t >= 0 && t <= _PyTime_MAX / SEC_TO_NS) || (t < 0 && t >= _PyTime_MIN / SEC_TO_NS)); t *= SEC_TO_NS; return pytime_from_nanoseconds(t); } _PyTime_t _PyTime_FromNanoseconds(_PyTime_t ns) { return pytime_from_nanoseconds(ns); } _PyTime_t _PyTime_FromMicrosecondsClamp(_PyTime_t us) { _PyTime_t ns = _PyTime_Mul(us, US_TO_NS); return pytime_from_nanoseconds(ns); } int _PyTime_FromNanosecondsObject(_PyTime_t *tp, PyObject *obj) { if (!PyLong_Check(obj)) { PyErr_Format(PyExc_TypeError, "expect int, got %s", Py_TYPE(obj)->tp_name); return -1; } static_assert(sizeof(long long) == sizeof(_PyTime_t), "_PyTime_t is not long long"); long long nsec = PyLong_AsLongLong(obj); if (nsec == -1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) { pytime_overflow(); } return -1; } _PyTime_t t = (_PyTime_t)nsec; *tp = pytime_from_nanoseconds(t); return 0; } #ifdef HAVE_CLOCK_GETTIME static int pytime_fromtimespec(_PyTime_t *tp, struct timespec *ts, int raise_exc) { _PyTime_t t, tv_nsec; static_assert(sizeof(ts->tv_sec) <= sizeof(_PyTime_t), "timespec.tv_sec is larger than _PyTime_t"); t = (_PyTime_t)ts->tv_sec; int res1 = pytime_mul(&t, SEC_TO_NS); tv_nsec = ts->tv_nsec; int res2 = pytime_add(&t, tv_nsec); *tp = pytime_from_nanoseconds(t); if (raise_exc && (res1 < 0 || res2 < 0)) { pytime_overflow(); return -1; } return 0; } int _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts) { return pytime_fromtimespec(tp, ts, 1); } #endif #ifndef MS_WINDOWS static int pytime_fromtimeval(_PyTime_t *tp, struct timeval *tv, int raise_exc) { static_assert(sizeof(tv->tv_sec) <= sizeof(_PyTime_t), "timeval.tv_sec is larger than _PyTime_t"); _PyTime_t t = (_PyTime_t)tv->tv_sec; int res1 = pytime_mul(&t, SEC_TO_NS); _PyTime_t usec = (_PyTime_t)tv->tv_usec * US_TO_NS; int res2 = pytime_add(&t, usec); *tp = pytime_from_nanoseconds(t); if (raise_exc && (res1 < 0 || res2 < 0)) { pytime_overflow(); return -1; } return 0; } int _PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv) { return pytime_fromtimeval(tp, tv, 1); } #endif static int pytime_from_double(_PyTime_t *tp, double value, _PyTime_round_t round, long unit_to_ns) { /* volatile avoids optimization changing how numbers are rounded */ volatile double d; /* convert to a number of nanoseconds */ d = value; d *= (double)unit_to_ns; d = pytime_round(d, round); /* See comments in pytime_double_to_denominator */ if (!((double)_PyTime_MIN <= d && d < -(double)_PyTime_MIN)) { pytime_time_t_overflow(); return -1; } _PyTime_t ns = (_PyTime_t)d; *tp = pytime_from_nanoseconds(ns); return 0; } static int pytime_from_object(_PyTime_t *tp, PyObject *obj, _PyTime_round_t round, long unit_to_ns) { if (PyFloat_Check(obj)) { double d; d = PyFloat_AsDouble(obj); if (Py_IS_NAN(d)) { PyErr_SetString(PyExc_ValueError, "Invalid value NaN (not a number)"); return -1; } return pytime_from_double(tp, d, round, unit_to_ns); } else { long long sec = PyLong_AsLongLong(obj); if (sec == -1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) { pytime_overflow(); } return -1; } static_assert(sizeof(long long) <= sizeof(_PyTime_t), "_PyTime_t is smaller than long long"); _PyTime_t ns = (_PyTime_t)sec; if (pytime_mul(&ns, unit_to_ns) < 0) { pytime_overflow(); return -1; } *tp = pytime_from_nanoseconds(ns); return 0; } } int _PyTime_FromSecondsObject(_PyTime_t *tp, PyObject *obj, _PyTime_round_t round) { return pytime_from_object(tp, obj, round, SEC_TO_NS); } int _PyTime_FromMillisecondsObject(_PyTime_t *tp, PyObject *obj, _PyTime_round_t round) { return pytime_from_object(tp, obj, round, MS_TO_NS); } double _PyTime_AsSecondsDouble(_PyTime_t t) { /* volatile avoids optimization changing how numbers are rounded */ volatile double d; _PyTime_t ns = pytime_as_nanoseconds(t); if (ns % SEC_TO_NS == 0) { /* Divide using integers to avoid rounding issues on the integer part. 1e-9 cannot be stored exactly in IEEE 64-bit. */ _PyTime_t secs = ns / SEC_TO_NS; d = (double)secs; } else { d = (double)ns; d /= 1e9; } return d; } PyObject * _PyTime_AsNanosecondsObject(_PyTime_t t) { _PyTime_t ns = pytime_as_nanoseconds(t); static_assert(sizeof(long long) >= sizeof(_PyTime_t), "_PyTime_t is larger than long long"); return PyLong_FromLongLong((long long)ns); } static _PyTime_t pytime_divide_round_up(const _PyTime_t t, const _PyTime_t k) { assert(k > 1); if (t >= 0) { // Don't use (t + k - 1) / k to avoid integer overflow // if t is equal to _PyTime_MAX _PyTime_t q = t / k; if (t % k) { q += 1; } return q; } else { // Don't use (t - (k - 1)) / k to avoid integer overflow // if t is equals to _PyTime_MIN. _PyTime_t q = t / k; if (t % k) { q -= 1; } return q; } } static _PyTime_t pytime_divide(const _PyTime_t t, const _PyTime_t k, const _PyTime_round_t round) { assert(k > 1); if (round == _PyTime_ROUND_HALF_EVEN) { _PyTime_t x = t / k; _PyTime_t r = t % k; _PyTime_t abs_r = Py_ABS(r); if (abs_r > k / 2 || (abs_r == k / 2 && (Py_ABS(x) & 1))) { if (t >= 0) { x++; } else { x--; } } return x; } else if (round == _PyTime_ROUND_CEILING) { if (t >= 0) { return pytime_divide_round_up(t, k); } else { return t / k; } } else if (round == _PyTime_ROUND_FLOOR){ if (t >= 0) { return t / k; } else { return pytime_divide_round_up(t, k); } } else { assert(round == _PyTime_ROUND_UP); return pytime_divide_round_up(t, k); } } // Compute (t / k, t % k) in (pq, pr). // Make sure that 0 <= pr < k. // Return 0 on success. // Return -1 on underflow and store (_PyTime_MIN, 0) in (pq, pr). static int pytime_divmod(const _PyTime_t t, const _PyTime_t k, _PyTime_t *pq, _PyTime_t *pr) { assert(k > 1); _PyTime_t q = t / k; _PyTime_t r = t % k; if (r < 0) { if (q == _PyTime_MIN) { *pq = _PyTime_MIN; *pr = 0; return -1; } r += k; q -= 1; } assert(0 <= r && r < k); *pq = q; *pr = r; return 0; } _PyTime_t _PyTime_AsNanoseconds(_PyTime_t t) { return pytime_as_nanoseconds(t); } #ifdef MS_WINDOWS _PyTime_t _PyTime_As100Nanoseconds(_PyTime_t t, _PyTime_round_t round) { _PyTime_t ns = pytime_as_nanoseconds(t); return pytime_divide(ns, NS_TO_100NS, round); } #endif _PyTime_t _PyTime_AsMicroseconds(_PyTime_t t, _PyTime_round_t round) { _PyTime_t ns = pytime_as_nanoseconds(t); return pytime_divide(ns, NS_TO_US, round); } _PyTime_t _PyTime_AsMilliseconds(_PyTime_t t, _PyTime_round_t round) { _PyTime_t ns = pytime_as_nanoseconds(t); return pytime_divide(ns, NS_TO_MS, round); } static int pytime_as_timeval(_PyTime_t t, _PyTime_t *ptv_sec, int *ptv_usec, _PyTime_round_t round) { _PyTime_t ns = pytime_as_nanoseconds(t); _PyTime_t us = pytime_divide(ns, US_TO_NS, round); _PyTime_t tv_sec, tv_usec; int res = pytime_divmod(us, SEC_TO_US, &tv_sec, &tv_usec); *ptv_sec = tv_sec; *ptv_usec = (int)tv_usec; return res; } static int pytime_as_timeval_struct(_PyTime_t t, struct timeval *tv, _PyTime_round_t round, int raise_exc) { _PyTime_t tv_sec; int tv_usec; int res = pytime_as_timeval(t, &tv_sec, &tv_usec, round); int res2; #ifdef MS_WINDOWS // On Windows, timeval.tv_sec type is long res2 = _PyTime_AsLong(tv_sec, &tv->tv_sec); #else res2 = _PyTime_AsTime_t(tv_sec, &tv->tv_sec); #endif if (res2 < 0) { tv_usec = 0; } tv->tv_usec = tv_usec; if (raise_exc && (res < 0 || res2 < 0)) { pytime_time_t_overflow(); return -1; } return 0; } int _PyTime_AsTimeval(_PyTime_t t, struct timeval *tv, _PyTime_round_t round) { return pytime_as_timeval_struct(t, tv, round, 1); } void _PyTime_AsTimeval_clamp(_PyTime_t t, struct timeval *tv, _PyTime_round_t round) { (void)pytime_as_timeval_struct(t, tv, round, 0); } int _PyTime_AsTimevalTime_t(_PyTime_t t, time_t *p_secs, int *us, _PyTime_round_t round) { _PyTime_t secs; if (pytime_as_timeval(t, &secs, us, round) < 0) { pytime_time_t_overflow(); return -1; } if (_PyTime_AsTime_t(secs, p_secs) < 0) { pytime_time_t_overflow(); return -1; } return 0; } #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_KQUEUE) static int pytime_as_timespec(_PyTime_t t, struct timespec *ts, int raise_exc) { _PyTime_t ns = pytime_as_nanoseconds(t); _PyTime_t tv_sec, tv_nsec; int res = pytime_divmod(ns, SEC_TO_NS, &tv_sec, &tv_nsec); int res2 = _PyTime_AsTime_t(tv_sec, &ts->tv_sec); if (res2 < 0) { tv_nsec = 0; } ts->tv_nsec = tv_nsec; if (raise_exc && (res < 0 || res2 < 0)) { pytime_time_t_overflow(); return -1; } return 0; } void _PyTime_AsTimespec_clamp(_PyTime_t t, struct timespec *ts) { (void)pytime_as_timespec(t, ts, 0); } int _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts) { return pytime_as_timespec(t, ts, 1); } #endif static int py_get_system_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise_exc) { assert(info == NULL || raise_exc); #ifdef MS_WINDOWS FILETIME system_time; ULARGE_INTEGER large; GetSystemTimeAsFileTime(&system_time); large.u.LowPart = system_time.dwLowDateTime; large.u.HighPart = system_time.dwHighDateTime; /* 11,644,473,600,000,000,000: number of nanoseconds between the 1st january 1601 and the 1st january 1970 (369 years + 89 leap days). */ _PyTime_t ns = large.QuadPart * 100 - 11644473600000000000; *tp = pytime_from_nanoseconds(ns); if (info) { DWORD timeAdjustment, timeIncrement; BOOL isTimeAdjustmentDisabled, ok; info->implementation = "GetSystemTimeAsFileTime()"; info->monotonic = 0; ok = GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &isTimeAdjustmentDisabled); if (!ok) { PyErr_SetFromWindowsErr(0); return -1; } info->resolution = timeIncrement * 1e-7; info->adjustable = 1; } #else /* MS_WINDOWS */ int err; #if defined(HAVE_CLOCK_GETTIME) struct timespec ts; #endif #if !defined(HAVE_CLOCK_GETTIME) || defined(__APPLE__) struct timeval tv; #endif #ifdef HAVE_CLOCK_GETTIME #ifdef HAVE_CLOCK_GETTIME_RUNTIME if (HAVE_CLOCK_GETTIME_RUNTIME) { #endif err = clock_gettime(CLOCK_REALTIME, &ts); if (err) { if (raise_exc) { PyErr_SetFromErrno(PyExc_OSError); } return -1; } if (pytime_fromtimespec(tp, &ts, raise_exc) < 0) { return -1; } if (info) { struct timespec res; info->implementation = "clock_gettime(CLOCK_REALTIME)"; info->monotonic = 0; info->adjustable = 1; if (clock_getres(CLOCK_REALTIME, &res) == 0) { info->resolution = (double)res.tv_sec + (double)res.tv_nsec * 1e-9; } else { info->resolution = 1e-9; } } #ifdef HAVE_CLOCK_GETTIME_RUNTIME } else { #endif #endif #if !defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_GETTIME_RUNTIME) /* test gettimeofday() */ err = gettimeofday(&tv, (struct timezone *)NULL); if (err) { if (raise_exc) { PyErr_SetFromErrno(PyExc_OSError); } return -1; } if (pytime_fromtimeval(tp, &tv, raise_exc) < 0) { return -1; } if (info) { info->implementation = "gettimeofday()"; info->resolution = 1e-6; info->monotonic = 0; info->adjustable = 1; } #if defined(HAVE_CLOCK_GETTIME_RUNTIME) && defined(HAVE_CLOCK_GETTIME) } /* end of availibity block */ #endif #endif /* !HAVE_CLOCK_GETTIME */ #endif /* !MS_WINDOWS */ return 0; } _PyTime_t _PyTime_GetSystemClock(void) { _PyTime_t t; if (py_get_system_clock(&t, NULL, 0) < 0) { // If clock_gettime(CLOCK_REALTIME) or gettimeofday() fails: // silently ignore the failure and return 0. t = 0; } return t; } int _PyTime_GetSystemClockWithInfo(_PyTime_t *t, _Py_clock_info_t *info) { return py_get_system_clock(t, info, 1); } #ifdef __APPLE__ static int py_mach_timebase_info(_PyTime_t *pnumer, _PyTime_t *pdenom, int raise) { static mach_timebase_info_data_t timebase; /* According to the Technical Q&A QA1398, mach_timebase_info() cannot fail: https://developer.apple.com/library/mac/#qa/qa1398/ */ (void)mach_timebase_info(&timebase); /* Sanity check: should never occur in practice */ if (timebase.numer < 1 || timebase.denom < 1) { if (raise) { PyErr_SetString(PyExc_RuntimeError, "invalid mach_timebase_info"); } return -1; } /* Check that timebase.numer and timebase.denom can be casted to _PyTime_t. In practice, timebase uses uint32_t, so casting cannot overflow. At the end, only make sure that the type is uint32_t (_PyTime_t is 64-bit long). */ static_assert(sizeof(timebase.numer) <= sizeof(_PyTime_t), "timebase.numer is larger than _PyTime_t"); static_assert(sizeof(timebase.denom) <= sizeof(_PyTime_t), "timebase.denom is larger than _PyTime_t"); /* Make sure that _PyTime_MulDiv(ticks, timebase_numer, timebase_denom) cannot overflow. Known time bases: * (1, 1) on Intel * (1000000000, 33333335) or (1000000000, 25000000) on PowerPC None of these time bases can overflow with 64-bit _PyTime_t, but check for overflow, just in case. */ if ((_PyTime_t)timebase.numer > _PyTime_MAX / (_PyTime_t)timebase.denom) { if (raise) { PyErr_SetString(PyExc_OverflowError, "mach_timebase_info is too large"); } return -1; } *pnumer = (_PyTime_t)timebase.numer; *pdenom = (_PyTime_t)timebase.denom; return 0; } #endif static int py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise_exc) { assert(info == NULL || raise_exc); #if defined(MS_WINDOWS) ULONGLONG ticks = GetTickCount64(); static_assert(sizeof(ticks) <= sizeof(_PyTime_t), "ULONGLONG is larger than _PyTime_t"); _PyTime_t t; if (ticks <= (ULONGLONG)_PyTime_MAX) { t = (_PyTime_t)ticks; } else { // GetTickCount64() maximum is larger than _PyTime_t maximum: // ULONGLONG is unsigned, whereas _PyTime_t is signed. t = _PyTime_MAX; } int res = pytime_mul(&t, MS_TO_NS); *tp = t; if (raise_exc && res < 0) { pytime_overflow(); return -1; } if (info) { DWORD timeAdjustment, timeIncrement; BOOL isTimeAdjustmentDisabled, ok; info->implementation = "GetTickCount64()"; info->monotonic = 1; ok = GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &isTimeAdjustmentDisabled); if (!ok) { PyErr_SetFromWindowsErr(0); return -1; } info->resolution = timeIncrement * 1e-7; info->adjustable = 0; } #elif defined(__APPLE__) static _PyTime_t timebase_numer = 0; static _PyTime_t timebase_denom = 0; if (timebase_denom == 0) { if (py_mach_timebase_info(&timebase_numer, &timebase_denom, raise_exc) < 0) { return -1; } } if (info) { info->implementation = "mach_absolute_time()"; info->resolution = (double)timebase_numer / (double)timebase_denom * 1e-9; info->monotonic = 1; info->adjustable = 0; } uint64_t uticks = mach_absolute_time(); // unsigned => signed assert(uticks <= (uint64_t)_PyTime_MAX); _PyTime_t ticks = (_PyTime_t)uticks; _PyTime_t ns = _PyTime_MulDiv(ticks, timebase_numer, timebase_denom); *tp = pytime_from_nanoseconds(ns); #elif defined(__hpux) hrtime_t time; time = gethrtime(); if (time == -1) { if (raise_exc) { PyErr_SetFromErrno(PyExc_OSError); } return -1; } *tp = pytime_from_nanoseconds(time); if (info) { info->implementation = "gethrtime()"; info->resolution = 1e-9; info->monotonic = 1; info->adjustable = 0; } #else #ifdef CLOCK_HIGHRES const clockid_t clk_id = CLOCK_HIGHRES; const char *implementation = "clock_gettime(CLOCK_HIGHRES)"; #else const clockid_t clk_id = CLOCK_MONOTONIC; const char *implementation = "clock_gettime(CLOCK_MONOTONIC)"; #endif struct timespec ts; if (clock_gettime(clk_id, &ts) != 0) { if (raise_exc) { PyErr_SetFromErrno(PyExc_OSError); return -1; } return -1; } if (pytime_fromtimespec(tp, &ts, raise_exc) < 0) { return -1; } if (info) { info->monotonic = 1; info->implementation = implementation; info->adjustable = 0; struct timespec res; if (clock_getres(clk_id, &res) != 0) { PyErr_SetFromErrno(PyExc_OSError); return -1; } info->resolution = res.tv_sec + res.tv_nsec * 1e-9; } #endif return 0; } _PyTime_t _PyTime_GetMonotonicClock(void) { _PyTime_t t; if (py_get_monotonic_clock(&t, NULL, 0) < 0) { // If mach_timebase_info(), clock_gettime() or gethrtime() fails: // silently ignore the failure and return 0. t = 0; } return t; } int _PyTime_GetMonotonicClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) { return py_get_monotonic_clock(tp, info, 1); } #ifdef MS_WINDOWS static int py_win_perf_counter_frequency(LONGLONG *pfrequency, int raise) { LONGLONG frequency; LARGE_INTEGER freq; // Since Windows XP, the function cannot fail. (void)QueryPerformanceFrequency(&freq); frequency = freq.QuadPart; // Since Windows XP, frequency cannot be zero. assert(frequency >= 1); /* Make also sure that (ticks * SEC_TO_NS) cannot overflow in _PyTime_MulDiv(), with ticks < frequency. Known QueryPerformanceFrequency() values: * 10,000,000 (10 MHz): 100 ns resolution * 3,579,545 Hz (3.6 MHz): 279 ns resolution None of these frequencies can overflow with 64-bit _PyTime_t, but check for integer overflow just in case. */ if (frequency > _PyTime_MAX / SEC_TO_NS) { if (raise) { PyErr_SetString(PyExc_OverflowError, "QueryPerformanceFrequency is too large"); } return -1; } *pfrequency = frequency; return 0; } static int py_get_win_perf_counter(_PyTime_t *tp, _Py_clock_info_t *info, int raise_exc) { assert(info == NULL || raise_exc); static LONGLONG frequency = 0; if (frequency == 0) { if (py_win_perf_counter_frequency(&frequency, raise_exc) < 0) { return -1; } } if (info) { info->implementation = "QueryPerformanceCounter()"; info->resolution = 1.0 / (double)frequency; info->monotonic = 1; info->adjustable = 0; } LARGE_INTEGER now; QueryPerformanceCounter(&now); LONGLONG ticksll = now.QuadPart; /* Make sure that casting LONGLONG to _PyTime_t cannot overflow, both types are signed */ _PyTime_t ticks; static_assert(sizeof(ticksll) <= sizeof(ticks), "LONGLONG is larger than _PyTime_t"); ticks = (_PyTime_t)ticksll; _PyTime_t ns = _PyTime_MulDiv(ticks, SEC_TO_NS, (_PyTime_t)frequency); *tp = pytime_from_nanoseconds(ns); return 0; } #endif // MS_WINDOWS int _PyTime_GetPerfCounterWithInfo(_PyTime_t *t, _Py_clock_info_t *info) { #ifdef MS_WINDOWS return py_get_win_perf_counter(t, info, 1); #else return _PyTime_GetMonotonicClockWithInfo(t, info); #endif } _PyTime_t _PyTime_GetPerfCounter(void) { _PyTime_t t; int res; #ifdef MS_WINDOWS res = py_get_win_perf_counter(&t, NULL, 0); #else res = py_get_monotonic_clock(&t, NULL, 0); #endif if (res < 0) { // If py_win_perf_counter_frequency() or py_get_monotonic_clock() // fails: silently ignore the failure and return 0. t = 0; } return t; } int _PyTime_localtime(time_t t, struct tm *tm) { #ifdef MS_WINDOWS int error; error = localtime_s(tm, &t); if (error != 0) { errno = error; PyErr_SetFromErrno(PyExc_OSError); return -1; } return 0; #else /* !MS_WINDOWS */ #if defined(_AIX) && (SIZEOF_TIME_T < 8) /* bpo-34373: AIX does not return NULL if t is too small or too large */ if (t < -2145916800 /* 1902-01-01 */ || t > 2145916800 /* 2038-01-01 */) { errno = EINVAL; PyErr_SetString(PyExc_OverflowError, "localtime argument out of range"); return -1; } #endif errno = 0; if (localtime_r(&t, tm) == NULL) { if (errno == 0) { errno = EINVAL; } PyErr_SetFromErrno(PyExc_OSError); return -1; } return 0; #endif /* MS_WINDOWS */ } int _PyTime_gmtime(time_t t, struct tm *tm) { #ifdef MS_WINDOWS int error; error = gmtime_s(tm, &t); if (error != 0) { errno = error; PyErr_SetFromErrno(PyExc_OSError); return -1; } return 0; #else /* !MS_WINDOWS */ if (gmtime_r(&t, tm) == NULL) { #ifdef EINVAL if (errno == 0) { errno = EINVAL; } #endif PyErr_SetFromErrno(PyExc_OSError); return -1; } return 0; #endif /* MS_WINDOWS */ } _PyTime_t _PyDeadline_Init(_PyTime_t timeout) { _PyTime_t now = _PyTime_GetMonotonicClock(); return _PyTime_Add(now, timeout); } _PyTime_t _PyDeadline_Get(_PyTime_t deadline) { _PyTime_t now = _PyTime_GetMonotonicClock(); return deadline - now; } ================================================ FILE: Python-AST.c ================================================ // File automatically generated by Parser/asdl_c.py. #include "Python.h" #include "pycore_ast.h" #include "pycore_ast_state.h" // struct ast_state #include "pycore_ceval.h" // _Py_EnterRecursiveCall #include "pycore_interp.h" // _PyInterpreterState.ast #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "structmember.h" #include // Forward declaration static int init_types(struct ast_state *state); static struct ast_state* get_ast_state(void) { PyInterpreterState *interp = _PyInterpreterState_GET(); struct ast_state *state = &interp->ast; if (!init_types(state)) { return NULL; } return state; } void _PyAST_Fini(PyInterpreterState *interp) { struct ast_state *state = &interp->ast; Py_CLEAR(state->AST_type); Py_CLEAR(state->Add_singleton); Py_CLEAR(state->Add_type); Py_CLEAR(state->And_singleton); Py_CLEAR(state->And_type); Py_CLEAR(state->AnnAssign_type); Py_CLEAR(state->Assert_type); Py_CLEAR(state->Assign_type); Py_CLEAR(state->AsyncFor_type); Py_CLEAR(state->AsyncFunctionDef_type); Py_CLEAR(state->AsyncWith_type); Py_CLEAR(state->Attribute_type); Py_CLEAR(state->AugAssign_type); Py_CLEAR(state->Await_type); Py_CLEAR(state->BinOp_type); Py_CLEAR(state->BitAnd_singleton); Py_CLEAR(state->BitAnd_type); Py_CLEAR(state->BitOr_singleton); Py_CLEAR(state->BitOr_type); Py_CLEAR(state->BitXor_singleton); Py_CLEAR(state->BitXor_type); Py_CLEAR(state->BoolOp_type); Py_CLEAR(state->Break_type); Py_CLEAR(state->Call_type); Py_CLEAR(state->ClassDef_type); Py_CLEAR(state->Compare_type); Py_CLEAR(state->Constant_type); Py_CLEAR(state->Continue_type); Py_CLEAR(state->Del_singleton); Py_CLEAR(state->Del_type); Py_CLEAR(state->Delete_type); Py_CLEAR(state->DictComp_type); Py_CLEAR(state->Dict_type); Py_CLEAR(state->Div_singleton); Py_CLEAR(state->Div_type); Py_CLEAR(state->Eq_singleton); Py_CLEAR(state->Eq_type); Py_CLEAR(state->ExceptHandler_type); Py_CLEAR(state->Expr_type); Py_CLEAR(state->Expression_type); Py_CLEAR(state->FloorDiv_singleton); Py_CLEAR(state->FloorDiv_type); Py_CLEAR(state->For_type); Py_CLEAR(state->FormattedValue_type); Py_CLEAR(state->FunctionDef_type); Py_CLEAR(state->FunctionType_type); Py_CLEAR(state->GeneratorExp_type); Py_CLEAR(state->Global_type); Py_CLEAR(state->GtE_singleton); Py_CLEAR(state->GtE_type); Py_CLEAR(state->Gt_singleton); Py_CLEAR(state->Gt_type); Py_CLEAR(state->IfExp_type); Py_CLEAR(state->If_type); Py_CLEAR(state->ImportFrom_type); Py_CLEAR(state->Import_type); Py_CLEAR(state->In_singleton); Py_CLEAR(state->In_type); Py_CLEAR(state->Interactive_type); Py_CLEAR(state->Invert_singleton); Py_CLEAR(state->Invert_type); Py_CLEAR(state->IsNot_singleton); Py_CLEAR(state->IsNot_type); Py_CLEAR(state->Is_singleton); Py_CLEAR(state->Is_type); Py_CLEAR(state->JoinedStr_type); Py_CLEAR(state->LShift_singleton); Py_CLEAR(state->LShift_type); Py_CLEAR(state->Lambda_type); Py_CLEAR(state->ListComp_type); Py_CLEAR(state->List_type); Py_CLEAR(state->Load_singleton); Py_CLEAR(state->Load_type); Py_CLEAR(state->LtE_singleton); Py_CLEAR(state->LtE_type); Py_CLEAR(state->Lt_singleton); Py_CLEAR(state->Lt_type); Py_CLEAR(state->MatMult_singleton); Py_CLEAR(state->MatMult_type); Py_CLEAR(state->MatchAs_type); Py_CLEAR(state->MatchClass_type); Py_CLEAR(state->MatchMapping_type); Py_CLEAR(state->MatchOr_type); Py_CLEAR(state->MatchSequence_type); Py_CLEAR(state->MatchSingleton_type); Py_CLEAR(state->MatchStar_type); Py_CLEAR(state->MatchValue_type); Py_CLEAR(state->Match_type); Py_CLEAR(state->Mod_singleton); Py_CLEAR(state->Mod_type); Py_CLEAR(state->Module_type); Py_CLEAR(state->Mult_singleton); Py_CLEAR(state->Mult_type); Py_CLEAR(state->Name_type); Py_CLEAR(state->NamedExpr_type); Py_CLEAR(state->Nonlocal_type); Py_CLEAR(state->NotEq_singleton); Py_CLEAR(state->NotEq_type); Py_CLEAR(state->NotIn_singleton); Py_CLEAR(state->NotIn_type); Py_CLEAR(state->Not_singleton); Py_CLEAR(state->Not_type); Py_CLEAR(state->Or_singleton); Py_CLEAR(state->Or_type); Py_CLEAR(state->ParamSpec_type); Py_CLEAR(state->Pass_type); Py_CLEAR(state->Pow_singleton); Py_CLEAR(state->Pow_type); Py_CLEAR(state->RShift_singleton); Py_CLEAR(state->RShift_type); Py_CLEAR(state->Raise_type); Py_CLEAR(state->Return_type); Py_CLEAR(state->SetComp_type); Py_CLEAR(state->Set_type); Py_CLEAR(state->Slice_type); Py_CLEAR(state->Starred_type); Py_CLEAR(state->Store_singleton); Py_CLEAR(state->Store_type); Py_CLEAR(state->Sub_singleton); Py_CLEAR(state->Sub_type); Py_CLEAR(state->Subscript_type); Py_CLEAR(state->TryStar_type); Py_CLEAR(state->Try_type); Py_CLEAR(state->Tuple_type); Py_CLEAR(state->TypeAlias_type); Py_CLEAR(state->TypeIgnore_type); Py_CLEAR(state->TypeVarTuple_type); Py_CLEAR(state->TypeVar_type); Py_CLEAR(state->UAdd_singleton); Py_CLEAR(state->UAdd_type); Py_CLEAR(state->USub_singleton); Py_CLEAR(state->USub_type); Py_CLEAR(state->UnaryOp_type); Py_CLEAR(state->While_type); Py_CLEAR(state->With_type); Py_CLEAR(state->YieldFrom_type); Py_CLEAR(state->Yield_type); Py_CLEAR(state->__dict__); Py_CLEAR(state->__doc__); Py_CLEAR(state->__match_args__); Py_CLEAR(state->__module__); Py_CLEAR(state->_attributes); Py_CLEAR(state->_fields); Py_CLEAR(state->alias_type); Py_CLEAR(state->annotation); Py_CLEAR(state->arg); Py_CLEAR(state->arg_type); Py_CLEAR(state->args); Py_CLEAR(state->argtypes); Py_CLEAR(state->arguments_type); Py_CLEAR(state->asname); Py_CLEAR(state->ast); Py_CLEAR(state->attr); Py_CLEAR(state->bases); Py_CLEAR(state->body); Py_CLEAR(state->boolop_type); Py_CLEAR(state->bound); Py_CLEAR(state->cases); Py_CLEAR(state->cause); Py_CLEAR(state->cls); Py_CLEAR(state->cmpop_type); Py_CLEAR(state->col_offset); Py_CLEAR(state->comparators); Py_CLEAR(state->comprehension_type); Py_CLEAR(state->context_expr); Py_CLEAR(state->conversion); Py_CLEAR(state->ctx); Py_CLEAR(state->decorator_list); Py_CLEAR(state->defaults); Py_CLEAR(state->elt); Py_CLEAR(state->elts); Py_CLEAR(state->end_col_offset); Py_CLEAR(state->end_lineno); Py_CLEAR(state->exc); Py_CLEAR(state->excepthandler_type); Py_CLEAR(state->expr_context_type); Py_CLEAR(state->expr_type); Py_CLEAR(state->finalbody); Py_CLEAR(state->format_spec); Py_CLEAR(state->func); Py_CLEAR(state->generators); Py_CLEAR(state->guard); Py_CLEAR(state->handlers); Py_CLEAR(state->id); Py_CLEAR(state->ifs); Py_CLEAR(state->is_async); Py_CLEAR(state->items); Py_CLEAR(state->iter); Py_CLEAR(state->key); Py_CLEAR(state->keys); Py_CLEAR(state->keyword_type); Py_CLEAR(state->keywords); Py_CLEAR(state->kind); Py_CLEAR(state->kw_defaults); Py_CLEAR(state->kwarg); Py_CLEAR(state->kwd_attrs); Py_CLEAR(state->kwd_patterns); Py_CLEAR(state->kwonlyargs); Py_CLEAR(state->left); Py_CLEAR(state->level); Py_CLEAR(state->lineno); Py_CLEAR(state->lower); Py_CLEAR(state->match_case_type); Py_CLEAR(state->mod_type); Py_CLEAR(state->module); Py_CLEAR(state->msg); Py_CLEAR(state->name); Py_CLEAR(state->names); Py_CLEAR(state->op); Py_CLEAR(state->operand); Py_CLEAR(state->operator_type); Py_CLEAR(state->ops); Py_CLEAR(state->optional_vars); Py_CLEAR(state->orelse); Py_CLEAR(state->pattern); Py_CLEAR(state->pattern_type); Py_CLEAR(state->patterns); Py_CLEAR(state->posonlyargs); Py_CLEAR(state->rest); Py_CLEAR(state->returns); Py_CLEAR(state->right); Py_CLEAR(state->simple); Py_CLEAR(state->slice); Py_CLEAR(state->step); Py_CLEAR(state->stmt_type); Py_CLEAR(state->subject); Py_CLEAR(state->tag); Py_CLEAR(state->target); Py_CLEAR(state->targets); Py_CLEAR(state->test); Py_CLEAR(state->type); Py_CLEAR(state->type_comment); Py_CLEAR(state->type_ignore_type); Py_CLEAR(state->type_ignores); Py_CLEAR(state->type_param_type); Py_CLEAR(state->type_params); Py_CLEAR(state->unaryop_type); Py_CLEAR(state->upper); Py_CLEAR(state->value); Py_CLEAR(state->values); Py_CLEAR(state->vararg); Py_CLEAR(state->withitem_type); Py_CLEAR(_Py_INTERP_CACHED_OBJECT(interp, str_replace_inf)); #if !defined(NDEBUG) state->initialized = -1; #else state->initialized = 0; #endif } static int init_identifiers(struct ast_state *state) { if ((state->__dict__ = PyUnicode_InternFromString("__dict__")) == NULL) return 0; if ((state->__doc__ = PyUnicode_InternFromString("__doc__")) == NULL) return 0; if ((state->__match_args__ = PyUnicode_InternFromString("__match_args__")) == NULL) return 0; if ((state->__module__ = PyUnicode_InternFromString("__module__")) == NULL) return 0; if ((state->_attributes = PyUnicode_InternFromString("_attributes")) == NULL) return 0; if ((state->_fields = PyUnicode_InternFromString("_fields")) == NULL) return 0; if ((state->annotation = PyUnicode_InternFromString("annotation")) == NULL) return 0; if ((state->arg = PyUnicode_InternFromString("arg")) == NULL) return 0; if ((state->args = PyUnicode_InternFromString("args")) == NULL) return 0; if ((state->argtypes = PyUnicode_InternFromString("argtypes")) == NULL) return 0; if ((state->asname = PyUnicode_InternFromString("asname")) == NULL) return 0; if ((state->ast = PyUnicode_InternFromString("ast")) == NULL) return 0; if ((state->attr = PyUnicode_InternFromString("attr")) == NULL) return 0; if ((state->bases = PyUnicode_InternFromString("bases")) == NULL) return 0; if ((state->body = PyUnicode_InternFromString("body")) == NULL) return 0; if ((state->bound = PyUnicode_InternFromString("bound")) == NULL) return 0; if ((state->cases = PyUnicode_InternFromString("cases")) == NULL) return 0; if ((state->cause = PyUnicode_InternFromString("cause")) == NULL) return 0; if ((state->cls = PyUnicode_InternFromString("cls")) == NULL) return 0; if ((state->col_offset = PyUnicode_InternFromString("col_offset")) == NULL) return 0; if ((state->comparators = PyUnicode_InternFromString("comparators")) == NULL) return 0; if ((state->context_expr = PyUnicode_InternFromString("context_expr")) == NULL) return 0; if ((state->conversion = PyUnicode_InternFromString("conversion")) == NULL) return 0; if ((state->ctx = PyUnicode_InternFromString("ctx")) == NULL) return 0; if ((state->decorator_list = PyUnicode_InternFromString("decorator_list")) == NULL) return 0; if ((state->defaults = PyUnicode_InternFromString("defaults")) == NULL) return 0; if ((state->elt = PyUnicode_InternFromString("elt")) == NULL) return 0; if ((state->elts = PyUnicode_InternFromString("elts")) == NULL) return 0; if ((state->end_col_offset = PyUnicode_InternFromString("end_col_offset")) == NULL) return 0; if ((state->end_lineno = PyUnicode_InternFromString("end_lineno")) == NULL) return 0; if ((state->exc = PyUnicode_InternFromString("exc")) == NULL) return 0; if ((state->finalbody = PyUnicode_InternFromString("finalbody")) == NULL) return 0; if ((state->format_spec = PyUnicode_InternFromString("format_spec")) == NULL) return 0; if ((state->func = PyUnicode_InternFromString("func")) == NULL) return 0; if ((state->generators = PyUnicode_InternFromString("generators")) == NULL) return 0; if ((state->guard = PyUnicode_InternFromString("guard")) == NULL) return 0; if ((state->handlers = PyUnicode_InternFromString("handlers")) == NULL) return 0; if ((state->id = PyUnicode_InternFromString("id")) == NULL) return 0; if ((state->ifs = PyUnicode_InternFromString("ifs")) == NULL) return 0; if ((state->is_async = PyUnicode_InternFromString("is_async")) == NULL) return 0; if ((state->items = PyUnicode_InternFromString("items")) == NULL) return 0; if ((state->iter = PyUnicode_InternFromString("iter")) == NULL) return 0; if ((state->key = PyUnicode_InternFromString("key")) == NULL) return 0; if ((state->keys = PyUnicode_InternFromString("keys")) == NULL) return 0; if ((state->keywords = PyUnicode_InternFromString("keywords")) == NULL) return 0; if ((state->kind = PyUnicode_InternFromString("kind")) == NULL) return 0; if ((state->kw_defaults = PyUnicode_InternFromString("kw_defaults")) == NULL) return 0; if ((state->kwarg = PyUnicode_InternFromString("kwarg")) == NULL) return 0; if ((state->kwd_attrs = PyUnicode_InternFromString("kwd_attrs")) == NULL) return 0; if ((state->kwd_patterns = PyUnicode_InternFromString("kwd_patterns")) == NULL) return 0; if ((state->kwonlyargs = PyUnicode_InternFromString("kwonlyargs")) == NULL) return 0; if ((state->left = PyUnicode_InternFromString("left")) == NULL) return 0; if ((state->level = PyUnicode_InternFromString("level")) == NULL) return 0; if ((state->lineno = PyUnicode_InternFromString("lineno")) == NULL) return 0; if ((state->lower = PyUnicode_InternFromString("lower")) == NULL) return 0; if ((state->module = PyUnicode_InternFromString("module")) == NULL) return 0; if ((state->msg = PyUnicode_InternFromString("msg")) == NULL) return 0; if ((state->name = PyUnicode_InternFromString("name")) == NULL) return 0; if ((state->names = PyUnicode_InternFromString("names")) == NULL) return 0; if ((state->op = PyUnicode_InternFromString("op")) == NULL) return 0; if ((state->operand = PyUnicode_InternFromString("operand")) == NULL) return 0; if ((state->ops = PyUnicode_InternFromString("ops")) == NULL) return 0; if ((state->optional_vars = PyUnicode_InternFromString("optional_vars")) == NULL) return 0; if ((state->orelse = PyUnicode_InternFromString("orelse")) == NULL) return 0; if ((state->pattern = PyUnicode_InternFromString("pattern")) == NULL) return 0; if ((state->patterns = PyUnicode_InternFromString("patterns")) == NULL) return 0; if ((state->posonlyargs = PyUnicode_InternFromString("posonlyargs")) == NULL) return 0; if ((state->rest = PyUnicode_InternFromString("rest")) == NULL) return 0; if ((state->returns = PyUnicode_InternFromString("returns")) == NULL) return 0; if ((state->right = PyUnicode_InternFromString("right")) == NULL) return 0; if ((state->simple = PyUnicode_InternFromString("simple")) == NULL) return 0; if ((state->slice = PyUnicode_InternFromString("slice")) == NULL) return 0; if ((state->step = PyUnicode_InternFromString("step")) == NULL) return 0; if ((state->subject = PyUnicode_InternFromString("subject")) == NULL) return 0; if ((state->tag = PyUnicode_InternFromString("tag")) == NULL) return 0; if ((state->target = PyUnicode_InternFromString("target")) == NULL) return 0; if ((state->targets = PyUnicode_InternFromString("targets")) == NULL) return 0; if ((state->test = PyUnicode_InternFromString("test")) == NULL) return 0; if ((state->type = PyUnicode_InternFromString("type")) == NULL) return 0; if ((state->type_comment = PyUnicode_InternFromString("type_comment")) == NULL) return 0; if ((state->type_ignores = PyUnicode_InternFromString("type_ignores")) == NULL) return 0; if ((state->type_params = PyUnicode_InternFromString("type_params")) == NULL) return 0; if ((state->upper = PyUnicode_InternFromString("upper")) == NULL) return 0; if ((state->value = PyUnicode_InternFromString("value")) == NULL) return 0; if ((state->values = PyUnicode_InternFromString("values")) == NULL) return 0; if ((state->vararg = PyUnicode_InternFromString("vararg")) == NULL) return 0; return 1; }; GENERATE_ASDL_SEQ_CONSTRUCTOR(mod, mod_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(stmt, stmt_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(expr, expr_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(comprehension, comprehension_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(excepthandler, excepthandler_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(arguments, arguments_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(arg, arg_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(keyword, keyword_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(alias, alias_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(withitem, withitem_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(match_case, match_case_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(pattern, pattern_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(type_ignore, type_ignore_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(type_param, type_param_ty) static PyObject* ast2obj_mod(struct ast_state *state, void*); static const char * const Module_fields[]={ "body", "type_ignores", }; static const char * const Interactive_fields[]={ "body", }; static const char * const Expression_fields[]={ "body", }; static const char * const FunctionType_fields[]={ "argtypes", "returns", }; static const char * const stmt_attributes[] = { "lineno", "col_offset", "end_lineno", "end_col_offset", }; static PyObject* ast2obj_stmt(struct ast_state *state, void*); static const char * const FunctionDef_fields[]={ "name", "args", "body", "decorator_list", "returns", "type_comment", "type_params", }; static const char * const AsyncFunctionDef_fields[]={ "name", "args", "body", "decorator_list", "returns", "type_comment", "type_params", }; static const char * const ClassDef_fields[]={ "name", "bases", "keywords", "body", "decorator_list", "type_params", }; static const char * const Return_fields[]={ "value", }; static const char * const Delete_fields[]={ "targets", }; static const char * const Assign_fields[]={ "targets", "value", "type_comment", }; static const char * const TypeAlias_fields[]={ "name", "type_params", "value", }; static const char * const AugAssign_fields[]={ "target", "op", "value", }; static const char * const AnnAssign_fields[]={ "target", "annotation", "value", "simple", }; static const char * const For_fields[]={ "target", "iter", "body", "orelse", "type_comment", }; static const char * const AsyncFor_fields[]={ "target", "iter", "body", "orelse", "type_comment", }; static const char * const While_fields[]={ "test", "body", "orelse", }; static const char * const If_fields[]={ "test", "body", "orelse", }; static const char * const With_fields[]={ "items", "body", "type_comment", }; static const char * const AsyncWith_fields[]={ "items", "body", "type_comment", }; static const char * const Match_fields[]={ "subject", "cases", }; static const char * const Raise_fields[]={ "exc", "cause", }; static const char * const Try_fields[]={ "body", "handlers", "orelse", "finalbody", }; static const char * const TryStar_fields[]={ "body", "handlers", "orelse", "finalbody", }; static const char * const Assert_fields[]={ "test", "msg", }; static const char * const Import_fields[]={ "names", }; static const char * const ImportFrom_fields[]={ "module", "names", "level", }; static const char * const Global_fields[]={ "names", }; static const char * const Nonlocal_fields[]={ "names", }; static const char * const Expr_fields[]={ "value", }; static const char * const expr_attributes[] = { "lineno", "col_offset", "end_lineno", "end_col_offset", }; static PyObject* ast2obj_expr(struct ast_state *state, void*); static const char * const BoolOp_fields[]={ "op", "values", }; static const char * const NamedExpr_fields[]={ "target", "value", }; static const char * const BinOp_fields[]={ "left", "op", "right", }; static const char * const UnaryOp_fields[]={ "op", "operand", }; static const char * const Lambda_fields[]={ "args", "body", }; static const char * const IfExp_fields[]={ "test", "body", "orelse", }; static const char * const Dict_fields[]={ "keys", "values", }; static const char * const Set_fields[]={ "elts", }; static const char * const ListComp_fields[]={ "elt", "generators", }; static const char * const SetComp_fields[]={ "elt", "generators", }; static const char * const DictComp_fields[]={ "key", "value", "generators", }; static const char * const GeneratorExp_fields[]={ "elt", "generators", }; static const char * const Await_fields[]={ "value", }; static const char * const Yield_fields[]={ "value", }; static const char * const YieldFrom_fields[]={ "value", }; static const char * const Compare_fields[]={ "left", "ops", "comparators", }; static const char * const Call_fields[]={ "func", "args", "keywords", }; static const char * const FormattedValue_fields[]={ "value", "conversion", "format_spec", }; static const char * const JoinedStr_fields[]={ "values", }; static const char * const Constant_fields[]={ "value", "kind", }; static const char * const Attribute_fields[]={ "value", "attr", "ctx", }; static const char * const Subscript_fields[]={ "value", "slice", "ctx", }; static const char * const Starred_fields[]={ "value", "ctx", }; static const char * const Name_fields[]={ "id", "ctx", }; static const char * const List_fields[]={ "elts", "ctx", }; static const char * const Tuple_fields[]={ "elts", "ctx", }; static const char * const Slice_fields[]={ "lower", "upper", "step", }; static PyObject* ast2obj_expr_context(struct ast_state *state, expr_context_ty); static PyObject* ast2obj_boolop(struct ast_state *state, boolop_ty); static PyObject* ast2obj_operator(struct ast_state *state, operator_ty); static PyObject* ast2obj_unaryop(struct ast_state *state, unaryop_ty); static PyObject* ast2obj_cmpop(struct ast_state *state, cmpop_ty); static PyObject* ast2obj_comprehension(struct ast_state *state, void*); static const char * const comprehension_fields[]={ "target", "iter", "ifs", "is_async", }; static const char * const excepthandler_attributes[] = { "lineno", "col_offset", "end_lineno", "end_col_offset", }; static PyObject* ast2obj_excepthandler(struct ast_state *state, void*); static const char * const ExceptHandler_fields[]={ "type", "name", "body", }; static PyObject* ast2obj_arguments(struct ast_state *state, void*); static const char * const arguments_fields[]={ "posonlyargs", "args", "vararg", "kwonlyargs", "kw_defaults", "kwarg", "defaults", }; static PyObject* ast2obj_arg(struct ast_state *state, void*); static const char * const arg_attributes[] = { "lineno", "col_offset", "end_lineno", "end_col_offset", }; static const char * const arg_fields[]={ "arg", "annotation", "type_comment", }; static PyObject* ast2obj_keyword(struct ast_state *state, void*); static const char * const keyword_attributes[] = { "lineno", "col_offset", "end_lineno", "end_col_offset", }; static const char * const keyword_fields[]={ "arg", "value", }; static PyObject* ast2obj_alias(struct ast_state *state, void*); static const char * const alias_attributes[] = { "lineno", "col_offset", "end_lineno", "end_col_offset", }; static const char * const alias_fields[]={ "name", "asname", }; static PyObject* ast2obj_withitem(struct ast_state *state, void*); static const char * const withitem_fields[]={ "context_expr", "optional_vars", }; static PyObject* ast2obj_match_case(struct ast_state *state, void*); static const char * const match_case_fields[]={ "pattern", "guard", "body", }; static const char * const pattern_attributes[] = { "lineno", "col_offset", "end_lineno", "end_col_offset", }; static PyObject* ast2obj_pattern(struct ast_state *state, void*); static const char * const MatchValue_fields[]={ "value", }; static const char * const MatchSingleton_fields[]={ "value", }; static const char * const MatchSequence_fields[]={ "patterns", }; static const char * const MatchMapping_fields[]={ "keys", "patterns", "rest", }; static const char * const MatchClass_fields[]={ "cls", "patterns", "kwd_attrs", "kwd_patterns", }; static const char * const MatchStar_fields[]={ "name", }; static const char * const MatchAs_fields[]={ "pattern", "name", }; static const char * const MatchOr_fields[]={ "patterns", }; static PyObject* ast2obj_type_ignore(struct ast_state *state, void*); static const char * const TypeIgnore_fields[]={ "lineno", "tag", }; static const char * const type_param_attributes[] = { "lineno", "col_offset", "end_lineno", "end_col_offset", }; static PyObject* ast2obj_type_param(struct ast_state *state, void*); static const char * const TypeVar_fields[]={ "name", "bound", }; static const char * const ParamSpec_fields[]={ "name", }; static const char * const TypeVarTuple_fields[]={ "name", }; typedef struct { PyObject_HEAD PyObject *dict; } AST_object; static void ast_dealloc(AST_object *self) { /* bpo-31095: UnTrack is needed before calling any callbacks */ PyTypeObject *tp = Py_TYPE(self); PyObject_GC_UnTrack(self); Py_CLEAR(self->dict); freefunc free_func = PyType_GetSlot(tp, Py_tp_free); assert(free_func != NULL); free_func(self); Py_DECREF(tp); } static int ast_traverse(AST_object *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); Py_VISIT(self->dict); return 0; } static int ast_clear(AST_object *self) { Py_CLEAR(self->dict); return 0; } static int ast_type_init(PyObject *self, PyObject *args, PyObject *kw) { struct ast_state *state = get_ast_state(); if (state == NULL) { return -1; } Py_ssize_t i, numfields = 0; int res = -1; PyObject *key, *value, *fields; if (_PyObject_LookupAttr((PyObject*)Py_TYPE(self), state->_fields, &fields) < 0) { goto cleanup; } if (fields) { numfields = PySequence_Size(fields); if (numfields == -1) { goto cleanup; } } res = 0; /* if no error occurs, this stays 0 to the end */ if (numfields < PyTuple_GET_SIZE(args)) { PyErr_Format(PyExc_TypeError, "%.400s constructor takes at most " "%zd positional argument%s", _PyType_Name(Py_TYPE(self)), numfields, numfields == 1 ? "" : "s"); res = -1; goto cleanup; } for (i = 0; i < PyTuple_GET_SIZE(args); i++) { /* cannot be reached when fields is NULL */ PyObject *name = PySequence_GetItem(fields, i); if (!name) { res = -1; goto cleanup; } res = PyObject_SetAttr(self, name, PyTuple_GET_ITEM(args, i)); Py_DECREF(name); if (res < 0) { goto cleanup; } } if (kw) { i = 0; /* needed by PyDict_Next */ while (PyDict_Next(kw, &i, &key, &value)) { int contains = PySequence_Contains(fields, key); if (contains == -1) { res = -1; goto cleanup; } else if (contains == 1) { Py_ssize_t p = PySequence_Index(fields, key); if (p == -1) { res = -1; goto cleanup; } if (p < PyTuple_GET_SIZE(args)) { PyErr_Format(PyExc_TypeError, "%.400s got multiple values for argument '%U'", Py_TYPE(self)->tp_name, key); res = -1; goto cleanup; } } res = PyObject_SetAttr(self, key, value); if (res < 0) { goto cleanup; } } } cleanup: Py_XDECREF(fields); return res; } /* Pickling support */ static PyObject * ast_type_reduce(PyObject *self, PyObject *unused) { struct ast_state *state = get_ast_state(); if (state == NULL) { return NULL; } PyObject *dict; if (_PyObject_LookupAttr(self, state->__dict__, &dict) < 0) { return NULL; } if (dict) { return Py_BuildValue("O()N", Py_TYPE(self), dict); } return Py_BuildValue("O()", Py_TYPE(self)); } static PyMemberDef ast_type_members[] = { {"__dictoffset__", T_PYSSIZET, offsetof(AST_object, dict), READONLY}, {NULL} /* Sentinel */ }; static PyMethodDef ast_type_methods[] = { {"__reduce__", ast_type_reduce, METH_NOARGS, NULL}, {NULL} }; static PyGetSetDef ast_type_getsets[] = { {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, {NULL} }; static PyType_Slot AST_type_slots[] = { {Py_tp_dealloc, ast_dealloc}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_setattro, PyObject_GenericSetAttr}, {Py_tp_traverse, ast_traverse}, {Py_tp_clear, ast_clear}, {Py_tp_members, ast_type_members}, {Py_tp_methods, ast_type_methods}, {Py_tp_getset, ast_type_getsets}, {Py_tp_init, ast_type_init}, {Py_tp_alloc, PyType_GenericAlloc}, {Py_tp_new, PyType_GenericNew}, {Py_tp_free, PyObject_GC_Del}, {0, 0}, }; static PyType_Spec AST_type_spec = { "ast.AST", sizeof(AST_object), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, AST_type_slots }; static PyObject * make_type(struct ast_state *state, const char *type, PyObject* base, const char* const* fields, int num_fields, const char *doc) { PyObject *fnames, *result; int i; fnames = PyTuple_New(num_fields); if (!fnames) return NULL; for (i = 0; i < num_fields; i++) { PyObject *field = PyUnicode_InternFromString(fields[i]); if (!field) { Py_DECREF(fnames); return NULL; } PyTuple_SET_ITEM(fnames, i, field); } result = PyObject_CallFunction((PyObject*)&PyType_Type, "s(O){OOOOOOOs}", type, base, state->_fields, fnames, state->__match_args__, fnames, state->__module__, state->ast, state->__doc__, doc); Py_DECREF(fnames); return result; } static int add_attributes(struct ast_state *state, PyObject *type, const char * const *attrs, int num_fields) { int i, result; PyObject *s, *l = PyTuple_New(num_fields); if (!l) return 0; for (i = 0; i < num_fields; i++) { s = PyUnicode_InternFromString(attrs[i]); if (!s) { Py_DECREF(l); return 0; } PyTuple_SET_ITEM(l, i, s); } result = PyObject_SetAttr(type, state->_attributes, l) >= 0; Py_DECREF(l); return result; } /* Conversion AST -> Python */ static PyObject* ast2obj_list(struct ast_state *state, asdl_seq *seq, PyObject* (*func)(struct ast_state *state, void*)) { Py_ssize_t i, n = asdl_seq_LEN(seq); PyObject *result = PyList_New(n); PyObject *value; if (!result) return NULL; for (i = 0; i < n; i++) { value = func(state, asdl_seq_GET_UNTYPED(seq, i)); if (!value) { Py_DECREF(result); return NULL; } PyList_SET_ITEM(result, i, value); } return result; } static PyObject* ast2obj_object(struct ast_state *Py_UNUSED(state), void *o) { PyObject *op = (PyObject*)o; if (!op) { op = Py_None; } return Py_NewRef(op); } #define ast2obj_constant ast2obj_object #define ast2obj_identifier ast2obj_object #define ast2obj_string ast2obj_object static PyObject* ast2obj_int(struct ast_state *Py_UNUSED(state), long b) { return PyLong_FromLong(b); } /* Conversion Python -> AST */ static int obj2ast_object(struct ast_state *Py_UNUSED(state), PyObject* obj, PyObject** out, PyArena* arena) { if (obj == Py_None) obj = NULL; if (obj) { if (_PyArena_AddPyObject(arena, obj) < 0) { *out = NULL; return -1; } *out = Py_NewRef(obj); } else { *out = NULL; } return 0; } static int obj2ast_constant(struct ast_state *Py_UNUSED(state), PyObject* obj, PyObject** out, PyArena* arena) { if (_PyArena_AddPyObject(arena, obj) < 0) { *out = NULL; return -1; } *out = Py_NewRef(obj); return 0; } static int obj2ast_identifier(struct ast_state *state, PyObject* obj, PyObject** out, PyArena* arena) { if (!PyUnicode_CheckExact(obj) && obj != Py_None) { PyErr_SetString(PyExc_TypeError, "AST identifier must be of type str"); return 1; } return obj2ast_object(state, obj, out, arena); } static int obj2ast_string(struct ast_state *state, PyObject* obj, PyObject** out, PyArena* arena) { if (!PyUnicode_CheckExact(obj) && !PyBytes_CheckExact(obj)) { PyErr_SetString(PyExc_TypeError, "AST string must be of type str"); return 1; } return obj2ast_object(state, obj, out, arena); } static int obj2ast_int(struct ast_state* Py_UNUSED(state), PyObject* obj, int* out, PyArena* arena) { int i; if (!PyLong_Check(obj)) { PyErr_Format(PyExc_ValueError, "invalid integer value: %R", obj); return 1; } i = _PyLong_AsInt(obj); if (i == -1 && PyErr_Occurred()) return 1; *out = i; return 0; } static int add_ast_fields(struct ast_state *state) { PyObject *empty_tuple; empty_tuple = PyTuple_New(0); if (!empty_tuple || PyObject_SetAttrString(state->AST_type, "_fields", empty_tuple) < 0 || PyObject_SetAttrString(state->AST_type, "__match_args__", empty_tuple) < 0 || PyObject_SetAttrString(state->AST_type, "_attributes", empty_tuple) < 0) { Py_XDECREF(empty_tuple); return -1; } Py_DECREF(empty_tuple); return 0; } static int init_types(struct ast_state *state) { // init_types() must not be called after _PyAST_Fini() // has been called assert(state->initialized >= 0); if (state->initialized) { return 1; } if (init_identifiers(state) < 0) { return 0; } state->AST_type = PyType_FromSpec(&AST_type_spec); if (!state->AST_type) { return 0; } if (add_ast_fields(state) < 0) { return 0; } state->mod_type = make_type(state, "mod", state->AST_type, NULL, 0, "mod = Module(stmt* body, type_ignore* type_ignores)\n" " | Interactive(stmt* body)\n" " | Expression(expr body)\n" " | FunctionType(expr* argtypes, expr returns)"); if (!state->mod_type) return 0; if (!add_attributes(state, state->mod_type, NULL, 0)) return 0; state->Module_type = make_type(state, "Module", state->mod_type, Module_fields, 2, "Module(stmt* body, type_ignore* type_ignores)"); if (!state->Module_type) return 0; state->Interactive_type = make_type(state, "Interactive", state->mod_type, Interactive_fields, 1, "Interactive(stmt* body)"); if (!state->Interactive_type) return 0; state->Expression_type = make_type(state, "Expression", state->mod_type, Expression_fields, 1, "Expression(expr body)"); if (!state->Expression_type) return 0; state->FunctionType_type = make_type(state, "FunctionType", state->mod_type, FunctionType_fields, 2, "FunctionType(expr* argtypes, expr returns)"); if (!state->FunctionType_type) return 0; state->stmt_type = make_type(state, "stmt", state->AST_type, NULL, 0, "stmt = FunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment, type_param* type_params)\n" " | AsyncFunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment, type_param* type_params)\n" " | ClassDef(identifier name, expr* bases, keyword* keywords, stmt* body, expr* decorator_list, type_param* type_params)\n" " | Return(expr? value)\n" " | Delete(expr* targets)\n" " | Assign(expr* targets, expr value, string? type_comment)\n" " | TypeAlias(expr name, type_param* type_params, expr value)\n" " | AugAssign(expr target, operator op, expr value)\n" " | AnnAssign(expr target, expr annotation, expr? value, int simple)\n" " | For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)\n" " | AsyncFor(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)\n" " | While(expr test, stmt* body, stmt* orelse)\n" " | If(expr test, stmt* body, stmt* orelse)\n" " | With(withitem* items, stmt* body, string? type_comment)\n" " | AsyncWith(withitem* items, stmt* body, string? type_comment)\n" " | Match(expr subject, match_case* cases)\n" " | Raise(expr? exc, expr? cause)\n" " | Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)\n" " | TryStar(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)\n" " | Assert(expr test, expr? msg)\n" " | Import(alias* names)\n" " | ImportFrom(identifier? module, alias* names, int? level)\n" " | Global(identifier* names)\n" " | Nonlocal(identifier* names)\n" " | Expr(expr value)\n" " | Pass\n" " | Break\n" " | Continue"); if (!state->stmt_type) return 0; if (!add_attributes(state, state->stmt_type, stmt_attributes, 4)) return 0; if (PyObject_SetAttr(state->stmt_type, state->end_lineno, Py_None) == -1) return 0; if (PyObject_SetAttr(state->stmt_type, state->end_col_offset, Py_None) == -1) return 0; state->FunctionDef_type = make_type(state, "FunctionDef", state->stmt_type, FunctionDef_fields, 7, "FunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment, type_param* type_params)"); if (!state->FunctionDef_type) return 0; if (PyObject_SetAttr(state->FunctionDef_type, state->returns, Py_None) == -1) return 0; if (PyObject_SetAttr(state->FunctionDef_type, state->type_comment, Py_None) == -1) return 0; state->AsyncFunctionDef_type = make_type(state, "AsyncFunctionDef", state->stmt_type, AsyncFunctionDef_fields, 7, "AsyncFunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment, type_param* type_params)"); if (!state->AsyncFunctionDef_type) return 0; if (PyObject_SetAttr(state->AsyncFunctionDef_type, state->returns, Py_None) == -1) return 0; if (PyObject_SetAttr(state->AsyncFunctionDef_type, state->type_comment, Py_None) == -1) return 0; state->ClassDef_type = make_type(state, "ClassDef", state->stmt_type, ClassDef_fields, 6, "ClassDef(identifier name, expr* bases, keyword* keywords, stmt* body, expr* decorator_list, type_param* type_params)"); if (!state->ClassDef_type) return 0; state->Return_type = make_type(state, "Return", state->stmt_type, Return_fields, 1, "Return(expr? value)"); if (!state->Return_type) return 0; if (PyObject_SetAttr(state->Return_type, state->value, Py_None) == -1) return 0; state->Delete_type = make_type(state, "Delete", state->stmt_type, Delete_fields, 1, "Delete(expr* targets)"); if (!state->Delete_type) return 0; state->Assign_type = make_type(state, "Assign", state->stmt_type, Assign_fields, 3, "Assign(expr* targets, expr value, string? type_comment)"); if (!state->Assign_type) return 0; if (PyObject_SetAttr(state->Assign_type, state->type_comment, Py_None) == -1) return 0; state->TypeAlias_type = make_type(state, "TypeAlias", state->stmt_type, TypeAlias_fields, 3, "TypeAlias(expr name, type_param* type_params, expr value)"); if (!state->TypeAlias_type) return 0; state->AugAssign_type = make_type(state, "AugAssign", state->stmt_type, AugAssign_fields, 3, "AugAssign(expr target, operator op, expr value)"); if (!state->AugAssign_type) return 0; state->AnnAssign_type = make_type(state, "AnnAssign", state->stmt_type, AnnAssign_fields, 4, "AnnAssign(expr target, expr annotation, expr? value, int simple)"); if (!state->AnnAssign_type) return 0; if (PyObject_SetAttr(state->AnnAssign_type, state->value, Py_None) == -1) return 0; state->For_type = make_type(state, "For", state->stmt_type, For_fields, 5, "For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)"); if (!state->For_type) return 0; if (PyObject_SetAttr(state->For_type, state->type_comment, Py_None) == -1) return 0; state->AsyncFor_type = make_type(state, "AsyncFor", state->stmt_type, AsyncFor_fields, 5, "AsyncFor(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)"); if (!state->AsyncFor_type) return 0; if (PyObject_SetAttr(state->AsyncFor_type, state->type_comment, Py_None) == -1) return 0; state->While_type = make_type(state, "While", state->stmt_type, While_fields, 3, "While(expr test, stmt* body, stmt* orelse)"); if (!state->While_type) return 0; state->If_type = make_type(state, "If", state->stmt_type, If_fields, 3, "If(expr test, stmt* body, stmt* orelse)"); if (!state->If_type) return 0; state->With_type = make_type(state, "With", state->stmt_type, With_fields, 3, "With(withitem* items, stmt* body, string? type_comment)"); if (!state->With_type) return 0; if (PyObject_SetAttr(state->With_type, state->type_comment, Py_None) == -1) return 0; state->AsyncWith_type = make_type(state, "AsyncWith", state->stmt_type, AsyncWith_fields, 3, "AsyncWith(withitem* items, stmt* body, string? type_comment)"); if (!state->AsyncWith_type) return 0; if (PyObject_SetAttr(state->AsyncWith_type, state->type_comment, Py_None) == -1) return 0; state->Match_type = make_type(state, "Match", state->stmt_type, Match_fields, 2, "Match(expr subject, match_case* cases)"); if (!state->Match_type) return 0; state->Raise_type = make_type(state, "Raise", state->stmt_type, Raise_fields, 2, "Raise(expr? exc, expr? cause)"); if (!state->Raise_type) return 0; if (PyObject_SetAttr(state->Raise_type, state->exc, Py_None) == -1) return 0; if (PyObject_SetAttr(state->Raise_type, state->cause, Py_None) == -1) return 0; state->Try_type = make_type(state, "Try", state->stmt_type, Try_fields, 4, "Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)"); if (!state->Try_type) return 0; state->TryStar_type = make_type(state, "TryStar", state->stmt_type, TryStar_fields, 4, "TryStar(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)"); if (!state->TryStar_type) return 0; state->Assert_type = make_type(state, "Assert", state->stmt_type, Assert_fields, 2, "Assert(expr test, expr? msg)"); if (!state->Assert_type) return 0; if (PyObject_SetAttr(state->Assert_type, state->msg, Py_None) == -1) return 0; state->Import_type = make_type(state, "Import", state->stmt_type, Import_fields, 1, "Import(alias* names)"); if (!state->Import_type) return 0; state->ImportFrom_type = make_type(state, "ImportFrom", state->stmt_type, ImportFrom_fields, 3, "ImportFrom(identifier? module, alias* names, int? level)"); if (!state->ImportFrom_type) return 0; if (PyObject_SetAttr(state->ImportFrom_type, state->module, Py_None) == -1) return 0; if (PyObject_SetAttr(state->ImportFrom_type, state->level, Py_None) == -1) return 0; state->Global_type = make_type(state, "Global", state->stmt_type, Global_fields, 1, "Global(identifier* names)"); if (!state->Global_type) return 0; state->Nonlocal_type = make_type(state, "Nonlocal", state->stmt_type, Nonlocal_fields, 1, "Nonlocal(identifier* names)"); if (!state->Nonlocal_type) return 0; state->Expr_type = make_type(state, "Expr", state->stmt_type, Expr_fields, 1, "Expr(expr value)"); if (!state->Expr_type) return 0; state->Pass_type = make_type(state, "Pass", state->stmt_type, NULL, 0, "Pass"); if (!state->Pass_type) return 0; state->Break_type = make_type(state, "Break", state->stmt_type, NULL, 0, "Break"); if (!state->Break_type) return 0; state->Continue_type = make_type(state, "Continue", state->stmt_type, NULL, 0, "Continue"); if (!state->Continue_type) return 0; state->expr_type = make_type(state, "expr", state->AST_type, NULL, 0, "expr = BoolOp(boolop op, expr* values)\n" " | NamedExpr(expr target, expr value)\n" " | BinOp(expr left, operator op, expr right)\n" " | UnaryOp(unaryop op, expr operand)\n" " | Lambda(arguments args, expr body)\n" " | IfExp(expr test, expr body, expr orelse)\n" " | Dict(expr* keys, expr* values)\n" " | Set(expr* elts)\n" " | ListComp(expr elt, comprehension* generators)\n" " | SetComp(expr elt, comprehension* generators)\n" " | DictComp(expr key, expr value, comprehension* generators)\n" " | GeneratorExp(expr elt, comprehension* generators)\n" " | Await(expr value)\n" " | Yield(expr? value)\n" " | YieldFrom(expr value)\n" " | Compare(expr left, cmpop* ops, expr* comparators)\n" " | Call(expr func, expr* args, keyword* keywords)\n" " | FormattedValue(expr value, int conversion, expr? format_spec)\n" " | JoinedStr(expr* values)\n" " | Constant(constant value, string? kind)\n" " | Attribute(expr value, identifier attr, expr_context ctx)\n" " | Subscript(expr value, expr slice, expr_context ctx)\n" " | Starred(expr value, expr_context ctx)\n" " | Name(identifier id, expr_context ctx)\n" " | List(expr* elts, expr_context ctx)\n" " | Tuple(expr* elts, expr_context ctx)\n" " | Slice(expr? lower, expr? upper, expr? step)"); if (!state->expr_type) return 0; if (!add_attributes(state, state->expr_type, expr_attributes, 4)) return 0; if (PyObject_SetAttr(state->expr_type, state->end_lineno, Py_None) == -1) return 0; if (PyObject_SetAttr(state->expr_type, state->end_col_offset, Py_None) == -1) return 0; state->BoolOp_type = make_type(state, "BoolOp", state->expr_type, BoolOp_fields, 2, "BoolOp(boolop op, expr* values)"); if (!state->BoolOp_type) return 0; state->NamedExpr_type = make_type(state, "NamedExpr", state->expr_type, NamedExpr_fields, 2, "NamedExpr(expr target, expr value)"); if (!state->NamedExpr_type) return 0; state->BinOp_type = make_type(state, "BinOp", state->expr_type, BinOp_fields, 3, "BinOp(expr left, operator op, expr right)"); if (!state->BinOp_type) return 0; state->UnaryOp_type = make_type(state, "UnaryOp", state->expr_type, UnaryOp_fields, 2, "UnaryOp(unaryop op, expr operand)"); if (!state->UnaryOp_type) return 0; state->Lambda_type = make_type(state, "Lambda", state->expr_type, Lambda_fields, 2, "Lambda(arguments args, expr body)"); if (!state->Lambda_type) return 0; state->IfExp_type = make_type(state, "IfExp", state->expr_type, IfExp_fields, 3, "IfExp(expr test, expr body, expr orelse)"); if (!state->IfExp_type) return 0; state->Dict_type = make_type(state, "Dict", state->expr_type, Dict_fields, 2, "Dict(expr* keys, expr* values)"); if (!state->Dict_type) return 0; state->Set_type = make_type(state, "Set", state->expr_type, Set_fields, 1, "Set(expr* elts)"); if (!state->Set_type) return 0; state->ListComp_type = make_type(state, "ListComp", state->expr_type, ListComp_fields, 2, "ListComp(expr elt, comprehension* generators)"); if (!state->ListComp_type) return 0; state->SetComp_type = make_type(state, "SetComp", state->expr_type, SetComp_fields, 2, "SetComp(expr elt, comprehension* generators)"); if (!state->SetComp_type) return 0; state->DictComp_type = make_type(state, "DictComp", state->expr_type, DictComp_fields, 3, "DictComp(expr key, expr value, comprehension* generators)"); if (!state->DictComp_type) return 0; state->GeneratorExp_type = make_type(state, "GeneratorExp", state->expr_type, GeneratorExp_fields, 2, "GeneratorExp(expr elt, comprehension* generators)"); if (!state->GeneratorExp_type) return 0; state->Await_type = make_type(state, "Await", state->expr_type, Await_fields, 1, "Await(expr value)"); if (!state->Await_type) return 0; state->Yield_type = make_type(state, "Yield", state->expr_type, Yield_fields, 1, "Yield(expr? value)"); if (!state->Yield_type) return 0; if (PyObject_SetAttr(state->Yield_type, state->value, Py_None) == -1) return 0; state->YieldFrom_type = make_type(state, "YieldFrom", state->expr_type, YieldFrom_fields, 1, "YieldFrom(expr value)"); if (!state->YieldFrom_type) return 0; state->Compare_type = make_type(state, "Compare", state->expr_type, Compare_fields, 3, "Compare(expr left, cmpop* ops, expr* comparators)"); if (!state->Compare_type) return 0; state->Call_type = make_type(state, "Call", state->expr_type, Call_fields, 3, "Call(expr func, expr* args, keyword* keywords)"); if (!state->Call_type) return 0; state->FormattedValue_type = make_type(state, "FormattedValue", state->expr_type, FormattedValue_fields, 3, "FormattedValue(expr value, int conversion, expr? format_spec)"); if (!state->FormattedValue_type) return 0; if (PyObject_SetAttr(state->FormattedValue_type, state->format_spec, Py_None) == -1) return 0; state->JoinedStr_type = make_type(state, "JoinedStr", state->expr_type, JoinedStr_fields, 1, "JoinedStr(expr* values)"); if (!state->JoinedStr_type) return 0; state->Constant_type = make_type(state, "Constant", state->expr_type, Constant_fields, 2, "Constant(constant value, string? kind)"); if (!state->Constant_type) return 0; if (PyObject_SetAttr(state->Constant_type, state->kind, Py_None) == -1) return 0; state->Attribute_type = make_type(state, "Attribute", state->expr_type, Attribute_fields, 3, "Attribute(expr value, identifier attr, expr_context ctx)"); if (!state->Attribute_type) return 0; state->Subscript_type = make_type(state, "Subscript", state->expr_type, Subscript_fields, 3, "Subscript(expr value, expr slice, expr_context ctx)"); if (!state->Subscript_type) return 0; state->Starred_type = make_type(state, "Starred", state->expr_type, Starred_fields, 2, "Starred(expr value, expr_context ctx)"); if (!state->Starred_type) return 0; state->Name_type = make_type(state, "Name", state->expr_type, Name_fields, 2, "Name(identifier id, expr_context ctx)"); if (!state->Name_type) return 0; state->List_type = make_type(state, "List", state->expr_type, List_fields, 2, "List(expr* elts, expr_context ctx)"); if (!state->List_type) return 0; state->Tuple_type = make_type(state, "Tuple", state->expr_type, Tuple_fields, 2, "Tuple(expr* elts, expr_context ctx)"); if (!state->Tuple_type) return 0; state->Slice_type = make_type(state, "Slice", state->expr_type, Slice_fields, 3, "Slice(expr? lower, expr? upper, expr? step)"); if (!state->Slice_type) return 0; if (PyObject_SetAttr(state->Slice_type, state->lower, Py_None) == -1) return 0; if (PyObject_SetAttr(state->Slice_type, state->upper, Py_None) == -1) return 0; if (PyObject_SetAttr(state->Slice_type, state->step, Py_None) == -1) return 0; state->expr_context_type = make_type(state, "expr_context", state->AST_type, NULL, 0, "expr_context = Load | Store | Del"); if (!state->expr_context_type) return 0; if (!add_attributes(state, state->expr_context_type, NULL, 0)) return 0; state->Load_type = make_type(state, "Load", state->expr_context_type, NULL, 0, "Load"); if (!state->Load_type) return 0; state->Load_singleton = PyType_GenericNew((PyTypeObject *)state->Load_type, NULL, NULL); if (!state->Load_singleton) return 0; state->Store_type = make_type(state, "Store", state->expr_context_type, NULL, 0, "Store"); if (!state->Store_type) return 0; state->Store_singleton = PyType_GenericNew((PyTypeObject *)state->Store_type, NULL, NULL); if (!state->Store_singleton) return 0; state->Del_type = make_type(state, "Del", state->expr_context_type, NULL, 0, "Del"); if (!state->Del_type) return 0; state->Del_singleton = PyType_GenericNew((PyTypeObject *)state->Del_type, NULL, NULL); if (!state->Del_singleton) return 0; state->boolop_type = make_type(state, "boolop", state->AST_type, NULL, 0, "boolop = And | Or"); if (!state->boolop_type) return 0; if (!add_attributes(state, state->boolop_type, NULL, 0)) return 0; state->And_type = make_type(state, "And", state->boolop_type, NULL, 0, "And"); if (!state->And_type) return 0; state->And_singleton = PyType_GenericNew((PyTypeObject *)state->And_type, NULL, NULL); if (!state->And_singleton) return 0; state->Or_type = make_type(state, "Or", state->boolop_type, NULL, 0, "Or"); if (!state->Or_type) return 0; state->Or_singleton = PyType_GenericNew((PyTypeObject *)state->Or_type, NULL, NULL); if (!state->Or_singleton) return 0; state->operator_type = make_type(state, "operator", state->AST_type, NULL, 0, "operator = Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift | RShift | BitOr | BitXor | BitAnd | FloorDiv"); if (!state->operator_type) return 0; if (!add_attributes(state, state->operator_type, NULL, 0)) return 0; state->Add_type = make_type(state, "Add", state->operator_type, NULL, 0, "Add"); if (!state->Add_type) return 0; state->Add_singleton = PyType_GenericNew((PyTypeObject *)state->Add_type, NULL, NULL); if (!state->Add_singleton) return 0; state->Sub_type = make_type(state, "Sub", state->operator_type, NULL, 0, "Sub"); if (!state->Sub_type) return 0; state->Sub_singleton = PyType_GenericNew((PyTypeObject *)state->Sub_type, NULL, NULL); if (!state->Sub_singleton) return 0; state->Mult_type = make_type(state, "Mult", state->operator_type, NULL, 0, "Mult"); if (!state->Mult_type) return 0; state->Mult_singleton = PyType_GenericNew((PyTypeObject *)state->Mult_type, NULL, NULL); if (!state->Mult_singleton) return 0; state->MatMult_type = make_type(state, "MatMult", state->operator_type, NULL, 0, "MatMult"); if (!state->MatMult_type) return 0; state->MatMult_singleton = PyType_GenericNew((PyTypeObject *)state->MatMult_type, NULL, NULL); if (!state->MatMult_singleton) return 0; state->Div_type = make_type(state, "Div", state->operator_type, NULL, 0, "Div"); if (!state->Div_type) return 0; state->Div_singleton = PyType_GenericNew((PyTypeObject *)state->Div_type, NULL, NULL); if (!state->Div_singleton) return 0; state->Mod_type = make_type(state, "Mod", state->operator_type, NULL, 0, "Mod"); if (!state->Mod_type) return 0; state->Mod_singleton = PyType_GenericNew((PyTypeObject *)state->Mod_type, NULL, NULL); if (!state->Mod_singleton) return 0; state->Pow_type = make_type(state, "Pow", state->operator_type, NULL, 0, "Pow"); if (!state->Pow_type) return 0; state->Pow_singleton = PyType_GenericNew((PyTypeObject *)state->Pow_type, NULL, NULL); if (!state->Pow_singleton) return 0; state->LShift_type = make_type(state, "LShift", state->operator_type, NULL, 0, "LShift"); if (!state->LShift_type) return 0; state->LShift_singleton = PyType_GenericNew((PyTypeObject *)state->LShift_type, NULL, NULL); if (!state->LShift_singleton) return 0; state->RShift_type = make_type(state, "RShift", state->operator_type, NULL, 0, "RShift"); if (!state->RShift_type) return 0; state->RShift_singleton = PyType_GenericNew((PyTypeObject *)state->RShift_type, NULL, NULL); if (!state->RShift_singleton) return 0; state->BitOr_type = make_type(state, "BitOr", state->operator_type, NULL, 0, "BitOr"); if (!state->BitOr_type) return 0; state->BitOr_singleton = PyType_GenericNew((PyTypeObject *)state->BitOr_type, NULL, NULL); if (!state->BitOr_singleton) return 0; state->BitXor_type = make_type(state, "BitXor", state->operator_type, NULL, 0, "BitXor"); if (!state->BitXor_type) return 0; state->BitXor_singleton = PyType_GenericNew((PyTypeObject *)state->BitXor_type, NULL, NULL); if (!state->BitXor_singleton) return 0; state->BitAnd_type = make_type(state, "BitAnd", state->operator_type, NULL, 0, "BitAnd"); if (!state->BitAnd_type) return 0; state->BitAnd_singleton = PyType_GenericNew((PyTypeObject *)state->BitAnd_type, NULL, NULL); if (!state->BitAnd_singleton) return 0; state->FloorDiv_type = make_type(state, "FloorDiv", state->operator_type, NULL, 0, "FloorDiv"); if (!state->FloorDiv_type) return 0; state->FloorDiv_singleton = PyType_GenericNew((PyTypeObject *)state->FloorDiv_type, NULL, NULL); if (!state->FloorDiv_singleton) return 0; state->unaryop_type = make_type(state, "unaryop", state->AST_type, NULL, 0, "unaryop = Invert | Not | UAdd | USub"); if (!state->unaryop_type) return 0; if (!add_attributes(state, state->unaryop_type, NULL, 0)) return 0; state->Invert_type = make_type(state, "Invert", state->unaryop_type, NULL, 0, "Invert"); if (!state->Invert_type) return 0; state->Invert_singleton = PyType_GenericNew((PyTypeObject *)state->Invert_type, NULL, NULL); if (!state->Invert_singleton) return 0; state->Not_type = make_type(state, "Not", state->unaryop_type, NULL, 0, "Not"); if (!state->Not_type) return 0; state->Not_singleton = PyType_GenericNew((PyTypeObject *)state->Not_type, NULL, NULL); if (!state->Not_singleton) return 0; state->UAdd_type = make_type(state, "UAdd", state->unaryop_type, NULL, 0, "UAdd"); if (!state->UAdd_type) return 0; state->UAdd_singleton = PyType_GenericNew((PyTypeObject *)state->UAdd_type, NULL, NULL); if (!state->UAdd_singleton) return 0; state->USub_type = make_type(state, "USub", state->unaryop_type, NULL, 0, "USub"); if (!state->USub_type) return 0; state->USub_singleton = PyType_GenericNew((PyTypeObject *)state->USub_type, NULL, NULL); if (!state->USub_singleton) return 0; state->cmpop_type = make_type(state, "cmpop", state->AST_type, NULL, 0, "cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn"); if (!state->cmpop_type) return 0; if (!add_attributes(state, state->cmpop_type, NULL, 0)) return 0; state->Eq_type = make_type(state, "Eq", state->cmpop_type, NULL, 0, "Eq"); if (!state->Eq_type) return 0; state->Eq_singleton = PyType_GenericNew((PyTypeObject *)state->Eq_type, NULL, NULL); if (!state->Eq_singleton) return 0; state->NotEq_type = make_type(state, "NotEq", state->cmpop_type, NULL, 0, "NotEq"); if (!state->NotEq_type) return 0; state->NotEq_singleton = PyType_GenericNew((PyTypeObject *)state->NotEq_type, NULL, NULL); if (!state->NotEq_singleton) return 0; state->Lt_type = make_type(state, "Lt", state->cmpop_type, NULL, 0, "Lt"); if (!state->Lt_type) return 0; state->Lt_singleton = PyType_GenericNew((PyTypeObject *)state->Lt_type, NULL, NULL); if (!state->Lt_singleton) return 0; state->LtE_type = make_type(state, "LtE", state->cmpop_type, NULL, 0, "LtE"); if (!state->LtE_type) return 0; state->LtE_singleton = PyType_GenericNew((PyTypeObject *)state->LtE_type, NULL, NULL); if (!state->LtE_singleton) return 0; state->Gt_type = make_type(state, "Gt", state->cmpop_type, NULL, 0, "Gt"); if (!state->Gt_type) return 0; state->Gt_singleton = PyType_GenericNew((PyTypeObject *)state->Gt_type, NULL, NULL); if (!state->Gt_singleton) return 0; state->GtE_type = make_type(state, "GtE", state->cmpop_type, NULL, 0, "GtE"); if (!state->GtE_type) return 0; state->GtE_singleton = PyType_GenericNew((PyTypeObject *)state->GtE_type, NULL, NULL); if (!state->GtE_singleton) return 0; state->Is_type = make_type(state, "Is", state->cmpop_type, NULL, 0, "Is"); if (!state->Is_type) return 0; state->Is_singleton = PyType_GenericNew((PyTypeObject *)state->Is_type, NULL, NULL); if (!state->Is_singleton) return 0; state->IsNot_type = make_type(state, "IsNot", state->cmpop_type, NULL, 0, "IsNot"); if (!state->IsNot_type) return 0; state->IsNot_singleton = PyType_GenericNew((PyTypeObject *)state->IsNot_type, NULL, NULL); if (!state->IsNot_singleton) return 0; state->In_type = make_type(state, "In", state->cmpop_type, NULL, 0, "In"); if (!state->In_type) return 0; state->In_singleton = PyType_GenericNew((PyTypeObject *)state->In_type, NULL, NULL); if (!state->In_singleton) return 0; state->NotIn_type = make_type(state, "NotIn", state->cmpop_type, NULL, 0, "NotIn"); if (!state->NotIn_type) return 0; state->NotIn_singleton = PyType_GenericNew((PyTypeObject *)state->NotIn_type, NULL, NULL); if (!state->NotIn_singleton) return 0; state->comprehension_type = make_type(state, "comprehension", state->AST_type, comprehension_fields, 4, "comprehension(expr target, expr iter, expr* ifs, int is_async)"); if (!state->comprehension_type) return 0; if (!add_attributes(state, state->comprehension_type, NULL, 0)) return 0; state->excepthandler_type = make_type(state, "excepthandler", state->AST_type, NULL, 0, "excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)"); if (!state->excepthandler_type) return 0; if (!add_attributes(state, state->excepthandler_type, excepthandler_attributes, 4)) return 0; if (PyObject_SetAttr(state->excepthandler_type, state->end_lineno, Py_None) == -1) return 0; if (PyObject_SetAttr(state->excepthandler_type, state->end_col_offset, Py_None) == -1) return 0; state->ExceptHandler_type = make_type(state, "ExceptHandler", state->excepthandler_type, ExceptHandler_fields, 3, "ExceptHandler(expr? type, identifier? name, stmt* body)"); if (!state->ExceptHandler_type) return 0; if (PyObject_SetAttr(state->ExceptHandler_type, state->type, Py_None) == -1) return 0; if (PyObject_SetAttr(state->ExceptHandler_type, state->name, Py_None) == -1) return 0; state->arguments_type = make_type(state, "arguments", state->AST_type, arguments_fields, 7, "arguments(arg* posonlyargs, arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults, arg? kwarg, expr* defaults)"); if (!state->arguments_type) return 0; if (!add_attributes(state, state->arguments_type, NULL, 0)) return 0; if (PyObject_SetAttr(state->arguments_type, state->vararg, Py_None) == -1) return 0; if (PyObject_SetAttr(state->arguments_type, state->kwarg, Py_None) == -1) return 0; state->arg_type = make_type(state, "arg", state->AST_type, arg_fields, 3, "arg(identifier arg, expr? annotation, string? type_comment)"); if (!state->arg_type) return 0; if (!add_attributes(state, state->arg_type, arg_attributes, 4)) return 0; if (PyObject_SetAttr(state->arg_type, state->annotation, Py_None) == -1) return 0; if (PyObject_SetAttr(state->arg_type, state->type_comment, Py_None) == -1) return 0; if (PyObject_SetAttr(state->arg_type, state->end_lineno, Py_None) == -1) return 0; if (PyObject_SetAttr(state->arg_type, state->end_col_offset, Py_None) == -1) return 0; state->keyword_type = make_type(state, "keyword", state->AST_type, keyword_fields, 2, "keyword(identifier? arg, expr value)"); if (!state->keyword_type) return 0; if (!add_attributes(state, state->keyword_type, keyword_attributes, 4)) return 0; if (PyObject_SetAttr(state->keyword_type, state->arg, Py_None) == -1) return 0; if (PyObject_SetAttr(state->keyword_type, state->end_lineno, Py_None) == -1) return 0; if (PyObject_SetAttr(state->keyword_type, state->end_col_offset, Py_None) == -1) return 0; state->alias_type = make_type(state, "alias", state->AST_type, alias_fields, 2, "alias(identifier name, identifier? asname)"); if (!state->alias_type) return 0; if (!add_attributes(state, state->alias_type, alias_attributes, 4)) return 0; if (PyObject_SetAttr(state->alias_type, state->asname, Py_None) == -1) return 0; if (PyObject_SetAttr(state->alias_type, state->end_lineno, Py_None) == -1) return 0; if (PyObject_SetAttr(state->alias_type, state->end_col_offset, Py_None) == -1) return 0; state->withitem_type = make_type(state, "withitem", state->AST_type, withitem_fields, 2, "withitem(expr context_expr, expr? optional_vars)"); if (!state->withitem_type) return 0; if (!add_attributes(state, state->withitem_type, NULL, 0)) return 0; if (PyObject_SetAttr(state->withitem_type, state->optional_vars, Py_None) == -1) return 0; state->match_case_type = make_type(state, "match_case", state->AST_type, match_case_fields, 3, "match_case(pattern pattern, expr? guard, stmt* body)"); if (!state->match_case_type) return 0; if (!add_attributes(state, state->match_case_type, NULL, 0)) return 0; if (PyObject_SetAttr(state->match_case_type, state->guard, Py_None) == -1) return 0; state->pattern_type = make_type(state, "pattern", state->AST_type, NULL, 0, "pattern = MatchValue(expr value)\n" " | MatchSingleton(constant value)\n" " | MatchSequence(pattern* patterns)\n" " | MatchMapping(expr* keys, pattern* patterns, identifier? rest)\n" " | MatchClass(expr cls, pattern* patterns, identifier* kwd_attrs, pattern* kwd_patterns)\n" " | MatchStar(identifier? name)\n" " | MatchAs(pattern? pattern, identifier? name)\n" " | MatchOr(pattern* patterns)"); if (!state->pattern_type) return 0; if (!add_attributes(state, state->pattern_type, pattern_attributes, 4)) return 0; state->MatchValue_type = make_type(state, "MatchValue", state->pattern_type, MatchValue_fields, 1, "MatchValue(expr value)"); if (!state->MatchValue_type) return 0; state->MatchSingleton_type = make_type(state, "MatchSingleton", state->pattern_type, MatchSingleton_fields, 1, "MatchSingleton(constant value)"); if (!state->MatchSingleton_type) return 0; state->MatchSequence_type = make_type(state, "MatchSequence", state->pattern_type, MatchSequence_fields, 1, "MatchSequence(pattern* patterns)"); if (!state->MatchSequence_type) return 0; state->MatchMapping_type = make_type(state, "MatchMapping", state->pattern_type, MatchMapping_fields, 3, "MatchMapping(expr* keys, pattern* patterns, identifier? rest)"); if (!state->MatchMapping_type) return 0; if (PyObject_SetAttr(state->MatchMapping_type, state->rest, Py_None) == -1) return 0; state->MatchClass_type = make_type(state, "MatchClass", state->pattern_type, MatchClass_fields, 4, "MatchClass(expr cls, pattern* patterns, identifier* kwd_attrs, pattern* kwd_patterns)"); if (!state->MatchClass_type) return 0; state->MatchStar_type = make_type(state, "MatchStar", state->pattern_type, MatchStar_fields, 1, "MatchStar(identifier? name)"); if (!state->MatchStar_type) return 0; if (PyObject_SetAttr(state->MatchStar_type, state->name, Py_None) == -1) return 0; state->MatchAs_type = make_type(state, "MatchAs", state->pattern_type, MatchAs_fields, 2, "MatchAs(pattern? pattern, identifier? name)"); if (!state->MatchAs_type) return 0; if (PyObject_SetAttr(state->MatchAs_type, state->pattern, Py_None) == -1) return 0; if (PyObject_SetAttr(state->MatchAs_type, state->name, Py_None) == -1) return 0; state->MatchOr_type = make_type(state, "MatchOr", state->pattern_type, MatchOr_fields, 1, "MatchOr(pattern* patterns)"); if (!state->MatchOr_type) return 0; state->type_ignore_type = make_type(state, "type_ignore", state->AST_type, NULL, 0, "type_ignore = TypeIgnore(int lineno, string tag)"); if (!state->type_ignore_type) return 0; if (!add_attributes(state, state->type_ignore_type, NULL, 0)) return 0; state->TypeIgnore_type = make_type(state, "TypeIgnore", state->type_ignore_type, TypeIgnore_fields, 2, "TypeIgnore(int lineno, string tag)"); if (!state->TypeIgnore_type) return 0; state->type_param_type = make_type(state, "type_param", state->AST_type, NULL, 0, "type_param = TypeVar(identifier name, expr? bound)\n" " | ParamSpec(identifier name)\n" " | TypeVarTuple(identifier name)"); if (!state->type_param_type) return 0; if (!add_attributes(state, state->type_param_type, type_param_attributes, 4)) return 0; if (PyObject_SetAttr(state->type_param_type, state->end_lineno, Py_None) == -1) return 0; if (PyObject_SetAttr(state->type_param_type, state->end_col_offset, Py_None) == -1) return 0; state->TypeVar_type = make_type(state, "TypeVar", state->type_param_type, TypeVar_fields, 2, "TypeVar(identifier name, expr? bound)"); if (!state->TypeVar_type) return 0; if (PyObject_SetAttr(state->TypeVar_type, state->bound, Py_None) == -1) return 0; state->ParamSpec_type = make_type(state, "ParamSpec", state->type_param_type, ParamSpec_fields, 1, "ParamSpec(identifier name)"); if (!state->ParamSpec_type) return 0; state->TypeVarTuple_type = make_type(state, "TypeVarTuple", state->type_param_type, TypeVarTuple_fields, 1, "TypeVarTuple(identifier name)"); if (!state->TypeVarTuple_type) return 0; state->recursion_depth = 0; state->recursion_limit = 0; state->initialized = 1; return 1; } static int obj2ast_mod(struct ast_state *state, PyObject* obj, mod_ty* out, PyArena* arena); static int obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* arena); static int obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* arena); static int obj2ast_expr_context(struct ast_state *state, PyObject* obj, expr_context_ty* out, PyArena* arena); static int obj2ast_boolop(struct ast_state *state, PyObject* obj, boolop_ty* out, PyArena* arena); static int obj2ast_operator(struct ast_state *state, PyObject* obj, operator_ty* out, PyArena* arena); static int obj2ast_unaryop(struct ast_state *state, PyObject* obj, unaryop_ty* out, PyArena* arena); static int obj2ast_cmpop(struct ast_state *state, PyObject* obj, cmpop_ty* out, PyArena* arena); static int obj2ast_comprehension(struct ast_state *state, PyObject* obj, comprehension_ty* out, PyArena* arena); static int obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty* out, PyArena* arena); static int obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, PyArena* arena); static int obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena); static int obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out, PyArena* arena); static int obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena* arena); static int obj2ast_withitem(struct ast_state *state, PyObject* obj, withitem_ty* out, PyArena* arena); static int obj2ast_match_case(struct ast_state *state, PyObject* obj, match_case_ty* out, PyArena* arena); static int obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, PyArena* arena); static int obj2ast_type_ignore(struct ast_state *state, PyObject* obj, type_ignore_ty* out, PyArena* arena); static int obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out, PyArena* arena); mod_ty _PyAST_Module(asdl_stmt_seq * body, asdl_type_ignore_seq * type_ignores, PyArena *arena) { mod_ty p; p = (mod_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Module_kind; p->v.Module.body = body; p->v.Module.type_ignores = type_ignores; return p; } mod_ty _PyAST_Interactive(asdl_stmt_seq * body, PyArena *arena) { mod_ty p; p = (mod_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Interactive_kind; p->v.Interactive.body = body; return p; } mod_ty _PyAST_Expression(expr_ty body, PyArena *arena) { mod_ty p; if (!body) { PyErr_SetString(PyExc_ValueError, "field 'body' is required for Expression"); return NULL; } p = (mod_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Expression_kind; p->v.Expression.body = body; return p; } mod_ty _PyAST_FunctionType(asdl_expr_seq * argtypes, expr_ty returns, PyArena *arena) { mod_ty p; if (!returns) { PyErr_SetString(PyExc_ValueError, "field 'returns' is required for FunctionType"); return NULL; } p = (mod_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = FunctionType_kind; p->v.FunctionType.argtypes = argtypes; p->v.FunctionType.returns = returns; return p; } stmt_ty _PyAST_FunctionDef(identifier name, arguments_ty args, asdl_stmt_seq * body, asdl_expr_seq * decorator_list, expr_ty returns, string type_comment, asdl_type_param_seq * type_params, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!name) { PyErr_SetString(PyExc_ValueError, "field 'name' is required for FunctionDef"); return NULL; } if (!args) { PyErr_SetString(PyExc_ValueError, "field 'args' is required for FunctionDef"); return NULL; } p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = FunctionDef_kind; p->v.FunctionDef.name = name; p->v.FunctionDef.args = args; p->v.FunctionDef.body = body; p->v.FunctionDef.decorator_list = decorator_list; p->v.FunctionDef.returns = returns; p->v.FunctionDef.type_comment = type_comment; p->v.FunctionDef.type_params = type_params; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_AsyncFunctionDef(identifier name, arguments_ty args, asdl_stmt_seq * body, asdl_expr_seq * decorator_list, expr_ty returns, string type_comment, asdl_type_param_seq * type_params, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!name) { PyErr_SetString(PyExc_ValueError, "field 'name' is required for AsyncFunctionDef"); return NULL; } if (!args) { PyErr_SetString(PyExc_ValueError, "field 'args' is required for AsyncFunctionDef"); return NULL; } p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = AsyncFunctionDef_kind; p->v.AsyncFunctionDef.name = name; p->v.AsyncFunctionDef.args = args; p->v.AsyncFunctionDef.body = body; p->v.AsyncFunctionDef.decorator_list = decorator_list; p->v.AsyncFunctionDef.returns = returns; p->v.AsyncFunctionDef.type_comment = type_comment; p->v.AsyncFunctionDef.type_params = type_params; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_ClassDef(identifier name, asdl_expr_seq * bases, asdl_keyword_seq * keywords, asdl_stmt_seq * body, asdl_expr_seq * decorator_list, asdl_type_param_seq * type_params, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!name) { PyErr_SetString(PyExc_ValueError, "field 'name' is required for ClassDef"); return NULL; } p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = ClassDef_kind; p->v.ClassDef.name = name; p->v.ClassDef.bases = bases; p->v.ClassDef.keywords = keywords; p->v.ClassDef.body = body; p->v.ClassDef.decorator_list = decorator_list; p->v.ClassDef.type_params = type_params; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_Return(expr_ty value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Return_kind; p->v.Return.value = value; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_Delete(asdl_expr_seq * targets, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Delete_kind; p->v.Delete.targets = targets; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_Assign(asdl_expr_seq * targets, expr_ty value, string type_comment, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for Assign"); return NULL; } p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Assign_kind; p->v.Assign.targets = targets; p->v.Assign.value = value; p->v.Assign.type_comment = type_comment; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_TypeAlias(expr_ty name, asdl_type_param_seq * type_params, expr_ty value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!name) { PyErr_SetString(PyExc_ValueError, "field 'name' is required for TypeAlias"); return NULL; } if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for TypeAlias"); return NULL; } p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = TypeAlias_kind; p->v.TypeAlias.name = name; p->v.TypeAlias.type_params = type_params; p->v.TypeAlias.value = value; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_AugAssign(expr_ty target, operator_ty op, expr_ty value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!target) { PyErr_SetString(PyExc_ValueError, "field 'target' is required for AugAssign"); return NULL; } if (!op) { PyErr_SetString(PyExc_ValueError, "field 'op' is required for AugAssign"); return NULL; } if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for AugAssign"); return NULL; } p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = AugAssign_kind; p->v.AugAssign.target = target; p->v.AugAssign.op = op; p->v.AugAssign.value = value; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_AnnAssign(expr_ty target, expr_ty annotation, expr_ty value, int simple, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!target) { PyErr_SetString(PyExc_ValueError, "field 'target' is required for AnnAssign"); return NULL; } if (!annotation) { PyErr_SetString(PyExc_ValueError, "field 'annotation' is required for AnnAssign"); return NULL; } p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = AnnAssign_kind; p->v.AnnAssign.target = target; p->v.AnnAssign.annotation = annotation; p->v.AnnAssign.value = value; p->v.AnnAssign.simple = simple; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_For(expr_ty target, expr_ty iter, asdl_stmt_seq * body, asdl_stmt_seq * orelse, string type_comment, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!target) { PyErr_SetString(PyExc_ValueError, "field 'target' is required for For"); return NULL; } if (!iter) { PyErr_SetString(PyExc_ValueError, "field 'iter' is required for For"); return NULL; } p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = For_kind; p->v.For.target = target; p->v.For.iter = iter; p->v.For.body = body; p->v.For.orelse = orelse; p->v.For.type_comment = type_comment; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_AsyncFor(expr_ty target, expr_ty iter, asdl_stmt_seq * body, asdl_stmt_seq * orelse, string type_comment, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!target) { PyErr_SetString(PyExc_ValueError, "field 'target' is required for AsyncFor"); return NULL; } if (!iter) { PyErr_SetString(PyExc_ValueError, "field 'iter' is required for AsyncFor"); return NULL; } p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = AsyncFor_kind; p->v.AsyncFor.target = target; p->v.AsyncFor.iter = iter; p->v.AsyncFor.body = body; p->v.AsyncFor.orelse = orelse; p->v.AsyncFor.type_comment = type_comment; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_While(expr_ty test, asdl_stmt_seq * body, asdl_stmt_seq * orelse, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!test) { PyErr_SetString(PyExc_ValueError, "field 'test' is required for While"); return NULL; } p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = While_kind; p->v.While.test = test; p->v.While.body = body; p->v.While.orelse = orelse; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_If(expr_ty test, asdl_stmt_seq * body, asdl_stmt_seq * orelse, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!test) { PyErr_SetString(PyExc_ValueError, "field 'test' is required for If"); return NULL; } p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = If_kind; p->v.If.test = test; p->v.If.body = body; p->v.If.orelse = orelse; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_With(asdl_withitem_seq * items, asdl_stmt_seq * body, string type_comment, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = With_kind; p->v.With.items = items; p->v.With.body = body; p->v.With.type_comment = type_comment; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_AsyncWith(asdl_withitem_seq * items, asdl_stmt_seq * body, string type_comment, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = AsyncWith_kind; p->v.AsyncWith.items = items; p->v.AsyncWith.body = body; p->v.AsyncWith.type_comment = type_comment; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_Match(expr_ty subject, asdl_match_case_seq * cases, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!subject) { PyErr_SetString(PyExc_ValueError, "field 'subject' is required for Match"); return NULL; } p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Match_kind; p->v.Match.subject = subject; p->v.Match.cases = cases; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_Raise(expr_ty exc, expr_ty cause, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Raise_kind; p->v.Raise.exc = exc; p->v.Raise.cause = cause; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_Try(asdl_stmt_seq * body, asdl_excepthandler_seq * handlers, asdl_stmt_seq * orelse, asdl_stmt_seq * finalbody, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Try_kind; p->v.Try.body = body; p->v.Try.handlers = handlers; p->v.Try.orelse = orelse; p->v.Try.finalbody = finalbody; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_TryStar(asdl_stmt_seq * body, asdl_excepthandler_seq * handlers, asdl_stmt_seq * orelse, asdl_stmt_seq * finalbody, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = TryStar_kind; p->v.TryStar.body = body; p->v.TryStar.handlers = handlers; p->v.TryStar.orelse = orelse; p->v.TryStar.finalbody = finalbody; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_Assert(expr_ty test, expr_ty msg, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!test) { PyErr_SetString(PyExc_ValueError, "field 'test' is required for Assert"); return NULL; } p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Assert_kind; p->v.Assert.test = test; p->v.Assert.msg = msg; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_Import(asdl_alias_seq * names, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Import_kind; p->v.Import.names = names; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_ImportFrom(identifier module, asdl_alias_seq * names, int level, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = ImportFrom_kind; p->v.ImportFrom.module = module; p->v.ImportFrom.names = names; p->v.ImportFrom.level = level; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_Global(asdl_identifier_seq * names, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Global_kind; p->v.Global.names = names; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_Nonlocal(asdl_identifier_seq * names, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Nonlocal_kind; p->v.Nonlocal.names = names; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_Expr(expr_ty value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for Expr"); return NULL; } p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Expr_kind; p->v.Expr.value = value; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_Pass(int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Pass_kind; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_Break(int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Break_kind; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } stmt_ty _PyAST_Continue(int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Continue_kind; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_BoolOp(boolop_ty op, asdl_expr_seq * values, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!op) { PyErr_SetString(PyExc_ValueError, "field 'op' is required for BoolOp"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = BoolOp_kind; p->v.BoolOp.op = op; p->v.BoolOp.values = values; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_NamedExpr(expr_ty target, expr_ty value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!target) { PyErr_SetString(PyExc_ValueError, "field 'target' is required for NamedExpr"); return NULL; } if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for NamedExpr"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = NamedExpr_kind; p->v.NamedExpr.target = target; p->v.NamedExpr.value = value; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_BinOp(expr_ty left, operator_ty op, expr_ty right, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!left) { PyErr_SetString(PyExc_ValueError, "field 'left' is required for BinOp"); return NULL; } if (!op) { PyErr_SetString(PyExc_ValueError, "field 'op' is required for BinOp"); return NULL; } if (!right) { PyErr_SetString(PyExc_ValueError, "field 'right' is required for BinOp"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = BinOp_kind; p->v.BinOp.left = left; p->v.BinOp.op = op; p->v.BinOp.right = right; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_UnaryOp(unaryop_ty op, expr_ty operand, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!op) { PyErr_SetString(PyExc_ValueError, "field 'op' is required for UnaryOp"); return NULL; } if (!operand) { PyErr_SetString(PyExc_ValueError, "field 'operand' is required for UnaryOp"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = UnaryOp_kind; p->v.UnaryOp.op = op; p->v.UnaryOp.operand = operand; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_Lambda(arguments_ty args, expr_ty body, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!args) { PyErr_SetString(PyExc_ValueError, "field 'args' is required for Lambda"); return NULL; } if (!body) { PyErr_SetString(PyExc_ValueError, "field 'body' is required for Lambda"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Lambda_kind; p->v.Lambda.args = args; p->v.Lambda.body = body; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!test) { PyErr_SetString(PyExc_ValueError, "field 'test' is required for IfExp"); return NULL; } if (!body) { PyErr_SetString(PyExc_ValueError, "field 'body' is required for IfExp"); return NULL; } if (!orelse) { PyErr_SetString(PyExc_ValueError, "field 'orelse' is required for IfExp"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = IfExp_kind; p->v.IfExp.test = test; p->v.IfExp.body = body; p->v.IfExp.orelse = orelse; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_Dict(asdl_expr_seq * keys, asdl_expr_seq * values, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Dict_kind; p->v.Dict.keys = keys; p->v.Dict.values = values; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_Set(asdl_expr_seq * elts, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Set_kind; p->v.Set.elts = elts; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_ListComp(expr_ty elt, asdl_comprehension_seq * generators, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!elt) { PyErr_SetString(PyExc_ValueError, "field 'elt' is required for ListComp"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = ListComp_kind; p->v.ListComp.elt = elt; p->v.ListComp.generators = generators; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_SetComp(expr_ty elt, asdl_comprehension_seq * generators, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!elt) { PyErr_SetString(PyExc_ValueError, "field 'elt' is required for SetComp"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = SetComp_kind; p->v.SetComp.elt = elt; p->v.SetComp.generators = generators; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_DictComp(expr_ty key, expr_ty value, asdl_comprehension_seq * generators, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!key) { PyErr_SetString(PyExc_ValueError, "field 'key' is required for DictComp"); return NULL; } if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for DictComp"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = DictComp_kind; p->v.DictComp.key = key; p->v.DictComp.value = value; p->v.DictComp.generators = generators; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_GeneratorExp(expr_ty elt, asdl_comprehension_seq * generators, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!elt) { PyErr_SetString(PyExc_ValueError, "field 'elt' is required for GeneratorExp"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = GeneratorExp_kind; p->v.GeneratorExp.elt = elt; p->v.GeneratorExp.generators = generators; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_Await(expr_ty value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for Await"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Await_kind; p->v.Await.value = value; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_Yield(expr_ty value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Yield_kind; p->v.Yield.value = value; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_YieldFrom(expr_ty value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for YieldFrom"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = YieldFrom_kind; p->v.YieldFrom.value = value; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_Compare(expr_ty left, asdl_int_seq * ops, asdl_expr_seq * comparators, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!left) { PyErr_SetString(PyExc_ValueError, "field 'left' is required for Compare"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Compare_kind; p->v.Compare.left = left; p->v.Compare.ops = ops; p->v.Compare.comparators = comparators; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_Call(expr_ty func, asdl_expr_seq * args, asdl_keyword_seq * keywords, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!func) { PyErr_SetString(PyExc_ValueError, "field 'func' is required for Call"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Call_kind; p->v.Call.func = func; p->v.Call.args = args; p->v.Call.keywords = keywords; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_FormattedValue(expr_ty value, int conversion, expr_ty format_spec, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for FormattedValue"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = FormattedValue_kind; p->v.FormattedValue.value = value; p->v.FormattedValue.conversion = conversion; p->v.FormattedValue.format_spec = format_spec; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_JoinedStr(asdl_expr_seq * values, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = JoinedStr_kind; p->v.JoinedStr.values = values; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_Constant(constant value, string kind, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for Constant"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Constant_kind; p->v.Constant.value = value; p->v.Constant.kind = kind; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for Attribute"); return NULL; } if (!attr) { PyErr_SetString(PyExc_ValueError, "field 'attr' is required for Attribute"); return NULL; } if (!ctx) { PyErr_SetString(PyExc_ValueError, "field 'ctx' is required for Attribute"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Attribute_kind; p->v.Attribute.value = value; p->v.Attribute.attr = attr; p->v.Attribute.ctx = ctx; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_Subscript(expr_ty value, expr_ty slice, expr_context_ty ctx, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for Subscript"); return NULL; } if (!slice) { PyErr_SetString(PyExc_ValueError, "field 'slice' is required for Subscript"); return NULL; } if (!ctx) { PyErr_SetString(PyExc_ValueError, "field 'ctx' is required for Subscript"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Subscript_kind; p->v.Subscript.value = value; p->v.Subscript.slice = slice; p->v.Subscript.ctx = ctx; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_Starred(expr_ty value, expr_context_ty ctx, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for Starred"); return NULL; } if (!ctx) { PyErr_SetString(PyExc_ValueError, "field 'ctx' is required for Starred"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Starred_kind; p->v.Starred.value = value; p->v.Starred.ctx = ctx; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_Name(identifier id, expr_context_ty ctx, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!id) { PyErr_SetString(PyExc_ValueError, "field 'id' is required for Name"); return NULL; } if (!ctx) { PyErr_SetString(PyExc_ValueError, "field 'ctx' is required for Name"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Name_kind; p->v.Name.id = id; p->v.Name.ctx = ctx; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_List(asdl_expr_seq * elts, expr_context_ty ctx, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!ctx) { PyErr_SetString(PyExc_ValueError, "field 'ctx' is required for List"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = List_kind; p->v.List.elts = elts; p->v.List.ctx = ctx; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_Tuple(asdl_expr_seq * elts, expr_context_ty ctx, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; if (!ctx) { PyErr_SetString(PyExc_ValueError, "field 'ctx' is required for Tuple"); return NULL; } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Tuple_kind; p->v.Tuple.elts = elts; p->v.Tuple.ctx = ctx; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } expr_ty _PyAST_Slice(expr_ty lower, expr_ty upper, expr_ty step, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { expr_ty p; p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = Slice_kind; p->v.Slice.lower = lower; p->v.Slice.upper = upper; p->v.Slice.step = step; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } comprehension_ty _PyAST_comprehension(expr_ty target, expr_ty iter, asdl_expr_seq * ifs, int is_async, PyArena *arena) { comprehension_ty p; if (!target) { PyErr_SetString(PyExc_ValueError, "field 'target' is required for comprehension"); return NULL; } if (!iter) { PyErr_SetString(PyExc_ValueError, "field 'iter' is required for comprehension"); return NULL; } p = (comprehension_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->target = target; p->iter = iter; p->ifs = ifs; p->is_async = is_async; return p; } excepthandler_ty _PyAST_ExceptHandler(expr_ty type, identifier name, asdl_stmt_seq * body, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { excepthandler_ty p; p = (excepthandler_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = ExceptHandler_kind; p->v.ExceptHandler.type = type; p->v.ExceptHandler.name = name; p->v.ExceptHandler.body = body; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } arguments_ty _PyAST_arguments(asdl_arg_seq * posonlyargs, asdl_arg_seq * args, arg_ty vararg, asdl_arg_seq * kwonlyargs, asdl_expr_seq * kw_defaults, arg_ty kwarg, asdl_expr_seq * defaults, PyArena *arena) { arguments_ty p; p = (arguments_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->posonlyargs = posonlyargs; p->args = args; p->vararg = vararg; p->kwonlyargs = kwonlyargs; p->kw_defaults = kw_defaults; p->kwarg = kwarg; p->defaults = defaults; return p; } arg_ty _PyAST_arg(identifier arg, expr_ty annotation, string type_comment, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { arg_ty p; if (!arg) { PyErr_SetString(PyExc_ValueError, "field 'arg' is required for arg"); return NULL; } p = (arg_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->arg = arg; p->annotation = annotation; p->type_comment = type_comment; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } keyword_ty _PyAST_keyword(identifier arg, expr_ty value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { keyword_ty p; if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for keyword"); return NULL; } p = (keyword_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->arg = arg; p->value = value; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } alias_ty _PyAST_alias(identifier name, identifier asname, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { alias_ty p; if (!name) { PyErr_SetString(PyExc_ValueError, "field 'name' is required for alias"); return NULL; } p = (alias_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->name = name; p->asname = asname; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } withitem_ty _PyAST_withitem(expr_ty context_expr, expr_ty optional_vars, PyArena *arena) { withitem_ty p; if (!context_expr) { PyErr_SetString(PyExc_ValueError, "field 'context_expr' is required for withitem"); return NULL; } p = (withitem_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->context_expr = context_expr; p->optional_vars = optional_vars; return p; } match_case_ty _PyAST_match_case(pattern_ty pattern, expr_ty guard, asdl_stmt_seq * body, PyArena *arena) { match_case_ty p; if (!pattern) { PyErr_SetString(PyExc_ValueError, "field 'pattern' is required for match_case"); return NULL; } p = (match_case_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->pattern = pattern; p->guard = guard; p->body = body; return p; } pattern_ty _PyAST_MatchValue(expr_ty value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { pattern_ty p; if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for MatchValue"); return NULL; } p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = MatchValue_kind; p->v.MatchValue.value = value; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } pattern_ty _PyAST_MatchSingleton(constant value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { pattern_ty p; if (!value) { PyErr_SetString(PyExc_ValueError, "field 'value' is required for MatchSingleton"); return NULL; } p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = MatchSingleton_kind; p->v.MatchSingleton.value = value; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } pattern_ty _PyAST_MatchSequence(asdl_pattern_seq * patterns, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { pattern_ty p; p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = MatchSequence_kind; p->v.MatchSequence.patterns = patterns; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } pattern_ty _PyAST_MatchMapping(asdl_expr_seq * keys, asdl_pattern_seq * patterns, identifier rest, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { pattern_ty p; p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = MatchMapping_kind; p->v.MatchMapping.keys = keys; p->v.MatchMapping.patterns = patterns; p->v.MatchMapping.rest = rest; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } pattern_ty _PyAST_MatchClass(expr_ty cls, asdl_pattern_seq * patterns, asdl_identifier_seq * kwd_attrs, asdl_pattern_seq * kwd_patterns, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { pattern_ty p; if (!cls) { PyErr_SetString(PyExc_ValueError, "field 'cls' is required for MatchClass"); return NULL; } p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = MatchClass_kind; p->v.MatchClass.cls = cls; p->v.MatchClass.patterns = patterns; p->v.MatchClass.kwd_attrs = kwd_attrs; p->v.MatchClass.kwd_patterns = kwd_patterns; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } pattern_ty _PyAST_MatchStar(identifier name, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { pattern_ty p; p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = MatchStar_kind; p->v.MatchStar.name = name; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } pattern_ty _PyAST_MatchAs(pattern_ty pattern, identifier name, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { pattern_ty p; p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = MatchAs_kind; p->v.MatchAs.pattern = pattern; p->v.MatchAs.name = name; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } pattern_ty _PyAST_MatchOr(asdl_pattern_seq * patterns, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { pattern_ty p; p = (pattern_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = MatchOr_kind; p->v.MatchOr.patterns = patterns; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } type_ignore_ty _PyAST_TypeIgnore(int lineno, string tag, PyArena *arena) { type_ignore_ty p; if (!tag) { PyErr_SetString(PyExc_ValueError, "field 'tag' is required for TypeIgnore"); return NULL; } p = (type_ignore_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = TypeIgnore_kind; p->v.TypeIgnore.lineno = lineno; p->v.TypeIgnore.tag = tag; return p; } type_param_ty _PyAST_TypeVar(identifier name, expr_ty bound, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { type_param_ty p; if (!name) { PyErr_SetString(PyExc_ValueError, "field 'name' is required for TypeVar"); return NULL; } p = (type_param_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = TypeVar_kind; p->v.TypeVar.name = name; p->v.TypeVar.bound = bound; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } type_param_ty _PyAST_ParamSpec(identifier name, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { type_param_ty p; if (!name) { PyErr_SetString(PyExc_ValueError, "field 'name' is required for ParamSpec"); return NULL; } p = (type_param_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = ParamSpec_kind; p->v.ParamSpec.name = name; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } type_param_ty _PyAST_TypeVarTuple(identifier name, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { type_param_ty p; if (!name) { PyErr_SetString(PyExc_ValueError, "field 'name' is required for TypeVarTuple"); return NULL; } p = (type_param_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = TypeVarTuple_kind; p->v.TypeVarTuple.name = name; p->lineno = lineno; p->col_offset = col_offset; p->end_lineno = end_lineno; p->end_col_offset = end_col_offset; return p; } PyObject* ast2obj_mod(struct ast_state *state, void* _o) { mod_ty o = (mod_ty)_o; PyObject *result = NULL, *value = NULL; PyTypeObject *tp; if (!o) { Py_RETURN_NONE; } if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during ast construction"); return 0; } switch (o->kind) { case Module_kind: tp = (PyTypeObject *)state->Module_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.Module.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.Module.type_ignores, ast2obj_type_ignore); if (!value) goto failed; if (PyObject_SetAttr(result, state->type_ignores, value) == -1) goto failed; Py_DECREF(value); break; case Interactive_kind: tp = (PyTypeObject *)state->Interactive_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.Interactive.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); break; case Expression_kind: tp = (PyTypeObject *)state->Expression_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.Expression.body); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); break; case FunctionType_kind: tp = (PyTypeObject *)state->FunctionType_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.FunctionType.argtypes, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->argtypes, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.FunctionType.returns); if (!value) goto failed; if (PyObject_SetAttr(result, state->returns, value) == -1) goto failed; Py_DECREF(value); break; } state->recursion_depth--; return result; failed: Py_XDECREF(value); Py_XDECREF(result); return NULL; } PyObject* ast2obj_stmt(struct ast_state *state, void* _o) { stmt_ty o = (stmt_ty)_o; PyObject *result = NULL, *value = NULL; PyTypeObject *tp; if (!o) { Py_RETURN_NONE; } if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during ast construction"); return 0; } switch (o->kind) { case FunctionDef_kind: tp = (PyTypeObject *)state->FunctionDef_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_identifier(state, o->v.FunctionDef.name); if (!value) goto failed; if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_arguments(state, o->v.FunctionDef.args); if (!value) goto failed; if (PyObject_SetAttr(result, state->args, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.FunctionDef.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.FunctionDef.decorator_list, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->decorator_list, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.FunctionDef.returns); if (!value) goto failed; if (PyObject_SetAttr(result, state->returns, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_string(state, o->v.FunctionDef.type_comment); if (!value) goto failed; if (PyObject_SetAttr(result, state->type_comment, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.FunctionDef.type_params, ast2obj_type_param); if (!value) goto failed; if (PyObject_SetAttr(result, state->type_params, value) == -1) goto failed; Py_DECREF(value); break; case AsyncFunctionDef_kind: tp = (PyTypeObject *)state->AsyncFunctionDef_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_identifier(state, o->v.AsyncFunctionDef.name); if (!value) goto failed; if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_arguments(state, o->v.AsyncFunctionDef.args); if (!value) goto failed; if (PyObject_SetAttr(result, state->args, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.AsyncFunctionDef.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.AsyncFunctionDef.decorator_list, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->decorator_list, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.AsyncFunctionDef.returns); if (!value) goto failed; if (PyObject_SetAttr(result, state->returns, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_string(state, o->v.AsyncFunctionDef.type_comment); if (!value) goto failed; if (PyObject_SetAttr(result, state->type_comment, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.AsyncFunctionDef.type_params, ast2obj_type_param); if (!value) goto failed; if (PyObject_SetAttr(result, state->type_params, value) == -1) goto failed; Py_DECREF(value); break; case ClassDef_kind: tp = (PyTypeObject *)state->ClassDef_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_identifier(state, o->v.ClassDef.name); if (!value) goto failed; if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.bases, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->bases, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.keywords, ast2obj_keyword); if (!value) goto failed; if (PyObject_SetAttr(result, state->keywords, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.decorator_list, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->decorator_list, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.type_params, ast2obj_type_param); if (!value) goto failed; if (PyObject_SetAttr(result, state->type_params, value) == -1) goto failed; Py_DECREF(value); break; case Return_kind: tp = (PyTypeObject *)state->Return_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.Return.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); break; case Delete_kind: tp = (PyTypeObject *)state->Delete_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.Delete.targets, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->targets, value) == -1) goto failed; Py_DECREF(value); break; case Assign_kind: tp = (PyTypeObject *)state->Assign_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.Assign.targets, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->targets, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.Assign.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_string(state, o->v.Assign.type_comment); if (!value) goto failed; if (PyObject_SetAttr(result, state->type_comment, value) == -1) goto failed; Py_DECREF(value); break; case TypeAlias_kind: tp = (PyTypeObject *)state->TypeAlias_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.TypeAlias.name); if (!value) goto failed; if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.TypeAlias.type_params, ast2obj_type_param); if (!value) goto failed; if (PyObject_SetAttr(result, state->type_params, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.TypeAlias.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); break; case AugAssign_kind: tp = (PyTypeObject *)state->AugAssign_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.AugAssign.target); if (!value) goto failed; if (PyObject_SetAttr(result, state->target, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_operator(state, o->v.AugAssign.op); if (!value) goto failed; if (PyObject_SetAttr(result, state->op, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.AugAssign.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); break; case AnnAssign_kind: tp = (PyTypeObject *)state->AnnAssign_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.AnnAssign.target); if (!value) goto failed; if (PyObject_SetAttr(result, state->target, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.AnnAssign.annotation); if (!value) goto failed; if (PyObject_SetAttr(result, state->annotation, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.AnnAssign.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->v.AnnAssign.simple); if (!value) goto failed; if (PyObject_SetAttr(result, state->simple, value) == -1) goto failed; Py_DECREF(value); break; case For_kind: tp = (PyTypeObject *)state->For_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.For.target); if (!value) goto failed; if (PyObject_SetAttr(result, state->target, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.For.iter); if (!value) goto failed; if (PyObject_SetAttr(result, state->iter, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.For.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.For.orelse, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->orelse, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_string(state, o->v.For.type_comment); if (!value) goto failed; if (PyObject_SetAttr(result, state->type_comment, value) == -1) goto failed; Py_DECREF(value); break; case AsyncFor_kind: tp = (PyTypeObject *)state->AsyncFor_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.AsyncFor.target); if (!value) goto failed; if (PyObject_SetAttr(result, state->target, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.AsyncFor.iter); if (!value) goto failed; if (PyObject_SetAttr(result, state->iter, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.AsyncFor.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.AsyncFor.orelse, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->orelse, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_string(state, o->v.AsyncFor.type_comment); if (!value) goto failed; if (PyObject_SetAttr(result, state->type_comment, value) == -1) goto failed; Py_DECREF(value); break; case While_kind: tp = (PyTypeObject *)state->While_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.While.test); if (!value) goto failed; if (PyObject_SetAttr(result, state->test, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.While.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.While.orelse, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->orelse, value) == -1) goto failed; Py_DECREF(value); break; case If_kind: tp = (PyTypeObject *)state->If_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.If.test); if (!value) goto failed; if (PyObject_SetAttr(result, state->test, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.If.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.If.orelse, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->orelse, value) == -1) goto failed; Py_DECREF(value); break; case With_kind: tp = (PyTypeObject *)state->With_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.With.items, ast2obj_withitem); if (!value) goto failed; if (PyObject_SetAttr(result, state->items, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.With.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_string(state, o->v.With.type_comment); if (!value) goto failed; if (PyObject_SetAttr(result, state->type_comment, value) == -1) goto failed; Py_DECREF(value); break; case AsyncWith_kind: tp = (PyTypeObject *)state->AsyncWith_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.AsyncWith.items, ast2obj_withitem); if (!value) goto failed; if (PyObject_SetAttr(result, state->items, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.AsyncWith.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_string(state, o->v.AsyncWith.type_comment); if (!value) goto failed; if (PyObject_SetAttr(result, state->type_comment, value) == -1) goto failed; Py_DECREF(value); break; case Match_kind: tp = (PyTypeObject *)state->Match_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.Match.subject); if (!value) goto failed; if (PyObject_SetAttr(result, state->subject, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.Match.cases, ast2obj_match_case); if (!value) goto failed; if (PyObject_SetAttr(result, state->cases, value) == -1) goto failed; Py_DECREF(value); break; case Raise_kind: tp = (PyTypeObject *)state->Raise_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.Raise.exc); if (!value) goto failed; if (PyObject_SetAttr(result, state->exc, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.Raise.cause); if (!value) goto failed; if (PyObject_SetAttr(result, state->cause, value) == -1) goto failed; Py_DECREF(value); break; case Try_kind: tp = (PyTypeObject *)state->Try_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.Try.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.Try.handlers, ast2obj_excepthandler); if (!value) goto failed; if (PyObject_SetAttr(result, state->handlers, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.Try.orelse, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->orelse, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.Try.finalbody, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->finalbody, value) == -1) goto failed; Py_DECREF(value); break; case TryStar_kind: tp = (PyTypeObject *)state->TryStar_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.TryStar.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.TryStar.handlers, ast2obj_excepthandler); if (!value) goto failed; if (PyObject_SetAttr(result, state->handlers, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.TryStar.orelse, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->orelse, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.TryStar.finalbody, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->finalbody, value) == -1) goto failed; Py_DECREF(value); break; case Assert_kind: tp = (PyTypeObject *)state->Assert_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.Assert.test); if (!value) goto failed; if (PyObject_SetAttr(result, state->test, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.Assert.msg); if (!value) goto failed; if (PyObject_SetAttr(result, state->msg, value) == -1) goto failed; Py_DECREF(value); break; case Import_kind: tp = (PyTypeObject *)state->Import_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.Import.names, ast2obj_alias); if (!value) goto failed; if (PyObject_SetAttr(result, state->names, value) == -1) goto failed; Py_DECREF(value); break; case ImportFrom_kind: tp = (PyTypeObject *)state->ImportFrom_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_identifier(state, o->v.ImportFrom.module); if (!value) goto failed; if (PyObject_SetAttr(result, state->module, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.ImportFrom.names, ast2obj_alias); if (!value) goto failed; if (PyObject_SetAttr(result, state->names, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->v.ImportFrom.level); if (!value) goto failed; if (PyObject_SetAttr(result, state->level, value) == -1) goto failed; Py_DECREF(value); break; case Global_kind: tp = (PyTypeObject *)state->Global_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.Global.names, ast2obj_identifier); if (!value) goto failed; if (PyObject_SetAttr(result, state->names, value) == -1) goto failed; Py_DECREF(value); break; case Nonlocal_kind: tp = (PyTypeObject *)state->Nonlocal_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.Nonlocal.names, ast2obj_identifier); if (!value) goto failed; if (PyObject_SetAttr(result, state->names, value) == -1) goto failed; Py_DECREF(value); break; case Expr_kind: tp = (PyTypeObject *)state->Expr_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.Expr.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); break; case Pass_kind: tp = (PyTypeObject *)state->Pass_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; break; case Break_kind: tp = (PyTypeObject *)state->Break_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; break; case Continue_kind: tp = (PyTypeObject *)state->Continue_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; break; } value = ast2obj_int(state, o->lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->col_offset, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_col_offset, value) < 0) goto failed; Py_DECREF(value); state->recursion_depth--; return result; failed: Py_XDECREF(value); Py_XDECREF(result); return NULL; } PyObject* ast2obj_expr(struct ast_state *state, void* _o) { expr_ty o = (expr_ty)_o; PyObject *result = NULL, *value = NULL; PyTypeObject *tp; if (!o) { Py_RETURN_NONE; } if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during ast construction"); return 0; } switch (o->kind) { case BoolOp_kind: tp = (PyTypeObject *)state->BoolOp_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_boolop(state, o->v.BoolOp.op); if (!value) goto failed; if (PyObject_SetAttr(result, state->op, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.BoolOp.values, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->values, value) == -1) goto failed; Py_DECREF(value); break; case NamedExpr_kind: tp = (PyTypeObject *)state->NamedExpr_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.NamedExpr.target); if (!value) goto failed; if (PyObject_SetAttr(result, state->target, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.NamedExpr.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); break; case BinOp_kind: tp = (PyTypeObject *)state->BinOp_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.BinOp.left); if (!value) goto failed; if (PyObject_SetAttr(result, state->left, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_operator(state, o->v.BinOp.op); if (!value) goto failed; if (PyObject_SetAttr(result, state->op, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.BinOp.right); if (!value) goto failed; if (PyObject_SetAttr(result, state->right, value) == -1) goto failed; Py_DECREF(value); break; case UnaryOp_kind: tp = (PyTypeObject *)state->UnaryOp_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_unaryop(state, o->v.UnaryOp.op); if (!value) goto failed; if (PyObject_SetAttr(result, state->op, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.UnaryOp.operand); if (!value) goto failed; if (PyObject_SetAttr(result, state->operand, value) == -1) goto failed; Py_DECREF(value); break; case Lambda_kind: tp = (PyTypeObject *)state->Lambda_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_arguments(state, o->v.Lambda.args); if (!value) goto failed; if (PyObject_SetAttr(result, state->args, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.Lambda.body); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); break; case IfExp_kind: tp = (PyTypeObject *)state->IfExp_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.IfExp.test); if (!value) goto failed; if (PyObject_SetAttr(result, state->test, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.IfExp.body); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.IfExp.orelse); if (!value) goto failed; if (PyObject_SetAttr(result, state->orelse, value) == -1) goto failed; Py_DECREF(value); break; case Dict_kind: tp = (PyTypeObject *)state->Dict_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.Dict.keys, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->keys, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.Dict.values, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->values, value) == -1) goto failed; Py_DECREF(value); break; case Set_kind: tp = (PyTypeObject *)state->Set_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.Set.elts, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->elts, value) == -1) goto failed; Py_DECREF(value); break; case ListComp_kind: tp = (PyTypeObject *)state->ListComp_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.ListComp.elt); if (!value) goto failed; if (PyObject_SetAttr(result, state->elt, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.ListComp.generators, ast2obj_comprehension); if (!value) goto failed; if (PyObject_SetAttr(result, state->generators, value) == -1) goto failed; Py_DECREF(value); break; case SetComp_kind: tp = (PyTypeObject *)state->SetComp_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.SetComp.elt); if (!value) goto failed; if (PyObject_SetAttr(result, state->elt, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.SetComp.generators, ast2obj_comprehension); if (!value) goto failed; if (PyObject_SetAttr(result, state->generators, value) == -1) goto failed; Py_DECREF(value); break; case DictComp_kind: tp = (PyTypeObject *)state->DictComp_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.DictComp.key); if (!value) goto failed; if (PyObject_SetAttr(result, state->key, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.DictComp.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.DictComp.generators, ast2obj_comprehension); if (!value) goto failed; if (PyObject_SetAttr(result, state->generators, value) == -1) goto failed; Py_DECREF(value); break; case GeneratorExp_kind: tp = (PyTypeObject *)state->GeneratorExp_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.GeneratorExp.elt); if (!value) goto failed; if (PyObject_SetAttr(result, state->elt, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.GeneratorExp.generators, ast2obj_comprehension); if (!value) goto failed; if (PyObject_SetAttr(result, state->generators, value) == -1) goto failed; Py_DECREF(value); break; case Await_kind: tp = (PyTypeObject *)state->Await_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.Await.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); break; case Yield_kind: tp = (PyTypeObject *)state->Yield_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.Yield.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); break; case YieldFrom_kind: tp = (PyTypeObject *)state->YieldFrom_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.YieldFrom.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); break; case Compare_kind: tp = (PyTypeObject *)state->Compare_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.Compare.left); if (!value) goto failed; if (PyObject_SetAttr(result, state->left, value) == -1) goto failed; Py_DECREF(value); { Py_ssize_t i, n = asdl_seq_LEN(o->v.Compare.ops); value = PyList_New(n); if (!value) goto failed; for(i = 0; i < n; i++) PyList_SET_ITEM(value, i, ast2obj_cmpop(state, (cmpop_ty)asdl_seq_GET(o->v.Compare.ops, i))); } if (!value) goto failed; if (PyObject_SetAttr(result, state->ops, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.Compare.comparators, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->comparators, value) == -1) goto failed; Py_DECREF(value); break; case Call_kind: tp = (PyTypeObject *)state->Call_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.Call.func); if (!value) goto failed; if (PyObject_SetAttr(result, state->func, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.Call.args, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->args, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.Call.keywords, ast2obj_keyword); if (!value) goto failed; if (PyObject_SetAttr(result, state->keywords, value) == -1) goto failed; Py_DECREF(value); break; case FormattedValue_kind: tp = (PyTypeObject *)state->FormattedValue_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.FormattedValue.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->v.FormattedValue.conversion); if (!value) goto failed; if (PyObject_SetAttr(result, state->conversion, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.FormattedValue.format_spec); if (!value) goto failed; if (PyObject_SetAttr(result, state->format_spec, value) == -1) goto failed; Py_DECREF(value); break; case JoinedStr_kind: tp = (PyTypeObject *)state->JoinedStr_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.JoinedStr.values, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->values, value) == -1) goto failed; Py_DECREF(value); break; case Constant_kind: tp = (PyTypeObject *)state->Constant_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_constant(state, o->v.Constant.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_string(state, o->v.Constant.kind); if (!value) goto failed; if (PyObject_SetAttr(result, state->kind, value) == -1) goto failed; Py_DECREF(value); break; case Attribute_kind: tp = (PyTypeObject *)state->Attribute_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.Attribute.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_identifier(state, o->v.Attribute.attr); if (!value) goto failed; if (PyObject_SetAttr(result, state->attr, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr_context(state, o->v.Attribute.ctx); if (!value) goto failed; if (PyObject_SetAttr(result, state->ctx, value) == -1) goto failed; Py_DECREF(value); break; case Subscript_kind: tp = (PyTypeObject *)state->Subscript_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.Subscript.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.Subscript.slice); if (!value) goto failed; if (PyObject_SetAttr(result, state->slice, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr_context(state, o->v.Subscript.ctx); if (!value) goto failed; if (PyObject_SetAttr(result, state->ctx, value) == -1) goto failed; Py_DECREF(value); break; case Starred_kind: tp = (PyTypeObject *)state->Starred_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.Starred.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr_context(state, o->v.Starred.ctx); if (!value) goto failed; if (PyObject_SetAttr(result, state->ctx, value) == -1) goto failed; Py_DECREF(value); break; case Name_kind: tp = (PyTypeObject *)state->Name_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_identifier(state, o->v.Name.id); if (!value) goto failed; if (PyObject_SetAttr(result, state->id, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr_context(state, o->v.Name.ctx); if (!value) goto failed; if (PyObject_SetAttr(result, state->ctx, value) == -1) goto failed; Py_DECREF(value); break; case List_kind: tp = (PyTypeObject *)state->List_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.List.elts, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->elts, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr_context(state, o->v.List.ctx); if (!value) goto failed; if (PyObject_SetAttr(result, state->ctx, value) == -1) goto failed; Py_DECREF(value); break; case Tuple_kind: tp = (PyTypeObject *)state->Tuple_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.Tuple.elts, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->elts, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr_context(state, o->v.Tuple.ctx); if (!value) goto failed; if (PyObject_SetAttr(result, state->ctx, value) == -1) goto failed; Py_DECREF(value); break; case Slice_kind: tp = (PyTypeObject *)state->Slice_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.Slice.lower); if (!value) goto failed; if (PyObject_SetAttr(result, state->lower, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.Slice.upper); if (!value) goto failed; if (PyObject_SetAttr(result, state->upper, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.Slice.step); if (!value) goto failed; if (PyObject_SetAttr(result, state->step, value) == -1) goto failed; Py_DECREF(value); break; } value = ast2obj_int(state, o->lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->col_offset, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_col_offset, value) < 0) goto failed; Py_DECREF(value); state->recursion_depth--; return result; failed: Py_XDECREF(value); Py_XDECREF(result); return NULL; } PyObject* ast2obj_expr_context(struct ast_state *state, expr_context_ty o) { switch(o) { case Load: return Py_NewRef(state->Load_singleton); case Store: return Py_NewRef(state->Store_singleton); case Del: return Py_NewRef(state->Del_singleton); } Py_UNREACHABLE(); } PyObject* ast2obj_boolop(struct ast_state *state, boolop_ty o) { switch(o) { case And: return Py_NewRef(state->And_singleton); case Or: return Py_NewRef(state->Or_singleton); } Py_UNREACHABLE(); } PyObject* ast2obj_operator(struct ast_state *state, operator_ty o) { switch(o) { case Add: return Py_NewRef(state->Add_singleton); case Sub: return Py_NewRef(state->Sub_singleton); case Mult: return Py_NewRef(state->Mult_singleton); case MatMult: return Py_NewRef(state->MatMult_singleton); case Div: return Py_NewRef(state->Div_singleton); case Mod: return Py_NewRef(state->Mod_singleton); case Pow: return Py_NewRef(state->Pow_singleton); case LShift: return Py_NewRef(state->LShift_singleton); case RShift: return Py_NewRef(state->RShift_singleton); case BitOr: return Py_NewRef(state->BitOr_singleton); case BitXor: return Py_NewRef(state->BitXor_singleton); case BitAnd: return Py_NewRef(state->BitAnd_singleton); case FloorDiv: return Py_NewRef(state->FloorDiv_singleton); } Py_UNREACHABLE(); } PyObject* ast2obj_unaryop(struct ast_state *state, unaryop_ty o) { switch(o) { case Invert: return Py_NewRef(state->Invert_singleton); case Not: return Py_NewRef(state->Not_singleton); case UAdd: return Py_NewRef(state->UAdd_singleton); case USub: return Py_NewRef(state->USub_singleton); } Py_UNREACHABLE(); } PyObject* ast2obj_cmpop(struct ast_state *state, cmpop_ty o) { switch(o) { case Eq: return Py_NewRef(state->Eq_singleton); case NotEq: return Py_NewRef(state->NotEq_singleton); case Lt: return Py_NewRef(state->Lt_singleton); case LtE: return Py_NewRef(state->LtE_singleton); case Gt: return Py_NewRef(state->Gt_singleton); case GtE: return Py_NewRef(state->GtE_singleton); case Is: return Py_NewRef(state->Is_singleton); case IsNot: return Py_NewRef(state->IsNot_singleton); case In: return Py_NewRef(state->In_singleton); case NotIn: return Py_NewRef(state->NotIn_singleton); } Py_UNREACHABLE(); } PyObject* ast2obj_comprehension(struct ast_state *state, void* _o) { comprehension_ty o = (comprehension_ty)_o; PyObject *result = NULL, *value = NULL; PyTypeObject *tp; if (!o) { Py_RETURN_NONE; } if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during ast construction"); return 0; } tp = (PyTypeObject *)state->comprehension_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) return NULL; value = ast2obj_expr(state, o->target); if (!value) goto failed; if (PyObject_SetAttr(result, state->target, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->iter); if (!value) goto failed; if (PyObject_SetAttr(result, state->iter, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->ifs, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->ifs, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->is_async); if (!value) goto failed; if (PyObject_SetAttr(result, state->is_async, value) == -1) goto failed; Py_DECREF(value); state->recursion_depth--; return result; failed: Py_XDECREF(value); Py_XDECREF(result); return NULL; } PyObject* ast2obj_excepthandler(struct ast_state *state, void* _o) { excepthandler_ty o = (excepthandler_ty)_o; PyObject *result = NULL, *value = NULL; PyTypeObject *tp; if (!o) { Py_RETURN_NONE; } if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during ast construction"); return 0; } switch (o->kind) { case ExceptHandler_kind: tp = (PyTypeObject *)state->ExceptHandler_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.ExceptHandler.type); if (!value) goto failed; if (PyObject_SetAttr(result, state->type, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_identifier(state, o->v.ExceptHandler.name); if (!value) goto failed; if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.ExceptHandler.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); break; } value = ast2obj_int(state, o->lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->col_offset, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_col_offset, value) < 0) goto failed; Py_DECREF(value); state->recursion_depth--; return result; failed: Py_XDECREF(value); Py_XDECREF(result); return NULL; } PyObject* ast2obj_arguments(struct ast_state *state, void* _o) { arguments_ty o = (arguments_ty)_o; PyObject *result = NULL, *value = NULL; PyTypeObject *tp; if (!o) { Py_RETURN_NONE; } if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during ast construction"); return 0; } tp = (PyTypeObject *)state->arguments_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) return NULL; value = ast2obj_list(state, (asdl_seq*)o->posonlyargs, ast2obj_arg); if (!value) goto failed; if (PyObject_SetAttr(result, state->posonlyargs, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->args, ast2obj_arg); if (!value) goto failed; if (PyObject_SetAttr(result, state->args, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_arg(state, o->vararg); if (!value) goto failed; if (PyObject_SetAttr(result, state->vararg, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->kwonlyargs, ast2obj_arg); if (!value) goto failed; if (PyObject_SetAttr(result, state->kwonlyargs, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->kw_defaults, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->kw_defaults, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_arg(state, o->kwarg); if (!value) goto failed; if (PyObject_SetAttr(result, state->kwarg, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->defaults, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->defaults, value) == -1) goto failed; Py_DECREF(value); state->recursion_depth--; return result; failed: Py_XDECREF(value); Py_XDECREF(result); return NULL; } PyObject* ast2obj_arg(struct ast_state *state, void* _o) { arg_ty o = (arg_ty)_o; PyObject *result = NULL, *value = NULL; PyTypeObject *tp; if (!o) { Py_RETURN_NONE; } if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during ast construction"); return 0; } tp = (PyTypeObject *)state->arg_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) return NULL; value = ast2obj_identifier(state, o->arg); if (!value) goto failed; if (PyObject_SetAttr(result, state->arg, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->annotation); if (!value) goto failed; if (PyObject_SetAttr(result, state->annotation, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_string(state, o->type_comment); if (!value) goto failed; if (PyObject_SetAttr(result, state->type_comment, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->col_offset, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_col_offset, value) < 0) goto failed; Py_DECREF(value); state->recursion_depth--; return result; failed: Py_XDECREF(value); Py_XDECREF(result); return NULL; } PyObject* ast2obj_keyword(struct ast_state *state, void* _o) { keyword_ty o = (keyword_ty)_o; PyObject *result = NULL, *value = NULL; PyTypeObject *tp; if (!o) { Py_RETURN_NONE; } if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during ast construction"); return 0; } tp = (PyTypeObject *)state->keyword_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) return NULL; value = ast2obj_identifier(state, o->arg); if (!value) goto failed; if (PyObject_SetAttr(result, state->arg, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->col_offset, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_col_offset, value) < 0) goto failed; Py_DECREF(value); state->recursion_depth--; return result; failed: Py_XDECREF(value); Py_XDECREF(result); return NULL; } PyObject* ast2obj_alias(struct ast_state *state, void* _o) { alias_ty o = (alias_ty)_o; PyObject *result = NULL, *value = NULL; PyTypeObject *tp; if (!o) { Py_RETURN_NONE; } if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during ast construction"); return 0; } tp = (PyTypeObject *)state->alias_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) return NULL; value = ast2obj_identifier(state, o->name); if (!value) goto failed; if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_identifier(state, o->asname); if (!value) goto failed; if (PyObject_SetAttr(result, state->asname, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->col_offset, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_col_offset, value) < 0) goto failed; Py_DECREF(value); state->recursion_depth--; return result; failed: Py_XDECREF(value); Py_XDECREF(result); return NULL; } PyObject* ast2obj_withitem(struct ast_state *state, void* _o) { withitem_ty o = (withitem_ty)_o; PyObject *result = NULL, *value = NULL; PyTypeObject *tp; if (!o) { Py_RETURN_NONE; } if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during ast construction"); return 0; } tp = (PyTypeObject *)state->withitem_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) return NULL; value = ast2obj_expr(state, o->context_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->context_expr, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->optional_vars); if (!value) goto failed; if (PyObject_SetAttr(result, state->optional_vars, value) == -1) goto failed; Py_DECREF(value); state->recursion_depth--; return result; failed: Py_XDECREF(value); Py_XDECREF(result); return NULL; } PyObject* ast2obj_match_case(struct ast_state *state, void* _o) { match_case_ty o = (match_case_ty)_o; PyObject *result = NULL, *value = NULL; PyTypeObject *tp; if (!o) { Py_RETURN_NONE; } if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during ast construction"); return 0; } tp = (PyTypeObject *)state->match_case_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) return NULL; value = ast2obj_pattern(state, o->pattern); if (!value) goto failed; if (PyObject_SetAttr(result, state->pattern, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->guard); if (!value) goto failed; if (PyObject_SetAttr(result, state->guard, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttr(result, state->body, value) == -1) goto failed; Py_DECREF(value); state->recursion_depth--; return result; failed: Py_XDECREF(value); Py_XDECREF(result); return NULL; } PyObject* ast2obj_pattern(struct ast_state *state, void* _o) { pattern_ty o = (pattern_ty)_o; PyObject *result = NULL, *value = NULL; PyTypeObject *tp; if (!o) { Py_RETURN_NONE; } if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during ast construction"); return 0; } switch (o->kind) { case MatchValue_kind: tp = (PyTypeObject *)state->MatchValue_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.MatchValue.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); break; case MatchSingleton_kind: tp = (PyTypeObject *)state->MatchSingleton_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_constant(state, o->v.MatchSingleton.value); if (!value) goto failed; if (PyObject_SetAttr(result, state->value, value) == -1) goto failed; Py_DECREF(value); break; case MatchSequence_kind: tp = (PyTypeObject *)state->MatchSequence_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.MatchSequence.patterns, ast2obj_pattern); if (!value) goto failed; if (PyObject_SetAttr(result, state->patterns, value) == -1) goto failed; Py_DECREF(value); break; case MatchMapping_kind: tp = (PyTypeObject *)state->MatchMapping_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.MatchMapping.keys, ast2obj_expr); if (!value) goto failed; if (PyObject_SetAttr(result, state->keys, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.MatchMapping.patterns, ast2obj_pattern); if (!value) goto failed; if (PyObject_SetAttr(result, state->patterns, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_identifier(state, o->v.MatchMapping.rest); if (!value) goto failed; if (PyObject_SetAttr(result, state->rest, value) == -1) goto failed; Py_DECREF(value); break; case MatchClass_kind: tp = (PyTypeObject *)state->MatchClass_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_expr(state, o->v.MatchClass.cls); if (!value) goto failed; if (PyObject_SetAttr(result, state->cls, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.MatchClass.patterns, ast2obj_pattern); if (!value) goto failed; if (PyObject_SetAttr(result, state->patterns, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.MatchClass.kwd_attrs, ast2obj_identifier); if (!value) goto failed; if (PyObject_SetAttr(result, state->kwd_attrs, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.MatchClass.kwd_patterns, ast2obj_pattern); if (!value) goto failed; if (PyObject_SetAttr(result, state->kwd_patterns, value) == -1) goto failed; Py_DECREF(value); break; case MatchStar_kind: tp = (PyTypeObject *)state->MatchStar_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_identifier(state, o->v.MatchStar.name); if (!value) goto failed; if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); break; case MatchAs_kind: tp = (PyTypeObject *)state->MatchAs_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_pattern(state, o->v.MatchAs.pattern); if (!value) goto failed; if (PyObject_SetAttr(result, state->pattern, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_identifier(state, o->v.MatchAs.name); if (!value) goto failed; if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); break; case MatchOr_kind: tp = (PyTypeObject *)state->MatchOr_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_list(state, (asdl_seq*)o->v.MatchOr.patterns, ast2obj_pattern); if (!value) goto failed; if (PyObject_SetAttr(result, state->patterns, value) == -1) goto failed; Py_DECREF(value); break; } value = ast2obj_int(state, o->lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->col_offset, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_col_offset, value) < 0) goto failed; Py_DECREF(value); state->recursion_depth--; return result; failed: Py_XDECREF(value); Py_XDECREF(result); return NULL; } PyObject* ast2obj_type_ignore(struct ast_state *state, void* _o) { type_ignore_ty o = (type_ignore_ty)_o; PyObject *result = NULL, *value = NULL; PyTypeObject *tp; if (!o) { Py_RETURN_NONE; } if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during ast construction"); return 0; } switch (o->kind) { case TypeIgnore_kind: tp = (PyTypeObject *)state->TypeIgnore_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_int(state, o->v.TypeIgnore.lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->lineno, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_string(state, o->v.TypeIgnore.tag); if (!value) goto failed; if (PyObject_SetAttr(result, state->tag, value) == -1) goto failed; Py_DECREF(value); break; } state->recursion_depth--; return result; failed: Py_XDECREF(value); Py_XDECREF(result); return NULL; } PyObject* ast2obj_type_param(struct ast_state *state, void* _o) { type_param_ty o = (type_param_ty)_o; PyObject *result = NULL, *value = NULL; PyTypeObject *tp; if (!o) { Py_RETURN_NONE; } if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during ast construction"); return 0; } switch (o->kind) { case TypeVar_kind: tp = (PyTypeObject *)state->TypeVar_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_identifier(state, o->v.TypeVar.name); if (!value) goto failed; if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.TypeVar.bound); if (!value) goto failed; if (PyObject_SetAttr(result, state->bound, value) == -1) goto failed; Py_DECREF(value); break; case ParamSpec_kind: tp = (PyTypeObject *)state->ParamSpec_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_identifier(state, o->v.ParamSpec.name); if (!value) goto failed; if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); break; case TypeVarTuple_kind: tp = (PyTypeObject *)state->TypeVarTuple_type; result = PyType_GenericNew(tp, NULL, NULL); if (!result) goto failed; value = ast2obj_identifier(state, o->v.TypeVarTuple.name); if (!value) goto failed; if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); break; } value = ast2obj_int(state, o->lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->col_offset, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_lineno); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_lineno, value) < 0) goto failed; Py_DECREF(value); value = ast2obj_int(state, o->end_col_offset); if (!value) goto failed; if (PyObject_SetAttr(result, state->end_col_offset, value) < 0) goto failed; Py_DECREF(value); state->recursion_depth--; return result; failed: Py_XDECREF(value); Py_XDECREF(result); return NULL; } int obj2ast_mod(struct ast_state *state, PyObject* obj, mod_ty* out, PyArena* arena) { int isinstance; PyObject *tmp = NULL; PyObject *tp; if (obj == Py_None) { *out = NULL; return 0; } tp = state->Module_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_stmt_seq* body; asdl_type_ignore_seq* type_ignores; if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Module"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Module field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); body = _Py_asdl_stmt_seq_new(len, arena); if (body == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Module' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Module field \"body\" changed size during iteration"); goto failed; } asdl_seq_SET(body, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->type_ignores, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"type_ignores\" missing from Module"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Module field \"type_ignores\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); type_ignores = _Py_asdl_type_ignore_seq_new(len, arena); if (type_ignores == NULL) goto failed; for (i = 0; i < len; i++) { type_ignore_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Module' node")) { goto failed; } res = obj2ast_type_ignore(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Module field \"type_ignores\" changed size during iteration"); goto failed; } asdl_seq_SET(type_ignores, i, val); } Py_CLEAR(tmp); } *out = _PyAST_Module(body, type_ignores, arena); if (*out == NULL) goto failed; return 0; } tp = state->Interactive_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_stmt_seq* body; if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Interactive"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Interactive field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); body = _Py_asdl_stmt_seq_new(len, arena); if (body == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Interactive' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Interactive field \"body\" changed size during iteration"); goto failed; } asdl_seq_SET(body, i, val); } Py_CLEAR(tmp); } *out = _PyAST_Interactive(body, arena); if (*out == NULL) goto failed; return 0; } tp = state->Expression_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty body; if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Expression"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Expression' node")) { goto failed; } res = obj2ast_expr(state, tmp, &body, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Expression(body, arena); if (*out == NULL) goto failed; return 0; } tp = state->FunctionType_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_expr_seq* argtypes; expr_ty returns; if (_PyObject_LookupAttr(obj, state->argtypes, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"argtypes\" missing from FunctionType"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "FunctionType field \"argtypes\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); argtypes = _Py_asdl_expr_seq_new(len, arena); if (argtypes == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'FunctionType' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "FunctionType field \"argtypes\" changed size during iteration"); goto failed; } asdl_seq_SET(argtypes, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->returns, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"returns\" missing from FunctionType"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'FunctionType' node")) { goto failed; } res = obj2ast_expr(state, tmp, &returns, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_FunctionType(argtypes, returns, arena); if (*out == NULL) goto failed; return 0; } PyErr_Format(PyExc_TypeError, "expected some sort of mod, but got %R", obj); failed: Py_XDECREF(tmp); return 1; } int obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* arena) { int isinstance; PyObject *tmp = NULL; PyObject *tp; int lineno; int col_offset; int end_lineno; int end_col_offset; if (obj == Py_None) { *out = NULL; return 0; } if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from stmt"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'stmt' node")) { goto failed; } res = obj2ast_int(state, tmp, &lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from stmt"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'stmt' node")) { goto failed; } res = obj2ast_int(state, tmp, &col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); end_lineno = lineno; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'stmt' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); end_col_offset = col_offset; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'stmt' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } tp = state->FunctionDef_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { identifier name; arguments_ty args; asdl_stmt_seq* body; asdl_expr_seq* decorator_list; expr_ty returns; string type_comment; asdl_type_param_seq* type_params; if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from FunctionDef"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'FunctionDef' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &name, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from FunctionDef"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'FunctionDef' node")) { goto failed; } res = obj2ast_arguments(state, tmp, &args, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from FunctionDef"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "FunctionDef field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); body = _Py_asdl_stmt_seq_new(len, arena); if (body == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'FunctionDef' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"body\" changed size during iteration"); goto failed; } asdl_seq_SET(body, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->decorator_list, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from FunctionDef"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "FunctionDef field \"decorator_list\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); decorator_list = _Py_asdl_expr_seq_new(len, arena); if (decorator_list == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'FunctionDef' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"decorator_list\" changed size during iteration"); goto failed; } asdl_seq_SET(decorator_list, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->returns, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); returns = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'FunctionDef' node")) { goto failed; } res = obj2ast_expr(state, tmp, &returns, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); type_comment = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'FunctionDef' node")) { goto failed; } res = obj2ast_string(state, tmp, &type_comment, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from FunctionDef"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "FunctionDef field \"type_params\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); type_params = _Py_asdl_type_param_seq_new(len, arena); if (type_params == NULL) goto failed; for (i = 0; i < len; i++) { type_param_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'FunctionDef' node")) { goto failed; } res = obj2ast_type_param(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"type_params\" changed size during iteration"); goto failed; } asdl_seq_SET(type_params, i, val); } Py_CLEAR(tmp); } *out = _PyAST_FunctionDef(name, args, body, decorator_list, returns, type_comment, type_params, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->AsyncFunctionDef_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { identifier name; arguments_ty args; asdl_stmt_seq* body; asdl_expr_seq* decorator_list; expr_ty returns; string type_comment; asdl_type_param_seq* type_params; if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from AsyncFunctionDef"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'AsyncFunctionDef' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &name, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from AsyncFunctionDef"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'AsyncFunctionDef' node")) { goto failed; } res = obj2ast_arguments(state, tmp, &args, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncFunctionDef"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "AsyncFunctionDef field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); body = _Py_asdl_stmt_seq_new(len, arena); if (body == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'AsyncFunctionDef' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"body\" changed size during iteration"); goto failed; } asdl_seq_SET(body, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->decorator_list, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from AsyncFunctionDef"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "AsyncFunctionDef field \"decorator_list\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); decorator_list = _Py_asdl_expr_seq_new(len, arena); if (decorator_list == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'AsyncFunctionDef' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"decorator_list\" changed size during iteration"); goto failed; } asdl_seq_SET(decorator_list, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->returns, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); returns = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'AsyncFunctionDef' node")) { goto failed; } res = obj2ast_expr(state, tmp, &returns, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); type_comment = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'AsyncFunctionDef' node")) { goto failed; } res = obj2ast_string(state, tmp, &type_comment, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from AsyncFunctionDef"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "AsyncFunctionDef field \"type_params\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); type_params = _Py_asdl_type_param_seq_new(len, arena); if (type_params == NULL) goto failed; for (i = 0; i < len; i++) { type_param_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'AsyncFunctionDef' node")) { goto failed; } res = obj2ast_type_param(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"type_params\" changed size during iteration"); goto failed; } asdl_seq_SET(type_params, i, val); } Py_CLEAR(tmp); } *out = _PyAST_AsyncFunctionDef(name, args, body, decorator_list, returns, type_comment, type_params, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->ClassDef_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { identifier name; asdl_expr_seq* bases; asdl_keyword_seq* keywords; asdl_stmt_seq* body; asdl_expr_seq* decorator_list; asdl_type_param_seq* type_params; if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from ClassDef"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'ClassDef' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &name, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->bases, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"bases\" missing from ClassDef"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "ClassDef field \"bases\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); bases = _Py_asdl_expr_seq_new(len, arena); if (bases == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'ClassDef' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"bases\" changed size during iteration"); goto failed; } asdl_seq_SET(bases, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->keywords, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from ClassDef"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "ClassDef field \"keywords\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); keywords = _Py_asdl_keyword_seq_new(len, arena); if (keywords == NULL) goto failed; for (i = 0; i < len; i++) { keyword_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'ClassDef' node")) { goto failed; } res = obj2ast_keyword(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"keywords\" changed size during iteration"); goto failed; } asdl_seq_SET(keywords, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ClassDef"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "ClassDef field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); body = _Py_asdl_stmt_seq_new(len, arena); if (body == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'ClassDef' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"body\" changed size during iteration"); goto failed; } asdl_seq_SET(body, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->decorator_list, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"decorator_list\" missing from ClassDef"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "ClassDef field \"decorator_list\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); decorator_list = _Py_asdl_expr_seq_new(len, arena); if (decorator_list == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'ClassDef' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"decorator_list\" changed size during iteration"); goto failed; } asdl_seq_SET(decorator_list, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from ClassDef"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "ClassDef field \"type_params\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); type_params = _Py_asdl_type_param_seq_new(len, arena); if (type_params == NULL) goto failed; for (i = 0; i < len; i++) { type_param_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'ClassDef' node")) { goto failed; } res = obj2ast_type_param(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"type_params\" changed size during iteration"); goto failed; } asdl_seq_SET(type_params, i, val); } Py_CLEAR(tmp); } *out = _PyAST_ClassDef(name, bases, keywords, body, decorator_list, type_params, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Return_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty value; if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); value = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Return' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Return(value, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Delete_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_expr_seq* targets; if (_PyObject_LookupAttr(obj, state->targets, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Delete"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Delete field \"targets\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); targets = _Py_asdl_expr_seq_new(len, arena); if (targets == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Delete' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Delete field \"targets\" changed size during iteration"); goto failed; } asdl_seq_SET(targets, i, val); } Py_CLEAR(tmp); } *out = _PyAST_Delete(targets, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Assign_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_expr_seq* targets; expr_ty value; string type_comment; if (_PyObject_LookupAttr(obj, state->targets, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"targets\" missing from Assign"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Assign field \"targets\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); targets = _Py_asdl_expr_seq_new(len, arena); if (targets == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Assign' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Assign field \"targets\" changed size during iteration"); goto failed; } asdl_seq_SET(targets, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Assign"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Assign' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); type_comment = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Assign' node")) { goto failed; } res = obj2ast_string(state, tmp, &type_comment, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Assign(targets, value, type_comment, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->TypeAlias_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty name; asdl_type_param_seq* type_params; expr_ty value; if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from TypeAlias"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'TypeAlias' node")) { goto failed; } res = obj2ast_expr(state, tmp, &name, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from TypeAlias"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "TypeAlias field \"type_params\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); type_params = _Py_asdl_type_param_seq_new(len, arena); if (type_params == NULL) goto failed; for (i = 0; i < len; i++) { type_param_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'TypeAlias' node")) { goto failed; } res = obj2ast_type_param(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "TypeAlias field \"type_params\" changed size during iteration"); goto failed; } asdl_seq_SET(type_params, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from TypeAlias"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'TypeAlias' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_TypeAlias(name, type_params, value, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->AugAssign_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty target; operator_ty op; expr_ty value; if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AugAssign"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'AugAssign' node")) { goto failed; } res = obj2ast_expr(state, tmp, &target, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->op, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from AugAssign"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'AugAssign' node")) { goto failed; } res = obj2ast_operator(state, tmp, &op, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from AugAssign"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'AugAssign' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_AugAssign(target, op, value, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->AnnAssign_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty target; expr_ty annotation; expr_ty value; int simple; if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AnnAssign"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'AnnAssign' node")) { goto failed; } res = obj2ast_expr(state, tmp, &target, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->annotation, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"annotation\" missing from AnnAssign"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'AnnAssign' node")) { goto failed; } res = obj2ast_expr(state, tmp, &annotation, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); value = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'AnnAssign' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->simple, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"simple\" missing from AnnAssign"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'AnnAssign' node")) { goto failed; } res = obj2ast_int(state, tmp, &simple, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_AnnAssign(target, annotation, value, simple, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->For_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty target; expr_ty iter; asdl_stmt_seq* body; asdl_stmt_seq* orelse; string type_comment; if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from For"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'For' node")) { goto failed; } res = obj2ast_expr(state, tmp, &target, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->iter, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from For"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'For' node")) { goto failed; } res = obj2ast_expr(state, tmp, &iter, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from For"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "For field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); body = _Py_asdl_stmt_seq_new(len, arena); if (body == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'For' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "For field \"body\" changed size during iteration"); goto failed; } asdl_seq_SET(body, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from For"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "For field \"orelse\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); orelse = _Py_asdl_stmt_seq_new(len, arena); if (orelse == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'For' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "For field \"orelse\" changed size during iteration"); goto failed; } asdl_seq_SET(orelse, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); type_comment = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'For' node")) { goto failed; } res = obj2ast_string(state, tmp, &type_comment, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_For(target, iter, body, orelse, type_comment, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->AsyncFor_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty target; expr_ty iter; asdl_stmt_seq* body; asdl_stmt_seq* orelse; string type_comment; if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from AsyncFor"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'AsyncFor' node")) { goto failed; } res = obj2ast_expr(state, tmp, &target, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->iter, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from AsyncFor"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'AsyncFor' node")) { goto failed; } res = obj2ast_expr(state, tmp, &iter, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncFor"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "AsyncFor field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); body = _Py_asdl_stmt_seq_new(len, arena); if (body == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'AsyncFor' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "AsyncFor field \"body\" changed size during iteration"); goto failed; } asdl_seq_SET(body, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from AsyncFor"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "AsyncFor field \"orelse\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); orelse = _Py_asdl_stmt_seq_new(len, arena); if (orelse == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'AsyncFor' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "AsyncFor field \"orelse\" changed size during iteration"); goto failed; } asdl_seq_SET(orelse, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); type_comment = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'AsyncFor' node")) { goto failed; } res = obj2ast_string(state, tmp, &type_comment, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_AsyncFor(target, iter, body, orelse, type_comment, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->While_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty test; asdl_stmt_seq* body; asdl_stmt_seq* orelse; if (_PyObject_LookupAttr(obj, state->test, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from While"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'While' node")) { goto failed; } res = obj2ast_expr(state, tmp, &test, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from While"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "While field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); body = _Py_asdl_stmt_seq_new(len, arena); if (body == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'While' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "While field \"body\" changed size during iteration"); goto failed; } asdl_seq_SET(body, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from While"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "While field \"orelse\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); orelse = _Py_asdl_stmt_seq_new(len, arena); if (orelse == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'While' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "While field \"orelse\" changed size during iteration"); goto failed; } asdl_seq_SET(orelse, i, val); } Py_CLEAR(tmp); } *out = _PyAST_While(test, body, orelse, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->If_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty test; asdl_stmt_seq* body; asdl_stmt_seq* orelse; if (_PyObject_LookupAttr(obj, state->test, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from If"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'If' node")) { goto failed; } res = obj2ast_expr(state, tmp, &test, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from If"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "If field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); body = _Py_asdl_stmt_seq_new(len, arena); if (body == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'If' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "If field \"body\" changed size during iteration"); goto failed; } asdl_seq_SET(body, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from If"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "If field \"orelse\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); orelse = _Py_asdl_stmt_seq_new(len, arena); if (orelse == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'If' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "If field \"orelse\" changed size during iteration"); goto failed; } asdl_seq_SET(orelse, i, val); } Py_CLEAR(tmp); } *out = _PyAST_If(test, body, orelse, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->With_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_withitem_seq* items; asdl_stmt_seq* body; string type_comment; if (_PyObject_LookupAttr(obj, state->items, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from With"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "With field \"items\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); items = _Py_asdl_withitem_seq_new(len, arena); if (items == NULL) goto failed; for (i = 0; i < len; i++) { withitem_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'With' node")) { goto failed; } res = obj2ast_withitem(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "With field \"items\" changed size during iteration"); goto failed; } asdl_seq_SET(items, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from With"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "With field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); body = _Py_asdl_stmt_seq_new(len, arena); if (body == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'With' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "With field \"body\" changed size during iteration"); goto failed; } asdl_seq_SET(body, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); type_comment = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'With' node")) { goto failed; } res = obj2ast_string(state, tmp, &type_comment, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_With(items, body, type_comment, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->AsyncWith_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_withitem_seq* items; asdl_stmt_seq* body; string type_comment; if (_PyObject_LookupAttr(obj, state->items, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"items\" missing from AsyncWith"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "AsyncWith field \"items\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); items = _Py_asdl_withitem_seq_new(len, arena); if (items == NULL) goto failed; for (i = 0; i < len; i++) { withitem_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'AsyncWith' node")) { goto failed; } res = obj2ast_withitem(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "AsyncWith field \"items\" changed size during iteration"); goto failed; } asdl_seq_SET(items, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from AsyncWith"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "AsyncWith field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); body = _Py_asdl_stmt_seq_new(len, arena); if (body == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'AsyncWith' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "AsyncWith field \"body\" changed size during iteration"); goto failed; } asdl_seq_SET(body, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); type_comment = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'AsyncWith' node")) { goto failed; } res = obj2ast_string(state, tmp, &type_comment, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_AsyncWith(items, body, type_comment, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Match_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty subject; asdl_match_case_seq* cases; if (_PyObject_LookupAttr(obj, state->subject, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"subject\" missing from Match"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Match' node")) { goto failed; } res = obj2ast_expr(state, tmp, &subject, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->cases, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"cases\" missing from Match"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Match field \"cases\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); cases = _Py_asdl_match_case_seq_new(len, arena); if (cases == NULL) goto failed; for (i = 0; i < len; i++) { match_case_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Match' node")) { goto failed; } res = obj2ast_match_case(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Match field \"cases\" changed size during iteration"); goto failed; } asdl_seq_SET(cases, i, val); } Py_CLEAR(tmp); } *out = _PyAST_Match(subject, cases, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Raise_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty exc; expr_ty cause; if (_PyObject_LookupAttr(obj, state->exc, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); exc = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Raise' node")) { goto failed; } res = obj2ast_expr(state, tmp, &exc, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->cause, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); cause = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Raise' node")) { goto failed; } res = obj2ast_expr(state, tmp, &cause, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Raise(exc, cause, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Try_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_stmt_seq* body; asdl_excepthandler_seq* handlers; asdl_stmt_seq* orelse; asdl_stmt_seq* finalbody; if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Try"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Try field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); body = _Py_asdl_stmt_seq_new(len, arena); if (body == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Try' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Try field \"body\" changed size during iteration"); goto failed; } asdl_seq_SET(body, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->handlers, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"handlers\" missing from Try"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Try field \"handlers\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); handlers = _Py_asdl_excepthandler_seq_new(len, arena); if (handlers == NULL) goto failed; for (i = 0; i < len; i++) { excepthandler_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Try' node")) { goto failed; } res = obj2ast_excepthandler(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Try field \"handlers\" changed size during iteration"); goto failed; } asdl_seq_SET(handlers, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from Try"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Try field \"orelse\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); orelse = _Py_asdl_stmt_seq_new(len, arena); if (orelse == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Try' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Try field \"orelse\" changed size during iteration"); goto failed; } asdl_seq_SET(orelse, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->finalbody, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"finalbody\" missing from Try"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Try field \"finalbody\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); finalbody = _Py_asdl_stmt_seq_new(len, arena); if (finalbody == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Try' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Try field \"finalbody\" changed size during iteration"); goto failed; } asdl_seq_SET(finalbody, i, val); } Py_CLEAR(tmp); } *out = _PyAST_Try(body, handlers, orelse, finalbody, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->TryStar_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_stmt_seq* body; asdl_excepthandler_seq* handlers; asdl_stmt_seq* orelse; asdl_stmt_seq* finalbody; if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from TryStar"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "TryStar field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); body = _Py_asdl_stmt_seq_new(len, arena); if (body == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'TryStar' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "TryStar field \"body\" changed size during iteration"); goto failed; } asdl_seq_SET(body, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->handlers, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"handlers\" missing from TryStar"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "TryStar field \"handlers\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); handlers = _Py_asdl_excepthandler_seq_new(len, arena); if (handlers == NULL) goto failed; for (i = 0; i < len; i++) { excepthandler_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'TryStar' node")) { goto failed; } res = obj2ast_excepthandler(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "TryStar field \"handlers\" changed size during iteration"); goto failed; } asdl_seq_SET(handlers, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from TryStar"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "TryStar field \"orelse\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); orelse = _Py_asdl_stmt_seq_new(len, arena); if (orelse == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'TryStar' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "TryStar field \"orelse\" changed size during iteration"); goto failed; } asdl_seq_SET(orelse, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->finalbody, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"finalbody\" missing from TryStar"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "TryStar field \"finalbody\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); finalbody = _Py_asdl_stmt_seq_new(len, arena); if (finalbody == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'TryStar' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "TryStar field \"finalbody\" changed size during iteration"); goto failed; } asdl_seq_SET(finalbody, i, val); } Py_CLEAR(tmp); } *out = _PyAST_TryStar(body, handlers, orelse, finalbody, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Assert_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty test; expr_ty msg; if (_PyObject_LookupAttr(obj, state->test, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from Assert"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Assert' node")) { goto failed; } res = obj2ast_expr(state, tmp, &test, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->msg, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); msg = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Assert' node")) { goto failed; } res = obj2ast_expr(state, tmp, &msg, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Assert(test, msg, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Import_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_alias_seq* names; if (_PyObject_LookupAttr(obj, state->names, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Import"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Import field \"names\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); names = _Py_asdl_alias_seq_new(len, arena); if (names == NULL) goto failed; for (i = 0; i < len; i++) { alias_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Import' node")) { goto failed; } res = obj2ast_alias(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Import field \"names\" changed size during iteration"); goto failed; } asdl_seq_SET(names, i, val); } Py_CLEAR(tmp); } *out = _PyAST_Import(names, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->ImportFrom_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { identifier module; asdl_alias_seq* names; int level; if (_PyObject_LookupAttr(obj, state->module, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); module = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'ImportFrom' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &module, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->names, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from ImportFrom"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "ImportFrom field \"names\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); names = _Py_asdl_alias_seq_new(len, arena); if (names == NULL) goto failed; for (i = 0; i < len; i++) { alias_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'ImportFrom' node")) { goto failed; } res = obj2ast_alias(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "ImportFrom field \"names\" changed size during iteration"); goto failed; } asdl_seq_SET(names, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->level, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); level = 0; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'ImportFrom' node")) { goto failed; } res = obj2ast_int(state, tmp, &level, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_ImportFrom(module, names, level, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Global_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_identifier_seq* names; if (_PyObject_LookupAttr(obj, state->names, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Global"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Global field \"names\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); names = _Py_asdl_identifier_seq_new(len, arena); if (names == NULL) goto failed; for (i = 0; i < len; i++) { identifier val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Global' node")) { goto failed; } res = obj2ast_identifier(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Global field \"names\" changed size during iteration"); goto failed; } asdl_seq_SET(names, i, val); } Py_CLEAR(tmp); } *out = _PyAST_Global(names, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Nonlocal_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_identifier_seq* names; if (_PyObject_LookupAttr(obj, state->names, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"names\" missing from Nonlocal"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Nonlocal field \"names\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); names = _Py_asdl_identifier_seq_new(len, arena); if (names == NULL) goto failed; for (i = 0; i < len; i++) { identifier val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Nonlocal' node")) { goto failed; } res = obj2ast_identifier(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Nonlocal field \"names\" changed size during iteration"); goto failed; } asdl_seq_SET(names, i, val); } Py_CLEAR(tmp); } *out = _PyAST_Nonlocal(names, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Expr_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty value; if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Expr"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Expr' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Expr(value, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Pass_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { *out = _PyAST_Pass(lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Break_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { *out = _PyAST_Break(lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Continue_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { *out = _PyAST_Continue(lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } PyErr_Format(PyExc_TypeError, "expected some sort of stmt, but got %R", obj); failed: Py_XDECREF(tmp); return 1; } int obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* arena) { int isinstance; PyObject *tmp = NULL; PyObject *tp; int lineno; int col_offset; int end_lineno; int end_col_offset; if (obj == Py_None) { *out = NULL; return 0; } if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from expr"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'expr' node")) { goto failed; } res = obj2ast_int(state, tmp, &lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from expr"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'expr' node")) { goto failed; } res = obj2ast_int(state, tmp, &col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); end_lineno = lineno; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'expr' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); end_col_offset = col_offset; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'expr' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } tp = state->BoolOp_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { boolop_ty op; asdl_expr_seq* values; if (_PyObject_LookupAttr(obj, state->op, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BoolOp"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'BoolOp' node")) { goto failed; } res = obj2ast_boolop(state, tmp, &op, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->values, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from BoolOp"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "BoolOp field \"values\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); values = _Py_asdl_expr_seq_new(len, arena); if (values == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'BoolOp' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "BoolOp field \"values\" changed size during iteration"); goto failed; } asdl_seq_SET(values, i, val); } Py_CLEAR(tmp); } *out = _PyAST_BoolOp(op, values, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->NamedExpr_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty target; expr_ty value; if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from NamedExpr"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'NamedExpr' node")) { goto failed; } res = obj2ast_expr(state, tmp, &target, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from NamedExpr"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'NamedExpr' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_NamedExpr(target, value, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->BinOp_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty left; operator_ty op; expr_ty right; if (_PyObject_LookupAttr(obj, state->left, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from BinOp"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'BinOp' node")) { goto failed; } res = obj2ast_expr(state, tmp, &left, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->op, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from BinOp"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'BinOp' node")) { goto failed; } res = obj2ast_operator(state, tmp, &op, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->right, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"right\" missing from BinOp"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'BinOp' node")) { goto failed; } res = obj2ast_expr(state, tmp, &right, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_BinOp(left, op, right, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->UnaryOp_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { unaryop_ty op; expr_ty operand; if (_PyObject_LookupAttr(obj, state->op, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"op\" missing from UnaryOp"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'UnaryOp' node")) { goto failed; } res = obj2ast_unaryop(state, tmp, &op, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->operand, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"operand\" missing from UnaryOp"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'UnaryOp' node")) { goto failed; } res = obj2ast_expr(state, tmp, &operand, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_UnaryOp(op, operand, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Lambda_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { arguments_ty args; expr_ty body; if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Lambda"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Lambda' node")) { goto failed; } res = obj2ast_arguments(state, tmp, &args, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from Lambda"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Lambda' node")) { goto failed; } res = obj2ast_expr(state, tmp, &body, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Lambda(args, body, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->IfExp_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty test; expr_ty body; expr_ty orelse; if (_PyObject_LookupAttr(obj, state->test, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"test\" missing from IfExp"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'IfExp' node")) { goto failed; } res = obj2ast_expr(state, tmp, &test, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from IfExp"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'IfExp' node")) { goto failed; } res = obj2ast_expr(state, tmp, &body, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"orelse\" missing from IfExp"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'IfExp' node")) { goto failed; } res = obj2ast_expr(state, tmp, &orelse, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_IfExp(test, body, orelse, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Dict_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_expr_seq* keys; asdl_expr_seq* values; if (_PyObject_LookupAttr(obj, state->keys, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"keys\" missing from Dict"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Dict field \"keys\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); keys = _Py_asdl_expr_seq_new(len, arena); if (keys == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Dict' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Dict field \"keys\" changed size during iteration"); goto failed; } asdl_seq_SET(keys, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->values, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from Dict"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Dict field \"values\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); values = _Py_asdl_expr_seq_new(len, arena); if (values == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Dict' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Dict field \"values\" changed size during iteration"); goto failed; } asdl_seq_SET(values, i, val); } Py_CLEAR(tmp); } *out = _PyAST_Dict(keys, values, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Set_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_expr_seq* elts; if (_PyObject_LookupAttr(obj, state->elts, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Set"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Set field \"elts\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); elts = _Py_asdl_expr_seq_new(len, arena); if (elts == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Set' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Set field \"elts\" changed size during iteration"); goto failed; } asdl_seq_SET(elts, i, val); } Py_CLEAR(tmp); } *out = _PyAST_Set(elts, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->ListComp_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty elt; asdl_comprehension_seq* generators; if (_PyObject_LookupAttr(obj, state->elt, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from ListComp"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'ListComp' node")) { goto failed; } res = obj2ast_expr(state, tmp, &elt, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->generators, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from ListComp"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "ListComp field \"generators\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); generators = _Py_asdl_comprehension_seq_new(len, arena); if (generators == NULL) goto failed; for (i = 0; i < len; i++) { comprehension_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'ListComp' node")) { goto failed; } res = obj2ast_comprehension(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "ListComp field \"generators\" changed size during iteration"); goto failed; } asdl_seq_SET(generators, i, val); } Py_CLEAR(tmp); } *out = _PyAST_ListComp(elt, generators, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->SetComp_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty elt; asdl_comprehension_seq* generators; if (_PyObject_LookupAttr(obj, state->elt, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from SetComp"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'SetComp' node")) { goto failed; } res = obj2ast_expr(state, tmp, &elt, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->generators, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from SetComp"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "SetComp field \"generators\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); generators = _Py_asdl_comprehension_seq_new(len, arena); if (generators == NULL) goto failed; for (i = 0; i < len; i++) { comprehension_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'SetComp' node")) { goto failed; } res = obj2ast_comprehension(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "SetComp field \"generators\" changed size during iteration"); goto failed; } asdl_seq_SET(generators, i, val); } Py_CLEAR(tmp); } *out = _PyAST_SetComp(elt, generators, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->DictComp_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty key; expr_ty value; asdl_comprehension_seq* generators; if (_PyObject_LookupAttr(obj, state->key, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"key\" missing from DictComp"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'DictComp' node")) { goto failed; } res = obj2ast_expr(state, tmp, &key, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from DictComp"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'DictComp' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->generators, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from DictComp"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "DictComp field \"generators\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); generators = _Py_asdl_comprehension_seq_new(len, arena); if (generators == NULL) goto failed; for (i = 0; i < len; i++) { comprehension_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'DictComp' node")) { goto failed; } res = obj2ast_comprehension(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "DictComp field \"generators\" changed size during iteration"); goto failed; } asdl_seq_SET(generators, i, val); } Py_CLEAR(tmp); } *out = _PyAST_DictComp(key, value, generators, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->GeneratorExp_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty elt; asdl_comprehension_seq* generators; if (_PyObject_LookupAttr(obj, state->elt, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"elt\" missing from GeneratorExp"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'GeneratorExp' node")) { goto failed; } res = obj2ast_expr(state, tmp, &elt, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->generators, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"generators\" missing from GeneratorExp"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "GeneratorExp field \"generators\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); generators = _Py_asdl_comprehension_seq_new(len, arena); if (generators == NULL) goto failed; for (i = 0; i < len; i++) { comprehension_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'GeneratorExp' node")) { goto failed; } res = obj2ast_comprehension(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "GeneratorExp field \"generators\" changed size during iteration"); goto failed; } asdl_seq_SET(generators, i, val); } Py_CLEAR(tmp); } *out = _PyAST_GeneratorExp(elt, generators, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Await_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty value; if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Await"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Await' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Await(value, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Yield_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty value; if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); value = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Yield' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Yield(value, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->YieldFrom_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty value; if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from YieldFrom"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'YieldFrom' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_YieldFrom(value, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Compare_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty left; asdl_int_seq* ops; asdl_expr_seq* comparators; if (_PyObject_LookupAttr(obj, state->left, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"left\" missing from Compare"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Compare' node")) { goto failed; } res = obj2ast_expr(state, tmp, &left, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->ops, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"ops\" missing from Compare"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Compare field \"ops\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); ops = _Py_asdl_int_seq_new(len, arena); if (ops == NULL) goto failed; for (i = 0; i < len; i++) { cmpop_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Compare' node")) { goto failed; } res = obj2ast_cmpop(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Compare field \"ops\" changed size during iteration"); goto failed; } asdl_seq_SET(ops, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->comparators, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"comparators\" missing from Compare"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Compare field \"comparators\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); comparators = _Py_asdl_expr_seq_new(len, arena); if (comparators == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Compare' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Compare field \"comparators\" changed size during iteration"); goto failed; } asdl_seq_SET(comparators, i, val); } Py_CLEAR(tmp); } *out = _PyAST_Compare(left, ops, comparators, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Call_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty func; asdl_expr_seq* args; asdl_keyword_seq* keywords; if (_PyObject_LookupAttr(obj, state->func, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"func\" missing from Call"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Call' node")) { goto failed; } res = obj2ast_expr(state, tmp, &func, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from Call"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Call field \"args\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); args = _Py_asdl_expr_seq_new(len, arena); if (args == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Call' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Call field \"args\" changed size during iteration"); goto failed; } asdl_seq_SET(args, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->keywords, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"keywords\" missing from Call"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Call field \"keywords\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); keywords = _Py_asdl_keyword_seq_new(len, arena); if (keywords == NULL) goto failed; for (i = 0; i < len; i++) { keyword_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Call' node")) { goto failed; } res = obj2ast_keyword(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Call field \"keywords\" changed size during iteration"); goto failed; } asdl_seq_SET(keywords, i, val); } Py_CLEAR(tmp); } *out = _PyAST_Call(func, args, keywords, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->FormattedValue_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty value; int conversion; expr_ty format_spec; if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from FormattedValue"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'FormattedValue' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->conversion, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"conversion\" missing from FormattedValue"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'FormattedValue' node")) { goto failed; } res = obj2ast_int(state, tmp, &conversion, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->format_spec, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); format_spec = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'FormattedValue' node")) { goto failed; } res = obj2ast_expr(state, tmp, &format_spec, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_FormattedValue(value, conversion, format_spec, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->JoinedStr_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_expr_seq* values; if (_PyObject_LookupAttr(obj, state->values, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"values\" missing from JoinedStr"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "JoinedStr field \"values\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); values = _Py_asdl_expr_seq_new(len, arena); if (values == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'JoinedStr' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "JoinedStr field \"values\" changed size during iteration"); goto failed; } asdl_seq_SET(values, i, val); } Py_CLEAR(tmp); } *out = _PyAST_JoinedStr(values, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Constant_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { constant value; string kind; if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Constant"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Constant' node")) { goto failed; } res = obj2ast_constant(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->kind, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); kind = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Constant' node")) { goto failed; } res = obj2ast_string(state, tmp, &kind, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Constant(value, kind, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Attribute_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty value; identifier attr; expr_context_ty ctx; if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Attribute"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Attribute' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->attr, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"attr\" missing from Attribute"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Attribute' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &attr, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Attribute"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Attribute' node")) { goto failed; } res = obj2ast_expr_context(state, tmp, &ctx, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Attribute(value, attr, ctx, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Subscript_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty value; expr_ty slice; expr_context_ty ctx; if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Subscript"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Subscript' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->slice, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"slice\" missing from Subscript"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Subscript' node")) { goto failed; } res = obj2ast_expr(state, tmp, &slice, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Subscript"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Subscript' node")) { goto failed; } res = obj2ast_expr_context(state, tmp, &ctx, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Subscript(value, slice, ctx, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Starred_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty value; expr_context_ty ctx; if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Starred"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Starred' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Starred"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Starred' node")) { goto failed; } res = obj2ast_expr_context(state, tmp, &ctx, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Starred(value, ctx, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Name_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { identifier id; expr_context_ty ctx; if (_PyObject_LookupAttr(obj, state->id, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"id\" missing from Name"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Name' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &id, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Name"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Name' node")) { goto failed; } res = obj2ast_expr_context(state, tmp, &ctx, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Name(id, ctx, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->List_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_expr_seq* elts; expr_context_ty ctx; if (_PyObject_LookupAttr(obj, state->elts, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from List"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "List field \"elts\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); elts = _Py_asdl_expr_seq_new(len, arena); if (elts == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'List' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "List field \"elts\" changed size during iteration"); goto failed; } asdl_seq_SET(elts, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from List"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'List' node")) { goto failed; } res = obj2ast_expr_context(state, tmp, &ctx, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_List(elts, ctx, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Tuple_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_expr_seq* elts; expr_context_ty ctx; if (_PyObject_LookupAttr(obj, state->elts, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"elts\" missing from Tuple"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "Tuple field \"elts\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); elts = _Py_asdl_expr_seq_new(len, arena); if (elts == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'Tuple' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "Tuple field \"elts\" changed size during iteration"); goto failed; } asdl_seq_SET(elts, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"ctx\" missing from Tuple"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Tuple' node")) { goto failed; } res = obj2ast_expr_context(state, tmp, &ctx, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Tuple(elts, ctx, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->Slice_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty lower; expr_ty upper; expr_ty step; if (_PyObject_LookupAttr(obj, state->lower, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); lower = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Slice' node")) { goto failed; } res = obj2ast_expr(state, tmp, &lower, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->upper, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); upper = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Slice' node")) { goto failed; } res = obj2ast_expr(state, tmp, &upper, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->step, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); step = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'Slice' node")) { goto failed; } res = obj2ast_expr(state, tmp, &step, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_Slice(lower, upper, step, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } PyErr_Format(PyExc_TypeError, "expected some sort of expr, but got %R", obj); failed: Py_XDECREF(tmp); return 1; } int obj2ast_expr_context(struct ast_state *state, PyObject* obj, expr_context_ty* out, PyArena* arena) { int isinstance; isinstance = PyObject_IsInstance(obj, state->Load_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Load; return 0; } isinstance = PyObject_IsInstance(obj, state->Store_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Store; return 0; } isinstance = PyObject_IsInstance(obj, state->Del_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Del; return 0; } PyErr_Format(PyExc_TypeError, "expected some sort of expr_context, but got %R", obj); return 1; } int obj2ast_boolop(struct ast_state *state, PyObject* obj, boolop_ty* out, PyArena* arena) { int isinstance; isinstance = PyObject_IsInstance(obj, state->And_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = And; return 0; } isinstance = PyObject_IsInstance(obj, state->Or_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Or; return 0; } PyErr_Format(PyExc_TypeError, "expected some sort of boolop, but got %R", obj); return 1; } int obj2ast_operator(struct ast_state *state, PyObject* obj, operator_ty* out, PyArena* arena) { int isinstance; isinstance = PyObject_IsInstance(obj, state->Add_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Add; return 0; } isinstance = PyObject_IsInstance(obj, state->Sub_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Sub; return 0; } isinstance = PyObject_IsInstance(obj, state->Mult_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Mult; return 0; } isinstance = PyObject_IsInstance(obj, state->MatMult_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = MatMult; return 0; } isinstance = PyObject_IsInstance(obj, state->Div_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Div; return 0; } isinstance = PyObject_IsInstance(obj, state->Mod_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Mod; return 0; } isinstance = PyObject_IsInstance(obj, state->Pow_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Pow; return 0; } isinstance = PyObject_IsInstance(obj, state->LShift_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = LShift; return 0; } isinstance = PyObject_IsInstance(obj, state->RShift_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = RShift; return 0; } isinstance = PyObject_IsInstance(obj, state->BitOr_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = BitOr; return 0; } isinstance = PyObject_IsInstance(obj, state->BitXor_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = BitXor; return 0; } isinstance = PyObject_IsInstance(obj, state->BitAnd_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = BitAnd; return 0; } isinstance = PyObject_IsInstance(obj, state->FloorDiv_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = FloorDiv; return 0; } PyErr_Format(PyExc_TypeError, "expected some sort of operator, but got %R", obj); return 1; } int obj2ast_unaryop(struct ast_state *state, PyObject* obj, unaryop_ty* out, PyArena* arena) { int isinstance; isinstance = PyObject_IsInstance(obj, state->Invert_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Invert; return 0; } isinstance = PyObject_IsInstance(obj, state->Not_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Not; return 0; } isinstance = PyObject_IsInstance(obj, state->UAdd_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = UAdd; return 0; } isinstance = PyObject_IsInstance(obj, state->USub_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = USub; return 0; } PyErr_Format(PyExc_TypeError, "expected some sort of unaryop, but got %R", obj); return 1; } int obj2ast_cmpop(struct ast_state *state, PyObject* obj, cmpop_ty* out, PyArena* arena) { int isinstance; isinstance = PyObject_IsInstance(obj, state->Eq_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Eq; return 0; } isinstance = PyObject_IsInstance(obj, state->NotEq_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = NotEq; return 0; } isinstance = PyObject_IsInstance(obj, state->Lt_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Lt; return 0; } isinstance = PyObject_IsInstance(obj, state->LtE_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = LtE; return 0; } isinstance = PyObject_IsInstance(obj, state->Gt_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Gt; return 0; } isinstance = PyObject_IsInstance(obj, state->GtE_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = GtE; return 0; } isinstance = PyObject_IsInstance(obj, state->Is_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = Is; return 0; } isinstance = PyObject_IsInstance(obj, state->IsNot_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = IsNot; return 0; } isinstance = PyObject_IsInstance(obj, state->In_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = In; return 0; } isinstance = PyObject_IsInstance(obj, state->NotIn_type); if (isinstance == -1) { return 1; } if (isinstance) { *out = NotIn; return 0; } PyErr_Format(PyExc_TypeError, "expected some sort of cmpop, but got %R", obj); return 1; } int obj2ast_comprehension(struct ast_state *state, PyObject* obj, comprehension_ty* out, PyArena* arena) { PyObject* tmp = NULL; expr_ty target; expr_ty iter; asdl_expr_seq* ifs; int is_async; if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"target\" missing from comprehension"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'comprehension' node")) { goto failed; } res = obj2ast_expr(state, tmp, &target, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->iter, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"iter\" missing from comprehension"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'comprehension' node")) { goto failed; } res = obj2ast_expr(state, tmp, &iter, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->ifs, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"ifs\" missing from comprehension"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "comprehension field \"ifs\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); ifs = _Py_asdl_expr_seq_new(len, arena); if (ifs == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'comprehension' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "comprehension field \"ifs\" changed size during iteration"); goto failed; } asdl_seq_SET(ifs, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->is_async, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"is_async\" missing from comprehension"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'comprehension' node")) { goto failed; } res = obj2ast_int(state, tmp, &is_async, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_comprehension(target, iter, ifs, is_async, arena); return 0; failed: Py_XDECREF(tmp); return 1; } int obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty* out, PyArena* arena) { int isinstance; PyObject *tmp = NULL; PyObject *tp; int lineno; int col_offset; int end_lineno; int end_col_offset; if (obj == Py_None) { *out = NULL; return 0; } if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from excepthandler"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'excepthandler' node")) { goto failed; } res = obj2ast_int(state, tmp, &lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from excepthandler"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'excepthandler' node")) { goto failed; } res = obj2ast_int(state, tmp, &col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); end_lineno = lineno; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'excepthandler' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); end_col_offset = col_offset; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'excepthandler' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } tp = state->ExceptHandler_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty type; identifier name; asdl_stmt_seq* body; if (_PyObject_LookupAttr(obj, state->type, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); type = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'ExceptHandler' node")) { goto failed; } res = obj2ast_expr(state, tmp, &type, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); name = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'ExceptHandler' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &name, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from ExceptHandler"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "ExceptHandler field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); body = _Py_asdl_stmt_seq_new(len, arena); if (body == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'ExceptHandler' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "ExceptHandler field \"body\" changed size during iteration"); goto failed; } asdl_seq_SET(body, i, val); } Py_CLEAR(tmp); } *out = _PyAST_ExceptHandler(type, name, body, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } PyErr_Format(PyExc_TypeError, "expected some sort of excepthandler, but got %R", obj); failed: Py_XDECREF(tmp); return 1; } int obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, PyArena* arena) { PyObject* tmp = NULL; asdl_arg_seq* posonlyargs; asdl_arg_seq* args; arg_ty vararg; asdl_arg_seq* kwonlyargs; asdl_expr_seq* kw_defaults; arg_ty kwarg; asdl_expr_seq* defaults; if (_PyObject_LookupAttr(obj, state->posonlyargs, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"posonlyargs\" missing from arguments"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "arguments field \"posonlyargs\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); posonlyargs = _Py_asdl_arg_seq_new(len, arena); if (posonlyargs == NULL) goto failed; for (i = 0; i < len; i++) { arg_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'arguments' node")) { goto failed; } res = obj2ast_arg(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "arguments field \"posonlyargs\" changed size during iteration"); goto failed; } asdl_seq_SET(posonlyargs, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"args\" missing from arguments"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "arguments field \"args\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); args = _Py_asdl_arg_seq_new(len, arena); if (args == NULL) goto failed; for (i = 0; i < len; i++) { arg_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'arguments' node")) { goto failed; } res = obj2ast_arg(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "arguments field \"args\" changed size during iteration"); goto failed; } asdl_seq_SET(args, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->vararg, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); vararg = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'arguments' node")) { goto failed; } res = obj2ast_arg(state, tmp, &vararg, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->kwonlyargs, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"kwonlyargs\" missing from arguments"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "arguments field \"kwonlyargs\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); kwonlyargs = _Py_asdl_arg_seq_new(len, arena); if (kwonlyargs == NULL) goto failed; for (i = 0; i < len; i++) { arg_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'arguments' node")) { goto failed; } res = obj2ast_arg(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "arguments field \"kwonlyargs\" changed size during iteration"); goto failed; } asdl_seq_SET(kwonlyargs, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->kw_defaults, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"kw_defaults\" missing from arguments"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "arguments field \"kw_defaults\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); kw_defaults = _Py_asdl_expr_seq_new(len, arena); if (kw_defaults == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'arguments' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "arguments field \"kw_defaults\" changed size during iteration"); goto failed; } asdl_seq_SET(kw_defaults, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->kwarg, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); kwarg = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'arguments' node")) { goto failed; } res = obj2ast_arg(state, tmp, &kwarg, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->defaults, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"defaults\" missing from arguments"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "arguments field \"defaults\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); defaults = _Py_asdl_expr_seq_new(len, arena); if (defaults == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'arguments' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "arguments field \"defaults\" changed size during iteration"); goto failed; } asdl_seq_SET(defaults, i, val); } Py_CLEAR(tmp); } *out = _PyAST_arguments(posonlyargs, args, vararg, kwonlyargs, kw_defaults, kwarg, defaults, arena); return 0; failed: Py_XDECREF(tmp); return 1; } int obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena) { PyObject* tmp = NULL; identifier arg; expr_ty annotation; string type_comment; int lineno; int col_offset; int end_lineno; int end_col_offset; if (_PyObject_LookupAttr(obj, state->arg, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"arg\" missing from arg"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'arg' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &arg, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->annotation, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); annotation = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'arg' node")) { goto failed; } res = obj2ast_expr(state, tmp, &annotation, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); type_comment = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'arg' node")) { goto failed; } res = obj2ast_string(state, tmp, &type_comment, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from arg"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'arg' node")) { goto failed; } res = obj2ast_int(state, tmp, &lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from arg"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'arg' node")) { goto failed; } res = obj2ast_int(state, tmp, &col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); end_lineno = lineno; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'arg' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); end_col_offset = col_offset; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'arg' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_arg(arg, annotation, type_comment, lineno, col_offset, end_lineno, end_col_offset, arena); return 0; failed: Py_XDECREF(tmp); return 1; } int obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out, PyArena* arena) { PyObject* tmp = NULL; identifier arg; expr_ty value; int lineno; int col_offset; int end_lineno; int end_col_offset; if (_PyObject_LookupAttr(obj, state->arg, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); arg = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'keyword' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &arg, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from keyword"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'keyword' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from keyword"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'keyword' node")) { goto failed; } res = obj2ast_int(state, tmp, &lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from keyword"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'keyword' node")) { goto failed; } res = obj2ast_int(state, tmp, &col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); end_lineno = lineno; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'keyword' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); end_col_offset = col_offset; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'keyword' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_keyword(arg, value, lineno, col_offset, end_lineno, end_col_offset, arena); return 0; failed: Py_XDECREF(tmp); return 1; } int obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena* arena) { PyObject* tmp = NULL; identifier name; identifier asname; int lineno; int col_offset; int end_lineno; int end_col_offset; if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from alias"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'alias' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &name, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->asname, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); asname = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'alias' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &asname, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from alias"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'alias' node")) { goto failed; } res = obj2ast_int(state, tmp, &lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from alias"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'alias' node")) { goto failed; } res = obj2ast_int(state, tmp, &col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); end_lineno = lineno; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'alias' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); end_col_offset = col_offset; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'alias' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_alias(name, asname, lineno, col_offset, end_lineno, end_col_offset, arena); return 0; failed: Py_XDECREF(tmp); return 1; } int obj2ast_withitem(struct ast_state *state, PyObject* obj, withitem_ty* out, PyArena* arena) { PyObject* tmp = NULL; expr_ty context_expr; expr_ty optional_vars; if (_PyObject_LookupAttr(obj, state->context_expr, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"context_expr\" missing from withitem"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'withitem' node")) { goto failed; } res = obj2ast_expr(state, tmp, &context_expr, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->optional_vars, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); optional_vars = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'withitem' node")) { goto failed; } res = obj2ast_expr(state, tmp, &optional_vars, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_withitem(context_expr, optional_vars, arena); return 0; failed: Py_XDECREF(tmp); return 1; } int obj2ast_match_case(struct ast_state *state, PyObject* obj, match_case_ty* out, PyArena* arena) { PyObject* tmp = NULL; pattern_ty pattern; expr_ty guard; asdl_stmt_seq* body; if (_PyObject_LookupAttr(obj, state->pattern, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"pattern\" missing from match_case"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'match_case' node")) { goto failed; } res = obj2ast_pattern(state, tmp, &pattern, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->guard, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); guard = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'match_case' node")) { goto failed; } res = obj2ast_expr(state, tmp, &guard, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"body\" missing from match_case"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "match_case field \"body\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); body = _Py_asdl_stmt_seq_new(len, arena); if (body == NULL) goto failed; for (i = 0; i < len; i++) { stmt_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'match_case' node")) { goto failed; } res = obj2ast_stmt(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "match_case field \"body\" changed size during iteration"); goto failed; } asdl_seq_SET(body, i, val); } Py_CLEAR(tmp); } *out = _PyAST_match_case(pattern, guard, body, arena); return 0; failed: Py_XDECREF(tmp); return 1; } int obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, PyArena* arena) { int isinstance; PyObject *tmp = NULL; PyObject *tp; int lineno; int col_offset; int end_lineno; int end_col_offset; if (obj == Py_None) { *out = NULL; return 0; } if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from pattern"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'pattern' node")) { goto failed; } res = obj2ast_int(state, tmp, &lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from pattern"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'pattern' node")) { goto failed; } res = obj2ast_int(state, tmp, &col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"end_lineno\" missing from pattern"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'pattern' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"end_col_offset\" missing from pattern"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'pattern' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } tp = state->MatchValue_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty value; if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from MatchValue"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'MatchValue' node")) { goto failed; } res = obj2ast_expr(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_MatchValue(value, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->MatchSingleton_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { constant value; if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from MatchSingleton"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'MatchSingleton' node")) { goto failed; } res = obj2ast_constant(state, tmp, &value, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_MatchSingleton(value, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->MatchSequence_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_pattern_seq* patterns; if (_PyObject_LookupAttr(obj, state->patterns, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"patterns\" missing from MatchSequence"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "MatchSequence field \"patterns\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); patterns = _Py_asdl_pattern_seq_new(len, arena); if (patterns == NULL) goto failed; for (i = 0; i < len; i++) { pattern_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'MatchSequence' node")) { goto failed; } res = obj2ast_pattern(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "MatchSequence field \"patterns\" changed size during iteration"); goto failed; } asdl_seq_SET(patterns, i, val); } Py_CLEAR(tmp); } *out = _PyAST_MatchSequence(patterns, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->MatchMapping_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_expr_seq* keys; asdl_pattern_seq* patterns; identifier rest; if (_PyObject_LookupAttr(obj, state->keys, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"keys\" missing from MatchMapping"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "MatchMapping field \"keys\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); keys = _Py_asdl_expr_seq_new(len, arena); if (keys == NULL) goto failed; for (i = 0; i < len; i++) { expr_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'MatchMapping' node")) { goto failed; } res = obj2ast_expr(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "MatchMapping field \"keys\" changed size during iteration"); goto failed; } asdl_seq_SET(keys, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->patterns, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"patterns\" missing from MatchMapping"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "MatchMapping field \"patterns\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); patterns = _Py_asdl_pattern_seq_new(len, arena); if (patterns == NULL) goto failed; for (i = 0; i < len; i++) { pattern_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'MatchMapping' node")) { goto failed; } res = obj2ast_pattern(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "MatchMapping field \"patterns\" changed size during iteration"); goto failed; } asdl_seq_SET(patterns, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->rest, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); rest = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'MatchMapping' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &rest, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_MatchMapping(keys, patterns, rest, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->MatchClass_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { expr_ty cls; asdl_pattern_seq* patterns; asdl_identifier_seq* kwd_attrs; asdl_pattern_seq* kwd_patterns; if (_PyObject_LookupAttr(obj, state->cls, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"cls\" missing from MatchClass"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'MatchClass' node")) { goto failed; } res = obj2ast_expr(state, tmp, &cls, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->patterns, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"patterns\" missing from MatchClass"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "MatchClass field \"patterns\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); patterns = _Py_asdl_pattern_seq_new(len, arena); if (patterns == NULL) goto failed; for (i = 0; i < len; i++) { pattern_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'MatchClass' node")) { goto failed; } res = obj2ast_pattern(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "MatchClass field \"patterns\" changed size during iteration"); goto failed; } asdl_seq_SET(patterns, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->kwd_attrs, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"kwd_attrs\" missing from MatchClass"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "MatchClass field \"kwd_attrs\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); kwd_attrs = _Py_asdl_identifier_seq_new(len, arena); if (kwd_attrs == NULL) goto failed; for (i = 0; i < len; i++) { identifier val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'MatchClass' node")) { goto failed; } res = obj2ast_identifier(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "MatchClass field \"kwd_attrs\" changed size during iteration"); goto failed; } asdl_seq_SET(kwd_attrs, i, val); } Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->kwd_patterns, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"kwd_patterns\" missing from MatchClass"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "MatchClass field \"kwd_patterns\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); kwd_patterns = _Py_asdl_pattern_seq_new(len, arena); if (kwd_patterns == NULL) goto failed; for (i = 0; i < len; i++) { pattern_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'MatchClass' node")) { goto failed; } res = obj2ast_pattern(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "MatchClass field \"kwd_patterns\" changed size during iteration"); goto failed; } asdl_seq_SET(kwd_patterns, i, val); } Py_CLEAR(tmp); } *out = _PyAST_MatchClass(cls, patterns, kwd_attrs, kwd_patterns, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->MatchStar_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { identifier name; if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); name = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'MatchStar' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &name, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_MatchStar(name, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->MatchAs_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { pattern_ty pattern; identifier name; if (_PyObject_LookupAttr(obj, state->pattern, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); pattern = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'MatchAs' node")) { goto failed; } res = obj2ast_pattern(state, tmp, &pattern, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); name = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'MatchAs' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &name, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_MatchAs(pattern, name, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->MatchOr_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { asdl_pattern_seq* patterns; if (_PyObject_LookupAttr(obj, state->patterns, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"patterns\" missing from MatchOr"); return 1; } else { int res; Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { PyErr_Format(PyExc_TypeError, "MatchOr field \"patterns\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); patterns = _Py_asdl_pattern_seq_new(len, arena); if (patterns == NULL) goto failed; for (i = 0; i < len; i++) { pattern_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'MatchOr' node")) { goto failed; } res = obj2ast_pattern(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { PyErr_SetString(PyExc_RuntimeError, "MatchOr field \"patterns\" changed size during iteration"); goto failed; } asdl_seq_SET(patterns, i, val); } Py_CLEAR(tmp); } *out = _PyAST_MatchOr(patterns, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } PyErr_Format(PyExc_TypeError, "expected some sort of pattern, but got %R", obj); failed: Py_XDECREF(tmp); return 1; } int obj2ast_type_ignore(struct ast_state *state, PyObject* obj, type_ignore_ty* out, PyArena* arena) { int isinstance; PyObject *tmp = NULL; PyObject *tp; if (obj == Py_None) { *out = NULL; return 0; } tp = state->TypeIgnore_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { int lineno; string tag; if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from TypeIgnore"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'TypeIgnore' node")) { goto failed; } res = obj2ast_int(state, tmp, &lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->tag, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"tag\" missing from TypeIgnore"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'TypeIgnore' node")) { goto failed; } res = obj2ast_string(state, tmp, &tag, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_TypeIgnore(lineno, tag, arena); if (*out == NULL) goto failed; return 0; } PyErr_Format(PyExc_TypeError, "expected some sort of type_ignore, but got %R", obj); failed: Py_XDECREF(tmp); return 1; } int obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out, PyArena* arena) { int isinstance; PyObject *tmp = NULL; PyObject *tp; int lineno; int col_offset; int end_lineno; int end_col_offset; if (obj == Py_None) { *out = NULL; return 0; } if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from type_param"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'type_param' node")) { goto failed; } res = obj2ast_int(state, tmp, &lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from type_param"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'type_param' node")) { goto failed; } res = obj2ast_int(state, tmp, &col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); end_lineno = lineno; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'type_param' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_lineno, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); end_col_offset = col_offset; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'type_param' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_col_offset, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } tp = state->TypeVar_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { identifier name; expr_ty bound; if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from TypeVar"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'TypeVar' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &name, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } if (_PyObject_LookupAttr(obj, state->bound, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { Py_CLEAR(tmp); bound = NULL; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'TypeVar' node")) { goto failed; } res = obj2ast_expr(state, tmp, &bound, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_TypeVar(name, bound, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->ParamSpec_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { identifier name; if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from ParamSpec"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'ParamSpec' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &name, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_ParamSpec(name, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } tp = state->TypeVarTuple_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { return 1; } if (isinstance) { identifier name; if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from TypeVarTuple"); return 1; } else { int res; if (_Py_EnterRecursiveCall(" while traversing 'TypeVarTuple' node")) { goto failed; } res = obj2ast_identifier(state, tmp, &name, arena); _Py_LeaveRecursiveCall(); if (res != 0) goto failed; Py_CLEAR(tmp); } *out = _PyAST_TypeVarTuple(name, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } PyErr_Format(PyExc_TypeError, "expected some sort of type_param, but got %R", obj); failed: Py_XDECREF(tmp); return 1; } static int astmodule_exec(PyObject *m) { struct ast_state *state = get_ast_state(); if (state == NULL) { return -1; } if (PyModule_AddObjectRef(m, "AST", state->AST_type) < 0) { return -1; } if (PyModule_AddIntMacro(m, PyCF_ALLOW_TOP_LEVEL_AWAIT) < 0) { return -1; } if (PyModule_AddIntMacro(m, PyCF_ONLY_AST) < 0) { return -1; } if (PyModule_AddIntMacro(m, PyCF_TYPE_COMMENTS) < 0) { return -1; } if (PyModule_AddObjectRef(m, "mod", state->mod_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Module", state->Module_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Interactive", state->Interactive_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Expression", state->Expression_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "FunctionType", state->FunctionType_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "stmt", state->stmt_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "FunctionDef", state->FunctionDef_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "AsyncFunctionDef", state->AsyncFunctionDef_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "ClassDef", state->ClassDef_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Return", state->Return_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Delete", state->Delete_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Assign", state->Assign_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "TypeAlias", state->TypeAlias_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "AugAssign", state->AugAssign_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "AnnAssign", state->AnnAssign_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "For", state->For_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "AsyncFor", state->AsyncFor_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "While", state->While_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "If", state->If_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "With", state->With_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "AsyncWith", state->AsyncWith_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Match", state->Match_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Raise", state->Raise_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Try", state->Try_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "TryStar", state->TryStar_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Assert", state->Assert_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Import", state->Import_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "ImportFrom", state->ImportFrom_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Global", state->Global_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Nonlocal", state->Nonlocal_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Expr", state->Expr_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Pass", state->Pass_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Break", state->Break_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Continue", state->Continue_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "expr", state->expr_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "BoolOp", state->BoolOp_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "NamedExpr", state->NamedExpr_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "BinOp", state->BinOp_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "UnaryOp", state->UnaryOp_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Lambda", state->Lambda_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "IfExp", state->IfExp_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Dict", state->Dict_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Set", state->Set_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "ListComp", state->ListComp_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "SetComp", state->SetComp_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "DictComp", state->DictComp_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "GeneratorExp", state->GeneratorExp_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Await", state->Await_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Yield", state->Yield_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "YieldFrom", state->YieldFrom_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Compare", state->Compare_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Call", state->Call_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "FormattedValue", state->FormattedValue_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "JoinedStr", state->JoinedStr_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Constant", state->Constant_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Attribute", state->Attribute_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Subscript", state->Subscript_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Starred", state->Starred_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Name", state->Name_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "List", state->List_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Tuple", state->Tuple_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Slice", state->Slice_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "expr_context", state->expr_context_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Load", state->Load_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Store", state->Store_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Del", state->Del_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "boolop", state->boolop_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "And", state->And_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Or", state->Or_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "operator", state->operator_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Add", state->Add_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Sub", state->Sub_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Mult", state->Mult_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "MatMult", state->MatMult_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Div", state->Div_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Mod", state->Mod_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Pow", state->Pow_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "LShift", state->LShift_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "RShift", state->RShift_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "BitOr", state->BitOr_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "BitXor", state->BitXor_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "BitAnd", state->BitAnd_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "FloorDiv", state->FloorDiv_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "unaryop", state->unaryop_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Invert", state->Invert_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Not", state->Not_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "UAdd", state->UAdd_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "USub", state->USub_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "cmpop", state->cmpop_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Eq", state->Eq_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "NotEq", state->NotEq_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Lt", state->Lt_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "LtE", state->LtE_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Gt", state->Gt_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "GtE", state->GtE_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Is", state->Is_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "IsNot", state->IsNot_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "In", state->In_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "NotIn", state->NotIn_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "comprehension", state->comprehension_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "excepthandler", state->excepthandler_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "ExceptHandler", state->ExceptHandler_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "arguments", state->arguments_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "arg", state->arg_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "keyword", state->keyword_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "alias", state->alias_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "withitem", state->withitem_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "match_case", state->match_case_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "pattern", state->pattern_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "MatchValue", state->MatchValue_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "MatchSingleton", state->MatchSingleton_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "MatchSequence", state->MatchSequence_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "MatchMapping", state->MatchMapping_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "MatchClass", state->MatchClass_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "MatchStar", state->MatchStar_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "MatchAs", state->MatchAs_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "MatchOr", state->MatchOr_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "type_ignore", state->type_ignore_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "TypeIgnore", state->TypeIgnore_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "type_param", state->type_param_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "TypeVar", state->TypeVar_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "ParamSpec", state->ParamSpec_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "TypeVarTuple", state->TypeVarTuple_type) < 0) { return -1; } return 0; } static PyModuleDef_Slot astmodule_slots[] = { {Py_mod_exec, astmodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; static struct PyModuleDef _astmodule = { PyModuleDef_HEAD_INIT, .m_name = "_ast", // The _ast module uses a per-interpreter state (PyInterpreterState.ast) .m_size = 0, .m_slots = astmodule_slots, }; PyMODINIT_FUNC PyInit__ast(void) { return PyModuleDef_Init(&_astmodule); } PyObject* PyAST_mod2obj(mod_ty t) { struct ast_state *state = get_ast_state(); if (state == NULL) { return NULL; } int starting_recursion_depth; /* Be careful here to prevent overflow. */ int COMPILER_STACK_FRAME_SCALE = 3; PyThreadState *tstate = _PyThreadState_GET(); if (!tstate) { return 0; } state->recursion_limit = C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE; int recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining; starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE; state->recursion_depth = starting_recursion_depth; PyObject *result = ast2obj_mod(state, t); /* Check that the recursion depth counting balanced correctly */ if (result && state->recursion_depth != starting_recursion_depth) { PyErr_Format(PyExc_SystemError, "AST constructor recursion depth mismatch (before=%d, after=%d)", starting_recursion_depth, state->recursion_depth); return 0; } return result; } /* mode is 0 for "exec", 1 for "eval" and 2 for "single" input */ mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode) { const char * const req_name[] = {"Module", "Expression", "Interactive"}; int isinstance; if (PySys_Audit("compile", "OO", ast, Py_None) < 0) { return NULL; } struct ast_state *state = get_ast_state(); if (state == NULL) { return NULL; } PyObject *req_type[3]; req_type[0] = state->Module_type; req_type[1] = state->Expression_type; req_type[2] = state->Interactive_type; assert(0 <= mode && mode <= 2); isinstance = PyObject_IsInstance(ast, req_type[mode]); if (isinstance == -1) return NULL; if (!isinstance) { PyErr_Format(PyExc_TypeError, "expected %s node, got %.400s", req_name[mode], _PyType_Name(Py_TYPE(ast))); return NULL; } mod_ty res = NULL; if (obj2ast_mod(state, ast, &res, arena) != 0) return NULL; else return res; } int PyAST_Check(PyObject* obj) { struct ast_state *state = get_ast_state(); if (state == NULL) { return -1; } return PyObject_IsInstance(obj, state->AST_type); } ================================================ FILE: Python-Tokenize.c ================================================ #include "Python.h" #include "errcode.h" #include "../Parser/tokenizer.h" #include "../Parser/pegen.h" // _PyPegen_byte_offset_to_character_offset() #include "../Parser/pegen.h" // _PyPegen_byte_offset_to_character_offset() static struct PyModuleDef _tokenizemodule; typedef struct { PyTypeObject *TokenizerIter; } tokenize_state; static tokenize_state * get_tokenize_state(PyObject *module) { return (tokenize_state *)PyModule_GetState(module); } #define _tokenize_get_state_by_type(type) \ get_tokenize_state(PyType_GetModuleByDef(type, &_tokenizemodule)) #include "pycore_runtime.h" #include "clinic/Python-tokenize.c.h" /*[clinic input] module _tokenizer class _tokenizer.tokenizeriter "tokenizeriterobject *" "_tokenize_get_state_by_type(type)->TokenizerIter" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=96d98ee2fef7a8bc]*/ typedef struct { PyObject_HEAD struct tok_state *tok; int done; } tokenizeriterobject; /*[clinic input] @classmethod _tokenizer.tokenizeriter.__new__ as tokenizeriter_new readline: object / * extra_tokens: bool encoding: str(c_default="NULL") = 'utf-8' [clinic start generated code]*/ static PyObject * tokenizeriter_new_impl(PyTypeObject *type, PyObject *readline, int extra_tokens, const char *encoding) /*[clinic end generated code: output=7501a1211683ce16 input=f7dddf8a613ae8bd]*/ { tokenizeriterobject *self = (tokenizeriterobject *)type->tp_alloc(type, 0); if (self == NULL) { return NULL; } PyObject *filename = PyUnicode_FromString(""); if (filename == NULL) { return NULL; } self->tok = _PyTokenizer_FromReadline(readline, encoding, 1, 1); if (self->tok == NULL) { Py_DECREF(filename); return NULL; } self->tok->filename = filename; if (extra_tokens) { self->tok->tok_extra_tokens = 1; } self->done = 0; return (PyObject *)self; } static int _tokenizer_error(struct tok_state *tok) { if (PyErr_Occurred()) { return -1; } const char *msg = NULL; PyObject* errtype = PyExc_SyntaxError; switch (tok->done) { case E_TOKEN: msg = "invalid token"; break; case E_EOF: if (tok->level > 0) { PyErr_Format(PyExc_SyntaxError, "parenthesis '%c' was never closed", tok->parenstack[tok->level-1]); } else { PyErr_SetString(PyExc_SyntaxError, "unexpected EOF while parsing"); } return -1; case E_DEDENT: msg = "unindent does not match any outer indentation level"; errtype = PyExc_IndentationError; break; case E_INTR: if (!PyErr_Occurred()) { PyErr_SetNone(PyExc_KeyboardInterrupt); } return -1; case E_NOMEM: PyErr_NoMemory(); return -1; case E_TABSPACE: errtype = PyExc_TabError; msg = "inconsistent use of tabs and spaces in indentation"; break; case E_TOODEEP: errtype = PyExc_IndentationError; msg = "too many levels of indentation"; break; case E_LINECONT: { msg = "unexpected character after line continuation character"; break; } default: msg = "unknown tokenization error"; } PyObject* errstr = NULL; PyObject* error_line = NULL; PyObject* tmp = NULL; PyObject* value = NULL; int result = 0; Py_ssize_t size = tok->inp - tok->buf; assert(tok->buf[size-1] == '\n'); size -= 1; // Remove the newline character from the end of the line error_line = PyUnicode_DecodeUTF8(tok->buf, size, "replace"); if (!error_line) { result = -1; goto exit; } Py_ssize_t offset = _PyPegen_byte_offset_to_character_offset(error_line, tok->inp - tok->buf); if (offset == -1) { result = -1; goto exit; } tmp = Py_BuildValue("(OnnOOO)", tok->filename, tok->lineno, offset, error_line, Py_None, Py_None); if (!tmp) { result = -1; goto exit; } errstr = PyUnicode_FromString(msg); if (!errstr) { result = -1; goto exit; } value = PyTuple_Pack(2, errstr, tmp); if (!value) { result = -1; goto exit; } PyErr_SetObject(errtype, value); exit: Py_XDECREF(errstr); Py_XDECREF(error_line); Py_XDECREF(tmp); Py_XDECREF(value); return result; } static PyObject * tokenizeriter_next(tokenizeriterobject *it) { PyObject* result = NULL; struct token token; _PyToken_Init(&token); int type = _PyTokenizer_Get(it->tok, &token); if (type == ERRORTOKEN) { if(!PyErr_Occurred()) { _tokenizer_error(it->tok); assert(PyErr_Occurred()); } goto exit; } if (it->done || type == ERRORTOKEN) { PyErr_SetString(PyExc_StopIteration, "EOF"); it->done = 1; goto exit; } PyObject *str = NULL; if (token.start == NULL || token.end == NULL) { str = PyUnicode_FromString(""); } else { str = PyUnicode_FromStringAndSize(token.start, token.end - token.start); } if (str == NULL) { goto exit; } int is_trailing_token = 0; if (type == ENDMARKER || (type == DEDENT && it->tok->done == E_EOF)) { is_trailing_token = 1; } const char *line_start = ISSTRINGLIT(type) ? it->tok->multi_line_start : it->tok->line_start; PyObject* line = NULL; if (it->tok->tok_extra_tokens && is_trailing_token) { line = PyUnicode_FromString(""); } else { Py_ssize_t size = it->tok->inp - line_start; line = PyUnicode_DecodeUTF8(line_start, size, "replace"); } if (line == NULL) { Py_DECREF(str); goto exit; } Py_ssize_t lineno = ISSTRINGLIT(type) ? it->tok->first_lineno : it->tok->lineno; Py_ssize_t end_lineno = it->tok->lineno; Py_ssize_t col_offset = -1; Py_ssize_t end_col_offset = -1; if (token.start != NULL && token.start >= line_start) { col_offset = _PyPegen_byte_offset_to_character_offset(line, token.start - line_start); } if (token.end != NULL && token.end >= it->tok->line_start) { end_col_offset = _PyPegen_byte_offset_to_character_offset(line, token.end - it->tok->line_start); } if (it->tok->tok_extra_tokens) { if (is_trailing_token) { lineno = end_lineno = lineno + 1; col_offset = end_col_offset = 0; } // Necessary adjustments to match the original Python tokenize // implementation if (type > DEDENT && type < OP) { type = OP; } else if (type == ASYNC || type == AWAIT) { type = NAME; } else if (type == NEWLINE) { Py_DECREF(str); if (it->tok->start[0] == '\r') { str = PyUnicode_FromString("\r\n"); } else { str = PyUnicode_FromString("\n"); } end_col_offset++; } } result = Py_BuildValue("(iN(nn)(nn)N)", type, str, lineno, col_offset, end_lineno, end_col_offset, line); exit: _PyToken_Free(&token); if (type == ENDMARKER) { it->done = 1; } return result; } static void tokenizeriter_dealloc(tokenizeriterobject *it) { PyTypeObject *tp = Py_TYPE(it); _PyTokenizer_Free(it->tok); tp->tp_free(it); Py_DECREF(tp); } static PyType_Slot tokenizeriter_slots[] = { {Py_tp_new, tokenizeriter_new}, {Py_tp_dealloc, tokenizeriter_dealloc}, {Py_tp_getattro, PyObject_GenericGetAttr}, {Py_tp_iter, PyObject_SelfIter}, {Py_tp_iternext, tokenizeriter_next}, {0, NULL}, }; static PyType_Spec tokenizeriter_spec = { .name = "_tokenize.TokenizerIter", .basicsize = sizeof(tokenizeriterobject), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE), .slots = tokenizeriter_slots, }; static int tokenizemodule_exec(PyObject *m) { tokenize_state *state = get_tokenize_state(m); if (state == NULL) { return -1; } state->TokenizerIter = (PyTypeObject *)PyType_FromModuleAndSpec(m, &tokenizeriter_spec, NULL); if (state->TokenizerIter == NULL) { return -1; } if (PyModule_AddType(m, state->TokenizerIter) < 0) { return -1; } return 0; } static PyMethodDef tokenize_methods[] = { {NULL, NULL, 0, NULL} /* Sentinel */ }; static PyModuleDef_Slot tokenizemodule_slots[] = { {Py_mod_exec, tokenizemodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; static int tokenizemodule_traverse(PyObject *m, visitproc visit, void *arg) { tokenize_state *state = get_tokenize_state(m); Py_VISIT(state->TokenizerIter); return 0; } static int tokenizemodule_clear(PyObject *m) { tokenize_state *state = get_tokenize_state(m); Py_CLEAR(state->TokenizerIter); return 0; } static void tokenizemodule_free(void *m) { tokenizemodule_clear((PyObject *)m); } static struct PyModuleDef _tokenizemodule = { PyModuleDef_HEAD_INIT, .m_name = "_tokenize", .m_size = sizeof(tokenize_state), .m_slots = tokenizemodule_slots, .m_methods = tokenize_methods, .m_traverse = tokenizemodule_traverse, .m_clear = tokenizemodule_clear, .m_free = tokenizemodule_free, }; PyMODINIT_FUNC PyInit__tokenize(void) { return PyModuleDef_Init(&_tokenizemodule); } ================================================ FILE: PythonRun.c ================================================ /* Top level execution of Python code (including in __main__) */ /* To help control the interfaces between the startup, execution and * shutdown code, the phases are split across separate modules (bootstrap, * pythonrun, shutdown) */ /* TODO: Cull includes following phase split */ #include #include "Python.h" #include "pycore_ast.h" // PyAST_mod2obj #include "pycore_ceval.h" // _Py_EnterRecursiveCall #include "pycore_compile.h" // _PyAST_Compile() #include "pycore_interp.h" // PyInterpreterState.importlib #include "pycore_object.h" // _PyDebug_PrintTotalRefs() #include "pycore_parser.h" // _PyParser_ASTFromString() #include "pycore_pyerrors.h" // _PyErr_GetRaisedException, _Py_Offer_Suggestions #include "pycore_pylifecycle.h" // _Py_UnhandledKeyboardInterrupt #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_sysmodule.h" // _PySys_Audit() #include "pycore_traceback.h" // _PyTraceBack_Print_Indented() #include "errcode.h" // E_EOF #include "marshal.h" // PyMarshal_ReadLongFromFile() #ifdef MS_WINDOWS # include "malloc.h" // alloca() #endif #ifdef MS_WINDOWS # undef BYTE # include "windows.h" #endif #ifdef __cplusplus extern "C" { #endif /* Forward */ static void flush_io(void); static PyObject *run_mod(mod_ty, PyObject *, PyObject *, PyObject *, PyCompilerFlags *, PyArena *); static PyObject *run_pyc_file(FILE *, PyObject *, PyObject *, PyCompilerFlags *); static int PyRun_InteractiveOneObjectEx(FILE *, PyObject *, PyCompilerFlags *); static PyObject* pyrun_file(FILE *fp, PyObject *filename, int start, PyObject *globals, PyObject *locals, int closeit, PyCompilerFlags *flags); int _PyRun_AnyFileObject(FILE *fp, PyObject *filename, int closeit, PyCompilerFlags *flags) { int decref_filename = 0; if (filename == NULL) { filename = PyUnicode_FromString("???"); if (filename == NULL) { PyErr_Print(); return -1; } decref_filename = 1; } int res; if (_Py_FdIsInteractive(fp, filename)) { res = _PyRun_InteractiveLoopObject(fp, filename, flags); if (closeit) { fclose(fp); } } else { res = _PyRun_SimpleFileObject(fp, filename, closeit, flags); } if (decref_filename) { Py_DECREF(filename); } return res; } /* Parse input from a file and execute it */ int PyRun_AnyFileExFlags(FILE *fp, const char *filename, int closeit, PyCompilerFlags *flags) { PyObject *filename_obj; if (filename != NULL) { filename_obj = PyUnicode_DecodeFSDefault(filename); if (filename_obj == NULL) { PyErr_Print(); return -1; } } else { filename_obj = NULL; } int res = _PyRun_AnyFileObject(fp, filename_obj, closeit, flags); Py_XDECREF(filename_obj); return res; } int _PyRun_InteractiveLoopObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags) { PyCompilerFlags local_flags = _PyCompilerFlags_INIT; if (flags == NULL) { flags = &local_flags; } PyThreadState *tstate = _PyThreadState_GET(); PyObject *v = _PySys_GetAttr(tstate, &_Py_ID(ps1)); if (v == NULL) { _PySys_SetAttr(&_Py_ID(ps1), v = PyUnicode_FromString(">>> ")); Py_XDECREF(v); } v = _PySys_GetAttr(tstate, &_Py_ID(ps2)); if (v == NULL) { _PySys_SetAttr(&_Py_ID(ps2), v = PyUnicode_FromString("... ")); Py_XDECREF(v); } #ifdef Py_REF_DEBUG int show_ref_count = _Py_GetConfig()->show_ref_count; #endif int err = 0; int ret; int nomem_count = 0; do { ret = PyRun_InteractiveOneObjectEx(fp, filename, flags); if (ret == -1 && PyErr_Occurred()) { /* Prevent an endless loop after multiple consecutive MemoryErrors * while still allowing an interactive command to fail with a * MemoryError. */ if (PyErr_ExceptionMatches(PyExc_MemoryError)) { if (++nomem_count > 16) { PyErr_Clear(); err = -1; break; } } else { nomem_count = 0; } PyErr_Print(); flush_io(); } else { nomem_count = 0; } #ifdef Py_REF_DEBUG if (show_ref_count) { _PyDebug_PrintTotalRefs(); } #endif } while (ret != E_EOF); return err; } int PyRun_InteractiveLoopFlags(FILE *fp, const char *filename, PyCompilerFlags *flags) { PyObject *filename_obj = PyUnicode_DecodeFSDefault(filename); if (filename_obj == NULL) { PyErr_Print(); return -1; } int err = _PyRun_InteractiveLoopObject(fp, filename_obj, flags); Py_DECREF(filename_obj); return err; } /* A PyRun_InteractiveOneObject() auxiliary function that does not print the * error on failure. */ static int PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename, PyCompilerFlags *flags) { PyObject *m, *d, *v, *w, *oenc = NULL; mod_ty mod; PyArena *arena; const char *ps1 = "", *ps2 = "", *enc = NULL; int errcode = 0; PyThreadState *tstate = _PyThreadState_GET(); if (fp == stdin) { /* Fetch encoding from sys.stdin if possible. */ v = _PySys_GetAttr(tstate, &_Py_ID(stdin)); if (v && v != Py_None) { oenc = PyObject_GetAttr(v, &_Py_ID(encoding)); if (oenc) enc = PyUnicode_AsUTF8(oenc); if (!enc) PyErr_Clear(); } } v = _PySys_GetAttr(tstate, &_Py_ID(ps1)); if (v != NULL) { v = PyObject_Str(v); if (v == NULL) PyErr_Clear(); else if (PyUnicode_Check(v)) { ps1 = PyUnicode_AsUTF8(v); if (ps1 == NULL) { PyErr_Clear(); ps1 = ""; } } } w = _PySys_GetAttr(tstate, &_Py_ID(ps2)); if (w != NULL) { w = PyObject_Str(w); if (w == NULL) PyErr_Clear(); else if (PyUnicode_Check(w)) { ps2 = PyUnicode_AsUTF8(w); if (ps2 == NULL) { PyErr_Clear(); ps2 = ""; } } } arena = _PyArena_New(); if (arena == NULL) { Py_XDECREF(v); Py_XDECREF(w); Py_XDECREF(oenc); return -1; } mod = _PyParser_ASTFromFile(fp, filename, enc, Py_single_input, ps1, ps2, flags, &errcode, arena); Py_XDECREF(v); Py_XDECREF(w); Py_XDECREF(oenc); if (mod == NULL) { _PyArena_Free(arena); if (errcode == E_EOF) { PyErr_Clear(); return E_EOF; } return -1; } m = PyImport_AddModuleObject(&_Py_ID(__main__)); if (m == NULL) { _PyArena_Free(arena); return -1; } d = PyModule_GetDict(m); v = run_mod(mod, filename, d, d, flags, arena); _PyArena_Free(arena); if (v == NULL) { return -1; } Py_DECREF(v); flush_io(); return 0; } int PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags) { int res; res = PyRun_InteractiveOneObjectEx(fp, filename, flags); if (res == -1) { PyErr_Print(); flush_io(); } return res; } int PyRun_InteractiveOneFlags(FILE *fp, const char *filename_str, PyCompilerFlags *flags) { PyObject *filename; int res; filename = PyUnicode_DecodeFSDefault(filename_str); if (filename == NULL) { PyErr_Print(); return -1; } res = PyRun_InteractiveOneObject(fp, filename, flags); Py_DECREF(filename); return res; } /* Check whether a file maybe a pyc file: Look at the extension, the file type, and, if we may close it, at the first few bytes. */ static int maybe_pyc_file(FILE *fp, PyObject *filename, int closeit) { PyObject *ext = PyUnicode_FromString(".pyc"); if (ext == NULL) { return -1; } Py_ssize_t endswith = PyUnicode_Tailmatch(filename, ext, 0, PY_SSIZE_T_MAX, +1); Py_DECREF(ext); if (endswith) { return 1; } /* Only look into the file if we are allowed to close it, since it then should also be seekable. */ if (!closeit) { return 0; } /* Read only two bytes of the magic. If the file was opened in text mode, the bytes 3 and 4 of the magic (\r\n) might not be read as they are on disk. */ unsigned int halfmagic = PyImport_GetMagicNumber() & 0xFFFF; unsigned char buf[2]; /* Mess: In case of -x, the stream is NOT at its start now, and ungetc() was used to push back the first newline, which makes the current stream position formally undefined, and a x-platform nightmare. Unfortunately, we have no direct way to know whether -x was specified. So we use a terrible hack: if the current stream position is not 0, we assume -x was specified, and give up. Bug 132850 on SourceForge spells out the hopelessness of trying anything else (fseek and ftell don't work predictably x-platform for text-mode files). */ int ispyc = 0; if (ftell(fp) == 0) { if (fread(buf, 1, 2, fp) == 2 && ((unsigned int)buf[1]<<8 | buf[0]) == halfmagic) ispyc = 1; rewind(fp); } return ispyc; } static int set_main_loader(PyObject *d, PyObject *filename, const char *loader_name) { PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *loader_type = _PyImport_GetImportlibExternalLoader(interp, loader_name); if (loader_type == NULL) { return -1; } PyObject *loader = PyObject_CallFunction(loader_type, "sO", "__main__", filename); Py_DECREF(loader_type); if (loader == NULL) { return -1; } if (PyDict_SetItemString(d, "__loader__", loader) < 0) { Py_DECREF(loader); return -1; } Py_DECREF(loader); return 0; } int _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit, PyCompilerFlags *flags) { PyObject *m, *d, *v; int set_file_name = 0, ret = -1; m = PyImport_AddModule("__main__"); if (m == NULL) return -1; Py_INCREF(m); d = PyModule_GetDict(m); if (_PyDict_GetItemStringWithError(d, "__file__") == NULL) { if (PyErr_Occurred()) { goto done; } if (PyDict_SetItemString(d, "__file__", filename) < 0) { goto done; } if (PyDict_SetItemString(d, "__cached__", Py_None) < 0) { goto done; } set_file_name = 1; } int pyc = maybe_pyc_file(fp, filename, closeit); if (pyc < 0) { goto done; } if (pyc) { FILE *pyc_fp; /* Try to run a pyc file. First, re-open in binary */ if (closeit) { fclose(fp); } pyc_fp = _Py_fopen_obj(filename, "rb"); if (pyc_fp == NULL) { fprintf(stderr, "python: Can't reopen .pyc file\n"); goto done; } if (set_main_loader(d, filename, "SourcelessFileLoader") < 0) { fprintf(stderr, "python: failed to set __main__.__loader__\n"); ret = -1; fclose(pyc_fp); goto done; } v = run_pyc_file(pyc_fp, d, d, flags); } else { /* When running from stdin, leave __main__.__loader__ alone */ if (PyUnicode_CompareWithASCIIString(filename, "") != 0 && set_main_loader(d, filename, "SourceFileLoader") < 0) { fprintf(stderr, "python: failed to set __main__.__loader__\n"); ret = -1; goto done; } v = pyrun_file(fp, filename, Py_file_input, d, d, closeit, flags); } flush_io(); if (v == NULL) { Py_CLEAR(m); PyErr_Print(); goto done; } Py_DECREF(v); ret = 0; done: if (set_file_name) { if (PyDict_DelItemString(d, "__file__")) { PyErr_Clear(); } if (PyDict_DelItemString(d, "__cached__")) { PyErr_Clear(); } } Py_XDECREF(m); return ret; } int PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, PyCompilerFlags *flags) { PyObject *filename_obj = PyUnicode_DecodeFSDefault(filename); if (filename_obj == NULL) { return -1; } int res = _PyRun_SimpleFileObject(fp, filename_obj, closeit, flags); Py_DECREF(filename_obj); return res; } int PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) { PyObject *m, *d, *v; m = PyImport_AddModule("__main__"); if (m == NULL) return -1; d = PyModule_GetDict(m); v = PyRun_StringFlags(command, Py_file_input, d, d, flags); if (v == NULL) { PyErr_Print(); return -1; } Py_DECREF(v); return 0; } static int parse_syntax_error(PyObject *err, PyObject **message, PyObject **filename, Py_ssize_t *lineno, Py_ssize_t *offset, Py_ssize_t* end_lineno, Py_ssize_t* end_offset, PyObject **text) { Py_ssize_t hold; PyObject *v; *message = NULL; *filename = NULL; /* new style errors. `err' is an instance */ *message = PyObject_GetAttr(err, &_Py_ID(msg)); if (!*message) goto finally; v = PyObject_GetAttr(err, &_Py_ID(filename)); if (!v) goto finally; if (v == Py_None) { Py_DECREF(v); _Py_DECLARE_STR(anon_string, ""); *filename = Py_NewRef(&_Py_STR(anon_string)); } else { *filename = v; } v = PyObject_GetAttr(err, &_Py_ID(lineno)); if (!v) goto finally; hold = PyLong_AsSsize_t(v); Py_DECREF(v); if (hold < 0 && PyErr_Occurred()) goto finally; *lineno = hold; v = PyObject_GetAttr(err, &_Py_ID(offset)); if (!v) goto finally; if (v == Py_None) { *offset = -1; Py_DECREF(v); } else { hold = PyLong_AsSsize_t(v); Py_DECREF(v); if (hold < 0 && PyErr_Occurred()) goto finally; *offset = hold; } if (Py_TYPE(err) == (PyTypeObject*)PyExc_SyntaxError) { v = PyObject_GetAttr(err, &_Py_ID(end_lineno)); if (!v) { PyErr_Clear(); *end_lineno = *lineno; } else if (v == Py_None) { *end_lineno = *lineno; Py_DECREF(v); } else { hold = PyLong_AsSsize_t(v); Py_DECREF(v); if (hold < 0 && PyErr_Occurred()) goto finally; *end_lineno = hold; } v = PyObject_GetAttr(err, &_Py_ID(end_offset)); if (!v) { PyErr_Clear(); *end_offset = -1; } else if (v == Py_None) { *end_offset = -1; Py_DECREF(v); } else { hold = PyLong_AsSsize_t(v); Py_DECREF(v); if (hold < 0 && PyErr_Occurred()) goto finally; *end_offset = hold; } } else { // SyntaxError subclasses *end_lineno = *lineno; *end_offset = -1; } v = PyObject_GetAttr(err, &_Py_ID(text)); if (!v) goto finally; if (v == Py_None) { Py_DECREF(v); *text = NULL; } else { *text = v; } return 1; finally: Py_XDECREF(*message); Py_XDECREF(*filename); return 0; } static int print_error_text(PyObject *f, Py_ssize_t offset, Py_ssize_t end_offset, PyObject *text_obj) { size_t caret_repetitions = (end_offset > 0 && end_offset > offset) ? end_offset - offset : 1; /* Convert text to a char pointer; return if error */ const char *text = PyUnicode_AsUTF8(text_obj); if (text == NULL) { return -1; } /* Convert offset from 1-based to 0-based */ offset--; /* Strip leading whitespace from text, adjusting offset as we go */ while (*text == ' ' || *text == '\t' || *text == '\f') { text++; offset--; } /* Calculate text length excluding trailing newline */ Py_ssize_t len = strlen(text); if (len > 0 && text[len-1] == '\n') { len--; } /* Clip offset to at most len */ if (offset > len) { offset = len; } /* Skip past newlines embedded in text */ for (;;) { const char *nl = strchr(text, '\n'); if (nl == NULL) { break; } Py_ssize_t inl = nl - text; if (inl >= offset) { break; } inl += 1; text += inl; len -= inl; offset -= (int)inl; } /* Print text */ if (PyFile_WriteString(" ", f) < 0) { return -1; } if (PyFile_WriteString(text, f) < 0) { return -1; } /* Make sure there's a newline at the end */ if (text[len] != '\n') { if (PyFile_WriteString("\n", f) < 0) { return -1; } } /* Don't print caret if it points to the left of the text */ if (offset < 0) { return 0; } /* Write caret line */ if (PyFile_WriteString(" ", f) < 0) { return -1; } while (--offset >= 0) { if (PyFile_WriteString(" ", f) < 0) { return -1; } } for (size_t caret_iter=0; caret_iter < caret_repetitions ; caret_iter++) { if (PyFile_WriteString("^", f) < 0) { return -1; } } if (PyFile_WriteString("\n", f) < 0) { return -1; } return 0; } int _Py_HandleSystemExit(int *exitcode_p) { int inspect = _Py_GetConfig()->inspect; if (inspect) { /* Don't exit if -i flag was given. This flag is set to 0 * when entering interactive mode for inspecting. */ return 0; } if (!PyErr_ExceptionMatches(PyExc_SystemExit)) { return 0; } fflush(stdout); int exitcode = 0; PyObject *exc = PyErr_GetRaisedException(); if (exc == NULL) { goto done; } assert(PyExceptionInstance_Check(exc)); /* The error code should be in the `code' attribute. */ PyObject *code = PyObject_GetAttr(exc, &_Py_ID(code)); if (code) { Py_SETREF(exc, code); if (exc == Py_None) { goto done; } } /* If we failed to dig out the 'code' attribute, * just let the else clause below print the error. */ if (PyLong_Check(exc)) { exitcode = (int)PyLong_AsLong(exc); } else { PyThreadState *tstate = _PyThreadState_GET(); PyObject *sys_stderr = _PySys_GetAttr(tstate, &_Py_ID(stderr)); /* We clear the exception here to avoid triggering the assertion * in PyObject_Str that ensures it won't silently lose exception * details. */ PyErr_Clear(); if (sys_stderr != NULL && sys_stderr != Py_None) { PyFile_WriteObject(exc, sys_stderr, Py_PRINT_RAW); } else { PyObject_Print(exc, stderr, Py_PRINT_RAW); fflush(stderr); } PySys_WriteStderr("\n"); exitcode = 1; } done: Py_CLEAR(exc); *exitcode_p = exitcode; return 1; } static void handle_system_exit(void) { int exitcode; if (_Py_HandleSystemExit(&exitcode)) { Py_Exit(exitcode); } } static void _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars) { PyObject *typ = NULL, *tb = NULL; handle_system_exit(); PyObject *exc = _PyErr_GetRaisedException(tstate); if (exc == NULL) { goto done; } assert(PyExceptionInstance_Check(exc)); typ = Py_NewRef(Py_TYPE(exc)); tb = PyException_GetTraceback(exc); if (tb == NULL) { tb = Py_NewRef(Py_None); } if (set_sys_last_vars) { if (_PySys_SetAttr(&_Py_ID(last_exc), exc) < 0) { _PyErr_Clear(tstate); } /* Legacy version: */ if (_PySys_SetAttr(&_Py_ID(last_type), typ) < 0) { _PyErr_Clear(tstate); } if (_PySys_SetAttr(&_Py_ID(last_value), exc) < 0) { _PyErr_Clear(tstate); } if (_PySys_SetAttr(&_Py_ID(last_traceback), tb) < 0) { _PyErr_Clear(tstate); } } PyObject *hook = _PySys_GetAttr(tstate, &_Py_ID(excepthook)); if (_PySys_Audit(tstate, "sys.excepthook", "OOOO", hook ? hook : Py_None, typ, exc, tb) < 0) { if (PyErr_ExceptionMatches(PyExc_RuntimeError)) { PyErr_Clear(); goto done; } _PyErr_WriteUnraisableMsg("in audit hook", NULL); } if (hook) { PyObject* stack[3]; stack[0] = typ; stack[1] = exc; stack[2] = tb; PyObject *result = _PyObject_FastCall(hook, stack, 3); if (result == NULL) { handle_system_exit(); PyObject *exc2 = _PyErr_GetRaisedException(tstate); assert(exc2 && PyExceptionInstance_Check(exc2)); fflush(stdout); PySys_WriteStderr("Error in sys.excepthook:\n"); PyErr_DisplayException(exc2); PySys_WriteStderr("\nOriginal exception was:\n"); PyErr_DisplayException(exc); Py_DECREF(exc2); } else { Py_DECREF(result); } } else { PySys_WriteStderr("sys.excepthook is missing\n"); PyErr_DisplayException(exc); } done: Py_XDECREF(typ); Py_XDECREF(exc); Py_XDECREF(tb); } void _PyErr_Print(PyThreadState *tstate) { _PyErr_PrintEx(tstate, 1); } void PyErr_PrintEx(int set_sys_last_vars) { PyThreadState *tstate = _PyThreadState_GET(); _PyErr_PrintEx(tstate, set_sys_last_vars); } void PyErr_Print(void) { PyErr_PrintEx(1); } struct exception_print_context { PyObject *file; PyObject *seen; // Prevent cycles in recursion int exception_group_depth; // nesting level of current exception group bool need_close; // Need a closing bottom frame int max_group_width; // Maximum number of children of each EG int max_group_depth; // Maximum nesting level of EGs }; #define EXC_MARGIN(ctx) ((ctx)->exception_group_depth ? "| " : "") #define EXC_INDENT(ctx) (2 * (ctx)->exception_group_depth) static int write_indented_margin(struct exception_print_context *ctx, PyObject *f) { return _Py_WriteIndentedMargin(EXC_INDENT(ctx), EXC_MARGIN(ctx), f); } static int print_exception_invalid_type(struct exception_print_context *ctx, PyObject *value) { PyObject *f = ctx->file; if (_Py_WriteIndent(EXC_INDENT(ctx), f) < 0) { return -1; } const char *const msg = "TypeError: print_exception(): Exception expected " "for value, "; if (PyFile_WriteString(msg, f) < 0) { return -1; } if (PyFile_WriteString(Py_TYPE(value)->tp_name, f) < 0) { return -1; } if (PyFile_WriteString(" found\n", f) < 0) { return -1; } return 0; } static int print_exception_traceback(struct exception_print_context *ctx, PyObject *value) { PyObject *f = ctx->file; int err = 0; PyObject *tb = PyException_GetTraceback(value); if (tb && tb != Py_None) { const char *header = EXCEPTION_TB_HEADER; const char *header_margin = EXC_MARGIN(ctx); if (_PyBaseExceptionGroup_Check(value)) { header = EXCEPTION_GROUP_TB_HEADER; if (ctx->exception_group_depth == 1) { header_margin = "+ "; } } err = _PyTraceBack_Print_Indented( tb, EXC_INDENT(ctx), EXC_MARGIN(ctx), header_margin, header, f); } Py_XDECREF(tb); return err; } static int print_exception_file_and_line(struct exception_print_context *ctx, PyObject **value_p) { PyObject *f = ctx->file; PyObject *tmp; int res = _PyObject_LookupAttr(*value_p, &_Py_ID(print_file_and_line), &tmp); if (res <= 0) { if (res < 0) { PyErr_Clear(); } return 0; } Py_DECREF(tmp); PyObject *message, *filename, *text; Py_ssize_t lineno, offset, end_lineno, end_offset; if (!parse_syntax_error(*value_p, &message, &filename, &lineno, &offset, &end_lineno, &end_offset, &text)) { PyErr_Clear(); return 0; } Py_SETREF(*value_p, message); PyObject *line = PyUnicode_FromFormat(" File \"%S\", line %zd\n", filename, lineno); Py_DECREF(filename); if (line == NULL) { goto error; } if (write_indented_margin(ctx, f) < 0) { goto error; } if (PyFile_WriteObject(line, f, Py_PRINT_RAW) < 0) { goto error; } Py_CLEAR(line); if (text != NULL) { Py_ssize_t line_size; const char *error_line = PyUnicode_AsUTF8AndSize(text, &line_size); // If the location of the error spawn multiple lines, we want // to just print the first one and highlight everything until // the end of that one since we don't support multi-line error // messages. if (end_lineno > lineno) { end_offset = (error_line != NULL) ? line_size : -1; } // Limit the amount of '^' that we can display to // the size of the text in the source line. if (error_line != NULL && end_offset > line_size + 1) { end_offset = line_size + 1; } if (print_error_text(f, offset, end_offset, text) < 0) { goto error; } Py_DECREF(text); } assert(!PyErr_Occurred()); return 0; error: Py_XDECREF(line); Py_XDECREF(text); return -1; } /* Prints the message line: module.qualname[: str(exc)] */ static int print_exception_message(struct exception_print_context *ctx, PyObject *type, PyObject *value) { PyObject *f = ctx->file; assert(PyExceptionClass_Check(type)); if (write_indented_margin(ctx, f) < 0) { return -1; } PyObject *modulename = PyObject_GetAttr(type, &_Py_ID(__module__)); if (modulename == NULL || !PyUnicode_Check(modulename)) { Py_XDECREF(modulename); PyErr_Clear(); if (PyFile_WriteString(".", f) < 0) { return -1; } } else { if (!_PyUnicode_Equal(modulename, &_Py_ID(builtins)) && !_PyUnicode_Equal(modulename, &_Py_ID(__main__))) { int res = PyFile_WriteObject(modulename, f, Py_PRINT_RAW); Py_DECREF(modulename); if (res < 0) { return -1; } if (PyFile_WriteString(".", f) < 0) { return -1; } } else { Py_DECREF(modulename); } } PyObject *qualname = PyType_GetQualName((PyTypeObject *)type); if (qualname == NULL || !PyUnicode_Check(qualname)) { Py_XDECREF(qualname); PyErr_Clear(); if (PyFile_WriteString("", f) < 0) { return -1; } } else { int res = PyFile_WriteObject(qualname, f, Py_PRINT_RAW); Py_DECREF(qualname); if (res < 0) { return -1; } } if (Py_IsNone(value)) { return 0; } PyObject *s = PyObject_Str(value); if (s == NULL) { PyErr_Clear(); if (PyFile_WriteString(": ", f) < 0) { return -1; } } else { /* only print colon if the str() of the object is not the empty string */ if (!PyUnicode_Check(s) || PyUnicode_GetLength(s) != 0) { if (PyFile_WriteString(": ", f) < 0) { Py_DECREF(s); return -1; } } int res = PyFile_WriteObject(s, f, Py_PRINT_RAW); Py_DECREF(s); if (res < 0) { return -1; } } return 0; } static int print_exception_suggestions(struct exception_print_context *ctx, PyObject *value) { PyObject *f = ctx->file; PyObject *suggestions = _Py_Offer_Suggestions(value); if (suggestions) { if (PyFile_WriteObject(suggestions, f, Py_PRINT_RAW) < 0) { goto error; } Py_DECREF(suggestions); } else if (PyErr_Occurred()) { PyErr_Clear(); } return 0; error: Py_XDECREF(suggestions); return -1; } static int print_exception_notes(struct exception_print_context *ctx, PyObject *value) { PyObject *f = ctx->file; if (!PyExceptionInstance_Check(value)) { return 0; } if (!PyObject_HasAttr(value, &_Py_ID(__notes__))) { return 0; } PyObject *notes = PyObject_GetAttr(value, &_Py_ID(__notes__)); if (notes == NULL) { return -1; } if (!PySequence_Check(notes) || PyUnicode_Check(notes) || PyBytes_Check(notes)) { int res = 0; if (write_indented_margin(ctx, f) < 0) { res = -1; } PyObject *s = PyObject_Repr(notes); if (s == NULL) { PyErr_Clear(); res = PyFile_WriteString("<__notes__ repr() failed>", f); } else { res = PyFile_WriteObject(s, f, Py_PRINT_RAW); Py_DECREF(s); } Py_DECREF(notes); if (PyFile_WriteString("\n", f) < 0) { res = -1; } return res; } Py_ssize_t num_notes = PySequence_Length(notes); PyObject *lines = NULL; for (Py_ssize_t ni = 0; ni < num_notes; ni++) { PyObject *note = PySequence_GetItem(notes, ni); PyObject *note_str = PyObject_Str(note); Py_DECREF(note); if (note_str == NULL) { PyErr_Clear(); if (PyFile_WriteString("", f) < 0) { goto error; } } else { lines = PyUnicode_Splitlines(note_str, 1); Py_DECREF(note_str); if (lines == NULL) { goto error; } Py_ssize_t n = PyList_GET_SIZE(lines); for (Py_ssize_t i = 0; i < n; i++) { PyObject *line = PyList_GET_ITEM(lines, i); assert(PyUnicode_Check(line)); if (write_indented_margin(ctx, f) < 0) { goto error; } if (PyFile_WriteObject(line, f, Py_PRINT_RAW) < 0) { goto error; } } Py_CLEAR(lines); } if (PyFile_WriteString("\n", f) < 0) { goto error; } } Py_DECREF(notes); return 0; error: Py_XDECREF(lines); Py_DECREF(notes); return -1; } static int print_exception(struct exception_print_context *ctx, PyObject *value) { PyObject *f = ctx->file; if (!PyExceptionInstance_Check(value)) { return print_exception_invalid_type(ctx, value); } Py_INCREF(value); fflush(stdout); if (print_exception_traceback(ctx, value) < 0) { goto error; } /* grab the type now because value can change below */ PyObject *type = (PyObject *) Py_TYPE(value); if (print_exception_file_and_line(ctx, &value) < 0) { goto error; } if (print_exception_message(ctx, type, value) < 0) { goto error; } if (print_exception_suggestions(ctx, value) < 0) { goto error; } if (PyFile_WriteString("\n", f) < 0) { goto error; } if (print_exception_notes(ctx, value) < 0) { goto error; } Py_DECREF(value); assert(!PyErr_Occurred()); return 0; error: Py_DECREF(value); return -1; } static const char cause_message[] = "The above exception was the direct cause " "of the following exception:\n"; static const char context_message[] = "During handling of the above exception, " "another exception occurred:\n"; static int print_exception_recursive(struct exception_print_context*, PyObject*); static int print_chained(struct exception_print_context* ctx, PyObject *value, const char * message, const char *tag) { PyObject *f = ctx->file; if (_Py_EnterRecursiveCall(" in print_chained")) { return -1; } bool need_close = ctx->need_close; int res = print_exception_recursive(ctx, value); ctx->need_close = need_close; _Py_LeaveRecursiveCall(); if (res < 0) { return -1; } if (write_indented_margin(ctx, f) < 0) { return -1; } if (PyFile_WriteString("\n", f) < 0) { return -1; } if (write_indented_margin(ctx, f) < 0) { return -1; } if (PyFile_WriteString(message, f) < 0) { return -1; } if (write_indented_margin(ctx, f) < 0) { return -1; } if (PyFile_WriteString("\n", f) < 0) { return -1; } return 0; } /* Return true if value is in seen or there was a lookup error. * Return false if lookup succeeded and the item was not found. * We suppress errors because this makes us err on the side of * under-printing which is better than over-printing irregular * exceptions (e.g., unhashable ones). */ static bool print_exception_seen_lookup(struct exception_print_context *ctx, PyObject *value) { PyObject *check_id = PyLong_FromVoidPtr(value); if (check_id == NULL) { PyErr_Clear(); return true; } int in_seen = PySet_Contains(ctx->seen, check_id); Py_DECREF(check_id); if (in_seen == -1) { PyErr_Clear(); return true; } if (in_seen == 1) { /* value is in seen */ return true; } return false; } static int print_exception_cause_and_context(struct exception_print_context *ctx, PyObject *value) { PyObject *value_id = PyLong_FromVoidPtr(value); if (value_id == NULL || PySet_Add(ctx->seen, value_id) == -1) { PyErr_Clear(); Py_XDECREF(value_id); return 0; } Py_DECREF(value_id); if (!PyExceptionInstance_Check(value)) { return 0; } PyObject *cause = PyException_GetCause(value); if (cause) { int err = 0; if (!print_exception_seen_lookup(ctx, cause)) { err = print_chained(ctx, cause, cause_message, "cause"); } Py_DECREF(cause); return err; } if (((PyBaseExceptionObject *)value)->suppress_context) { return 0; } PyObject *context = PyException_GetContext(value); if (context) { int err = 0; if (!print_exception_seen_lookup(ctx, context)) { err = print_chained(ctx, context, context_message, "context"); } Py_DECREF(context); return err; } return 0; } static int print_exception_group(struct exception_print_context *ctx, PyObject *value) { PyObject *f = ctx->file; if (ctx->exception_group_depth > ctx->max_group_depth) { /* depth exceeds limit */ if (write_indented_margin(ctx, f) < 0) { return -1; } PyObject *line = PyUnicode_FromFormat("... (max_group_depth is %d)\n", ctx->max_group_depth); if (line == NULL) { return -1; } int err = PyFile_WriteObject(line, f, Py_PRINT_RAW); Py_DECREF(line); return err; } if (ctx->exception_group_depth == 0) { ctx->exception_group_depth += 1; } if (print_exception(ctx, value) < 0) { return -1; } PyObject *excs = ((PyBaseExceptionGroupObject *)value)->excs; assert(excs && PyTuple_Check(excs)); Py_ssize_t num_excs = PyTuple_GET_SIZE(excs); assert(num_excs > 0); Py_ssize_t n; if (num_excs <= ctx->max_group_width) { n = num_excs; } else { n = ctx->max_group_width + 1; } ctx->need_close = false; for (Py_ssize_t i = 0; i < n; i++) { bool last_exc = (i == n - 1); if (last_exc) { // The closing frame may be added in a recursive call ctx->need_close = true; } if (_Py_WriteIndent(EXC_INDENT(ctx), f) < 0) { return -1; } bool truncated = (i >= ctx->max_group_width); PyObject *line; if (!truncated) { line = PyUnicode_FromFormat( "%s+---------------- %zd ----------------\n", (i == 0) ? "+-" : " ", i + 1); } else { line = PyUnicode_FromFormat( "%s+---------------- ... ----------------\n", (i == 0) ? "+-" : " "); } if (line == NULL) { return -1; } int err = PyFile_WriteObject(line, f, Py_PRINT_RAW); Py_DECREF(line); if (err < 0) { return -1; } ctx->exception_group_depth += 1; PyObject *exc = PyTuple_GET_ITEM(excs, i); if (!truncated) { if (_Py_EnterRecursiveCall(" in print_exception_group")) { return -1; } int res = print_exception_recursive(ctx, exc); _Py_LeaveRecursiveCall(); if (res < 0) { return -1; } } else { Py_ssize_t excs_remaining = num_excs - ctx->max_group_width; if (write_indented_margin(ctx, f) < 0) { return -1; } PyObject *line = PyUnicode_FromFormat( "and %zd more exception%s\n", excs_remaining, excs_remaining > 1 ? "s" : ""); if (line == NULL) { return -1; } int err = PyFile_WriteObject(line, f, Py_PRINT_RAW); Py_DECREF(line); if (err < 0) { return -1; } } if (last_exc && ctx->need_close) { if (_Py_WriteIndent(EXC_INDENT(ctx), f) < 0) { return -1; } if (PyFile_WriteString( "+------------------------------------\n", f) < 0) { return -1; } ctx->need_close = false; } ctx->exception_group_depth -= 1; } if (ctx->exception_group_depth == 1) { ctx->exception_group_depth -= 1; } return 0; } static int print_exception_recursive(struct exception_print_context *ctx, PyObject *value) { if (_Py_EnterRecursiveCall(" in print_exception_recursive")) { return -1; } if (ctx->seen != NULL) { /* Exception chaining */ if (print_exception_cause_and_context(ctx, value) < 0) { goto error; } } if (!_PyBaseExceptionGroup_Check(value)) { if (print_exception(ctx, value) < 0) { goto error; } } else if (print_exception_group(ctx, value) < 0) { goto error; } assert(!PyErr_Occurred()); _Py_LeaveRecursiveCall(); return 0; error: _Py_LeaveRecursiveCall(); return -1; } #define PyErr_MAX_GROUP_WIDTH 15 #define PyErr_MAX_GROUP_DEPTH 10 void _PyErr_Display(PyObject *file, PyObject *unused, PyObject *value, PyObject *tb) { assert(file != NULL && file != Py_None); if (PyExceptionInstance_Check(value) && tb != NULL && PyTraceBack_Check(tb)) { /* Put the traceback on the exception, otherwise it won't get displayed. See issue #18776. */ PyObject *cur_tb = PyException_GetTraceback(value); if (cur_tb == NULL) { PyException_SetTraceback(value, tb); } else { Py_DECREF(cur_tb); } } struct exception_print_context ctx; ctx.file = file; ctx.exception_group_depth = 0; ctx.need_close = false; ctx.max_group_width = PyErr_MAX_GROUP_WIDTH; ctx.max_group_depth = PyErr_MAX_GROUP_DEPTH; /* We choose to ignore seen being possibly NULL, and report at least the main exception (it could be a MemoryError). */ ctx.seen = PySet_New(NULL); if (ctx.seen == NULL) { PyErr_Clear(); } if (print_exception_recursive(&ctx, value) < 0) { PyErr_Clear(); _PyObject_Dump(value); fprintf(stderr, "lost sys.stderr\n"); } Py_XDECREF(ctx.seen); /* Call file.flush() */ PyObject *res = _PyObject_CallMethodNoArgs(file, &_Py_ID(flush)); if (!res) { /* Silently ignore file.flush() error */ PyErr_Clear(); } else { Py_DECREF(res); } } void PyErr_Display(PyObject *unused, PyObject *value, PyObject *tb) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *file = _PySys_GetAttr(tstate, &_Py_ID(stderr)); if (file == NULL) { _PyObject_Dump(value); fprintf(stderr, "lost sys.stderr\n"); return; } if (file == Py_None) { return; } Py_INCREF(file); _PyErr_Display(file, NULL, value, tb); Py_DECREF(file); } void _PyErr_DisplayException(PyObject *file, PyObject *exc) { _PyErr_Display(file, NULL, exc, NULL); } void PyErr_DisplayException(PyObject *exc) { PyErr_Display(NULL, exc, NULL); } PyObject * PyRun_StringFlags(const char *str, int start, PyObject *globals, PyObject *locals, PyCompilerFlags *flags) { PyObject *ret = NULL; mod_ty mod; PyArena *arena; arena = _PyArena_New(); if (arena == NULL) return NULL; _Py_DECLARE_STR(anon_string, ""); mod = _PyParser_ASTFromString( str, &_Py_STR(anon_string), start, flags, arena); if (mod != NULL) ret = run_mod(mod, &_Py_STR(anon_string), globals, locals, flags, arena); _PyArena_Free(arena); return ret; } static PyObject * pyrun_file(FILE *fp, PyObject *filename, int start, PyObject *globals, PyObject *locals, int closeit, PyCompilerFlags *flags) { PyArena *arena = _PyArena_New(); if (arena == NULL) { return NULL; } mod_ty mod; mod = _PyParser_ASTFromFile(fp, filename, NULL, start, NULL, NULL, flags, NULL, arena); if (closeit) { fclose(fp); } PyObject *ret; if (mod != NULL) { ret = run_mod(mod, filename, globals, locals, flags, arena); } else { ret = NULL; } _PyArena_Free(arena); return ret; } PyObject * PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals, PyObject *locals, int closeit, PyCompilerFlags *flags) { PyObject *filename_obj = PyUnicode_DecodeFSDefault(filename); if (filename_obj == NULL) { return NULL; } PyObject *res = pyrun_file(fp, filename_obj, start, globals, locals, closeit, flags); Py_DECREF(filename_obj); return res; } static void flush_io_stream(PyThreadState *tstate, PyObject *name) { PyObject *f = _PySys_GetAttr(tstate, name); if (f != NULL) { PyObject *r = _PyObject_CallMethodNoArgs(f, &_Py_ID(flush)); if (r) { Py_DECREF(r); } else { PyErr_Clear(); } } } static void flush_io(void) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *exc = _PyErr_GetRaisedException(tstate); flush_io_stream(tstate, &_Py_ID(stderr)); flush_io_stream(tstate, &_Py_ID(stdout)); _PyErr_SetRaisedException(tstate, exc); } static PyObject * run_eval_code_obj(PyThreadState *tstate, PyCodeObject *co, PyObject *globals, PyObject *locals) { PyObject *v; /* * We explicitly re-initialize _Py_UnhandledKeyboardInterrupt every eval * _just in case_ someone is calling into an embedded Python where they * don't care about an uncaught KeyboardInterrupt exception (why didn't they * leave config.install_signal_handlers set to 0?!?) but then later call * Py_Main() itself (which _checks_ this flag and dies with a signal after * its interpreter exits). We don't want a previous embedded interpreter's * uncaught exception to trigger an unexplained signal exit from a future * Py_Main() based one. */ // XXX Isn't this dealt with by the move to _PyRuntimeState? _PyRuntime.signals.unhandled_keyboard_interrupt = 0; /* Set globals['__builtins__'] if it doesn't exist */ if (globals != NULL && _PyDict_GetItemStringWithError(globals, "__builtins__") == NULL) { if (PyErr_Occurred() || PyDict_SetItemString(globals, "__builtins__", tstate->interp->builtins) < 0) { return NULL; } } v = PyEval_EvalCode((PyObject*)co, globals, locals); if (!v && _PyErr_Occurred(tstate) == PyExc_KeyboardInterrupt) { _PyRuntime.signals.unhandled_keyboard_interrupt = 1; } return v; } static PyObject * run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals, PyCompilerFlags *flags, PyArena *arena) { PyThreadState *tstate = _PyThreadState_GET(); PyCodeObject *co = _PyAST_Compile(mod, filename, flags, -1, arena); if (co == NULL) return NULL; if (_PySys_Audit(tstate, "exec", "O", co) < 0) { Py_DECREF(co); return NULL; } PyObject *v = run_eval_code_obj(tstate, co, globals, locals); Py_DECREF(co); return v; } static PyObject * run_pyc_file(FILE *fp, PyObject *globals, PyObject *locals, PyCompilerFlags *flags) { PyThreadState *tstate = _PyThreadState_GET(); PyCodeObject *co; PyObject *v; long magic; long PyImport_GetMagicNumber(void); magic = PyMarshal_ReadLongFromFile(fp); if (magic != PyImport_GetMagicNumber()) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError, "Bad magic number in .pyc file"); goto error; } /* Skip the rest of the header. */ (void) PyMarshal_ReadLongFromFile(fp); (void) PyMarshal_ReadLongFromFile(fp); (void) PyMarshal_ReadLongFromFile(fp); if (PyErr_Occurred()) { goto error; } v = PyMarshal_ReadLastObjectFromFile(fp); if (v == NULL || !PyCode_Check(v)) { Py_XDECREF(v); PyErr_SetString(PyExc_RuntimeError, "Bad code object in .pyc file"); goto error; } fclose(fp); co = (PyCodeObject *)v; v = run_eval_code_obj(tstate, co, globals, locals); if (v && flags) flags->cf_flags |= (co->co_flags & PyCF_MASK); Py_DECREF(co); return v; error: fclose(fp); return NULL; } PyObject * Py_CompileStringObject(const char *str, PyObject *filename, int start, PyCompilerFlags *flags, int optimize) { PyCodeObject *co; mod_ty mod; PyArena *arena = _PyArena_New(); if (arena == NULL) return NULL; mod = _PyParser_ASTFromString(str, filename, start, flags, arena); if (mod == NULL) { _PyArena_Free(arena); return NULL; } if (flags && (flags->cf_flags & PyCF_ONLY_AST)) { PyObject *result = PyAST_mod2obj(mod); _PyArena_Free(arena); return result; } co = _PyAST_Compile(mod, filename, flags, optimize, arena); _PyArena_Free(arena); return (PyObject *)co; } PyObject * Py_CompileStringExFlags(const char *str, const char *filename_str, int start, PyCompilerFlags *flags, int optimize) { PyObject *filename, *co; filename = PyUnicode_DecodeFSDefault(filename_str); if (filename == NULL) return NULL; co = Py_CompileStringObject(str, filename, start, flags, optimize); Py_DECREF(filename); return co; } const char * _Py_SourceAsString(PyObject *cmd, const char *funcname, const char *what, PyCompilerFlags *cf, PyObject **cmd_copy) { const char *str; Py_ssize_t size; Py_buffer view; *cmd_copy = NULL; if (PyUnicode_Check(cmd)) { cf->cf_flags |= PyCF_IGNORE_COOKIE; str = PyUnicode_AsUTF8AndSize(cmd, &size); if (str == NULL) return NULL; } else if (PyBytes_Check(cmd)) { str = PyBytes_AS_STRING(cmd); size = PyBytes_GET_SIZE(cmd); } else if (PyByteArray_Check(cmd)) { str = PyByteArray_AS_STRING(cmd); size = PyByteArray_GET_SIZE(cmd); } else if (PyObject_GetBuffer(cmd, &view, PyBUF_SIMPLE) == 0) { /* Copy to NUL-terminated buffer. */ *cmd_copy = PyBytes_FromStringAndSize( (const char *)view.buf, view.len); PyBuffer_Release(&view); if (*cmd_copy == NULL) { return NULL; } str = PyBytes_AS_STRING(*cmd_copy); size = PyBytes_GET_SIZE(*cmd_copy); } else { PyErr_Format(PyExc_TypeError, "%s() arg 1 must be a %s object", funcname, what); return NULL; } if (strlen(str) != (size_t)size) { PyErr_SetString(PyExc_SyntaxError, "source code string cannot contain null bytes"); Py_CLEAR(*cmd_copy); return NULL; } return str; } #if defined(USE_STACKCHECK) #if defined(WIN32) && defined(_MSC_VER) /* Stack checking for Microsoft C */ #include #include /* * Return non-zero when we run out of memory on the stack; zero otherwise. */ int PyOS_CheckStack(void) { __try { /* alloca throws a stack overflow exception if there's not enough space left on the stack */ alloca(PYOS_STACK_MARGIN * sizeof(void*)); return 0; } __except (GetExceptionCode() == STATUS_STACK_OVERFLOW ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { int errcode = _resetstkoflw(); if (errcode == 0) { Py_FatalError("Could not reset the stack!"); } } return 1; } #endif /* WIN32 && _MSC_VER */ /* Alternate implementations can be added here... */ #endif /* USE_STACKCHECK */ /* Deprecated C API functions still provided for binary compatibility */ #undef PyRun_AnyFile PyAPI_FUNC(int) PyRun_AnyFile(FILE *fp, const char *name) { return PyRun_AnyFileExFlags(fp, name, 0, NULL); } #undef PyRun_AnyFileEx PyAPI_FUNC(int) PyRun_AnyFileEx(FILE *fp, const char *name, int closeit) { return PyRun_AnyFileExFlags(fp, name, closeit, NULL); } #undef PyRun_AnyFileFlags PyAPI_FUNC(int) PyRun_AnyFileFlags(FILE *fp, const char *name, PyCompilerFlags *flags) { return PyRun_AnyFileExFlags(fp, name, 0, flags); } #undef PyRun_File PyAPI_FUNC(PyObject *) PyRun_File(FILE *fp, const char *p, int s, PyObject *g, PyObject *l) { return PyRun_FileExFlags(fp, p, s, g, l, 0, NULL); } #undef PyRun_FileEx PyAPI_FUNC(PyObject *) PyRun_FileEx(FILE *fp, const char *p, int s, PyObject *g, PyObject *l, int c) { return PyRun_FileExFlags(fp, p, s, g, l, c, NULL); } #undef PyRun_FileFlags PyAPI_FUNC(PyObject *) PyRun_FileFlags(FILE *fp, const char *p, int s, PyObject *g, PyObject *l, PyCompilerFlags *flags) { return PyRun_FileExFlags(fp, p, s, g, l, 0, flags); } #undef PyRun_SimpleFile PyAPI_FUNC(int) PyRun_SimpleFile(FILE *f, const char *p) { return PyRun_SimpleFileExFlags(f, p, 0, NULL); } #undef PyRun_SimpleFileEx PyAPI_FUNC(int) PyRun_SimpleFileEx(FILE *f, const char *p, int c) { return PyRun_SimpleFileExFlags(f, p, c, NULL); } #undef PyRun_String PyAPI_FUNC(PyObject *) PyRun_String(const char *str, int s, PyObject *g, PyObject *l) { return PyRun_StringFlags(str, s, g, l, NULL); } #undef PyRun_SimpleString PyAPI_FUNC(int) PyRun_SimpleString(const char *s) { return PyRun_SimpleStringFlags(s, NULL); } #undef Py_CompileString PyAPI_FUNC(PyObject *) Py_CompileString(const char *str, const char *p, int s) { return Py_CompileStringExFlags(str, p, s, NULL, -1); } #undef Py_CompileStringFlags PyAPI_FUNC(PyObject *) Py_CompileStringFlags(const char *str, const char *p, int s, PyCompilerFlags *flags) { return Py_CompileStringExFlags(str, p, s, flags, -1); } #undef PyRun_InteractiveOne PyAPI_FUNC(int) PyRun_InteractiveOne(FILE *f, const char *p) { return PyRun_InteractiveOneFlags(f, p, NULL); } #undef PyRun_InteractiveLoop PyAPI_FUNC(int) PyRun_InteractiveLoop(FILE *f, const char *p) { return PyRun_InteractiveLoopFlags(f, p, NULL); } #ifdef __cplusplus } #endif ================================================ FILE: Specialize.c ================================================ #include "Python.h" #include "pycore_code.h" #include "pycore_dict.h" #include "pycore_function.h" // _PyFunction_GetVersionForCurrentState() #include "pycore_global_strings.h" // _Py_ID() #include "pycore_long.h" #include "pycore_moduleobject.h" #include "pycore_object.h" #include "pycore_opcode.h" // _PyOpcode_Caches #include "structmember.h" // struct PyMemberDef, T_OFFSET_EX #include "pycore_descrobject.h" #include // rand() /* For guidance on adding or extending families of instructions see * ./adaptive.md */ #ifdef Py_STATS PyStats _py_stats_struct = { 0 }; PyStats *_py_stats = NULL; #define ADD_STAT_TO_DICT(res, field) \ do { \ PyObject *val = PyLong_FromUnsignedLongLong(stats->field); \ if (val == NULL) { \ Py_DECREF(res); \ return NULL; \ } \ if (PyDict_SetItemString(res, #field, val) == -1) { \ Py_DECREF(res); \ Py_DECREF(val); \ return NULL; \ } \ Py_DECREF(val); \ } while(0); static PyObject* stats_to_dict(SpecializationStats *stats) { PyObject *res = PyDict_New(); if (res == NULL) { return NULL; } ADD_STAT_TO_DICT(res, success); ADD_STAT_TO_DICT(res, failure); ADD_STAT_TO_DICT(res, hit); ADD_STAT_TO_DICT(res, deferred); ADD_STAT_TO_DICT(res, miss); ADD_STAT_TO_DICT(res, deopt); PyObject *failure_kinds = PyTuple_New(SPECIALIZATION_FAILURE_KINDS); if (failure_kinds == NULL) { Py_DECREF(res); return NULL; } for (int i = 0; i < SPECIALIZATION_FAILURE_KINDS; i++) { PyObject *stat = PyLong_FromUnsignedLongLong(stats->failure_kinds[i]); if (stat == NULL) { Py_DECREF(res); Py_DECREF(failure_kinds); return NULL; } PyTuple_SET_ITEM(failure_kinds, i, stat); } if (PyDict_SetItemString(res, "failure_kinds", failure_kinds)) { Py_DECREF(res); Py_DECREF(failure_kinds); return NULL; } Py_DECREF(failure_kinds); return res; } #undef ADD_STAT_TO_DICT static int add_stat_dict( PyObject *res, int opcode, const char *name) { SpecializationStats *stats = &_py_stats_struct.opcode_stats[opcode].specialization; PyObject *d = stats_to_dict(stats); if (d == NULL) { return -1; } int err = PyDict_SetItemString(res, name, d); Py_DECREF(d); return err; } #ifdef Py_STATS PyObject* _Py_GetSpecializationStats(void) { PyObject *stats = PyDict_New(); if (stats == NULL) { return NULL; } int err = 0; err += add_stat_dict(stats, LOAD_SUPER_ATTR, "load_super_attr"); err += add_stat_dict(stats, LOAD_ATTR, "load_attr"); err += add_stat_dict(stats, LOAD_GLOBAL, "load_global"); err += add_stat_dict(stats, BINARY_SUBSCR, "binary_subscr"); err += add_stat_dict(stats, STORE_SUBSCR, "store_subscr"); err += add_stat_dict(stats, STORE_ATTR, "store_attr"); err += add_stat_dict(stats, CALL, "call"); err += add_stat_dict(stats, BINARY_OP, "binary_op"); err += add_stat_dict(stats, COMPARE_OP, "compare_op"); err += add_stat_dict(stats, UNPACK_SEQUENCE, "unpack_sequence"); err += add_stat_dict(stats, FOR_ITER, "for_iter"); if (err < 0) { Py_DECREF(stats); return NULL; } return stats; } #endif #define PRINT_STAT(i, field) \ if (stats[i].field) { \ fprintf(out, " opcode[%d]." #field " : %" PRIu64 "\n", i, stats[i].field); \ } static void print_spec_stats(FILE *out, OpcodeStats *stats) { /* Mark some opcodes as specializable for stats, * even though we don't specialize them yet. */ fprintf(out, "opcode[%d].specializable : 1\n", BINARY_SLICE); fprintf(out, "opcode[%d].specializable : 1\n", COMPARE_OP); fprintf(out, "opcode[%d].specializable : 1\n", STORE_SLICE); fprintf(out, "opcode[%d].specializable : 1\n", SEND); for (int i = 0; i < 256; i++) { if (_PyOpcode_Caches[i]) { fprintf(out, "opcode[%d].specializable : 1\n", i); } PRINT_STAT(i, specialization.success); PRINT_STAT(i, specialization.failure); PRINT_STAT(i, specialization.hit); PRINT_STAT(i, specialization.deferred); PRINT_STAT(i, specialization.miss); PRINT_STAT(i, specialization.deopt); PRINT_STAT(i, execution_count); for (int j = 0; j < SPECIALIZATION_FAILURE_KINDS; j++) { uint64_t val = stats[i].specialization.failure_kinds[j]; if (val) { fprintf(out, " opcode[%d].specialization.failure_kinds[%d] : %" PRIu64 "\n", i, j, val); } } for (int j = 0; j < 256; j++) { if (stats[i].pair_count[j]) { fprintf(out, "opcode[%d].pair_count[%d] : %" PRIu64 "\n", i, j, stats[i].pair_count[j]); } } } } #undef PRINT_STAT static void print_call_stats(FILE *out, CallStats *stats) { fprintf(out, "Calls to PyEval_EvalDefault: %" PRIu64 "\n", stats->pyeval_calls); fprintf(out, "Calls to Python functions inlined: %" PRIu64 "\n", stats->inlined_py_calls); fprintf(out, "Frames pushed: %" PRIu64 "\n", stats->frames_pushed); fprintf(out, "Frame objects created: %" PRIu64 "\n", stats->frame_objects_created); for (int i = 0; i < EVAL_CALL_KINDS; i++) { fprintf(out, "Calls via PyEval_EvalFrame[%d] : %" PRIu64 "\n", i, stats->eval_calls[i]); } } static void print_object_stats(FILE *out, ObjectStats *stats) { fprintf(out, "Object allocations from freelist: %" PRIu64 "\n", stats->from_freelist); fprintf(out, "Object frees to freelist: %" PRIu64 "\n", stats->to_freelist); fprintf(out, "Object allocations: %" PRIu64 "\n", stats->allocations); fprintf(out, "Object allocations to 512 bytes: %" PRIu64 "\n", stats->allocations512); fprintf(out, "Object allocations to 4 kbytes: %" PRIu64 "\n", stats->allocations4k); fprintf(out, "Object allocations over 4 kbytes: %" PRIu64 "\n", stats->allocations_big); fprintf(out, "Object frees: %" PRIu64 "\n", stats->frees); fprintf(out, "Object new values: %" PRIu64 "\n", stats->new_values); fprintf(out, "Object interpreter increfs: %" PRIu64 "\n", stats->interpreter_increfs); fprintf(out, "Object interpreter decrefs: %" PRIu64 "\n", stats->interpreter_decrefs); fprintf(out, "Object increfs: %" PRIu64 "\n", stats->increfs); fprintf(out, "Object decrefs: %" PRIu64 "\n", stats->decrefs); fprintf(out, "Object materialize dict (on request): %" PRIu64 "\n", stats->dict_materialized_on_request); fprintf(out, "Object materialize dict (new key): %" PRIu64 "\n", stats->dict_materialized_new_key); fprintf(out, "Object materialize dict (too big): %" PRIu64 "\n", stats->dict_materialized_too_big); fprintf(out, "Object materialize dict (str subclass): %" PRIu64 "\n", stats->dict_materialized_str_subclass); fprintf(out, "Object method cache hits: %" PRIu64 "\n", stats->type_cache_hits); fprintf(out, "Object method cache misses: %" PRIu64 "\n", stats->type_cache_misses); fprintf(out, "Object method cache collisions: %" PRIu64 "\n", stats->type_cache_collisions); fprintf(out, "Object method cache dunder hits: %" PRIu64 "\n", stats->type_cache_dunder_hits); fprintf(out, "Object method cache dunder misses: %" PRIu64 "\n", stats->type_cache_dunder_misses); } static void print_stats(FILE *out, PyStats *stats) { print_spec_stats(out, stats->opcode_stats); print_call_stats(out, &stats->call_stats); print_object_stats(out, &stats->object_stats); } void _Py_StatsClear(void) { _py_stats_struct = (PyStats) { 0 }; } void _Py_PrintSpecializationStats(int to_file) { FILE *out = stderr; if (to_file) { /* Write to a file instead of stderr. */ # ifdef MS_WINDOWS const char *dirname = "c:\\temp\\py_stats\\"; # else const char *dirname = "/tmp/py_stats/"; # endif /* Use random 160 bit number as file name, * to avoid both accidental collisions and * symlink attacks. */ unsigned char rand[20]; char hex_name[41]; _PyOS_URandomNonblock(rand, 20); for (int i = 0; i < 20; i++) { hex_name[2*i] = "0123456789abcdef"[rand[i]&15]; hex_name[2*i+1] = "0123456789abcdef"[(rand[i]>>4)&15]; } hex_name[40] = '\0'; char buf[64]; assert(strlen(dirname) + 40 + strlen(".txt") < 64); sprintf(buf, "%s%s.txt", dirname, hex_name); FILE *fout = fopen(buf, "w"); if (fout) { out = fout; } } else { fprintf(out, "Specialization stats:\n"); } print_stats(out, &_py_stats_struct); if (out != stderr) { fclose(out); } } #ifdef Py_STATS #define SPECIALIZATION_FAIL(opcode, kind) \ do { \ if (_py_stats) { \ _py_stats->opcode_stats[opcode].specialization.failure_kinds[kind]++; \ } \ } while (0) #endif #endif #ifndef SPECIALIZATION_FAIL #define SPECIALIZATION_FAIL(opcode, kind) ((void)0) #endif // Initialize warmup counters and insert superinstructions. This cannot fail. void _PyCode_Quicken(PyCodeObject *code) { #if ENABLE_SPECIALIZATION int opcode = 0; _Py_CODEUNIT *instructions = _PyCode_CODE(code); for (int i = 0; i < Py_SIZE(code); i++) { int previous_opcode = opcode; opcode = _Py_GetBaseOpcode(code, i); assert(opcode < MIN_INSTRUMENTED_OPCODE); int caches = _PyOpcode_Caches[opcode]; if (caches) { instructions[i + 1].cache = adaptive_counter_warmup(); i += caches; continue; } switch (previous_opcode << 8 | opcode) { case LOAD_CONST << 8 | LOAD_FAST: instructions[i - 1].op.code = LOAD_CONST__LOAD_FAST; break; case LOAD_FAST << 8 | LOAD_CONST: instructions[i - 1].op.code = LOAD_FAST__LOAD_CONST; break; case LOAD_FAST << 8 | LOAD_FAST: instructions[i - 1].op.code = LOAD_FAST__LOAD_FAST; break; case STORE_FAST << 8 | LOAD_FAST: instructions[i - 1].op.code = STORE_FAST__LOAD_FAST; break; case STORE_FAST << 8 | STORE_FAST: instructions[i - 1].op.code = STORE_FAST__STORE_FAST; break; } } #endif /* ENABLE_SPECIALIZATION */ } #define SIMPLE_FUNCTION 0 /* Common */ #define SPEC_FAIL_OTHER 0 #define SPEC_FAIL_NO_DICT 1 #define SPEC_FAIL_OVERRIDDEN 2 #define SPEC_FAIL_OUT_OF_VERSIONS 3 #define SPEC_FAIL_OUT_OF_RANGE 4 #define SPEC_FAIL_EXPECTED_ERROR 5 #define SPEC_FAIL_WRONG_NUMBER_ARGUMENTS 6 #define SPEC_FAIL_CODE_COMPLEX_PARAMETERS 7 #define SPEC_FAIL_CODE_NOT_OPTIMIZED 8 #define SPEC_FAIL_LOAD_GLOBAL_NON_DICT 17 #define SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT 18 /* Super */ #define SPEC_FAIL_SUPER_BAD_CLASS 9 #define SPEC_FAIL_SUPER_SHADOWED 10 /* Attributes */ #define SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR 9 #define SPEC_FAIL_ATTR_NON_OVERRIDING_DESCRIPTOR 10 #define SPEC_FAIL_ATTR_NOT_DESCRIPTOR 11 #define SPEC_FAIL_ATTR_METHOD 12 #define SPEC_FAIL_ATTR_MUTABLE_CLASS 13 #define SPEC_FAIL_ATTR_PROPERTY 14 #define SPEC_FAIL_ATTR_NON_OBJECT_SLOT 15 #define SPEC_FAIL_ATTR_READ_ONLY 16 #define SPEC_FAIL_ATTR_AUDITED_SLOT 17 #define SPEC_FAIL_ATTR_NOT_MANAGED_DICT 18 #define SPEC_FAIL_ATTR_NON_STRING_OR_SPLIT 19 #define SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND 20 #define SPEC_FAIL_ATTR_SHADOWED 21 #define SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD 22 #define SPEC_FAIL_ATTR_CLASS_METHOD_OBJ 23 #define SPEC_FAIL_ATTR_OBJECT_SLOT 24 #define SPEC_FAIL_ATTR_HAS_MANAGED_DICT 25 #define SPEC_FAIL_ATTR_INSTANCE_ATTRIBUTE 26 #define SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE 27 #define SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION 28 #define SPEC_FAIL_ATTR_NOT_IN_KEYS 29 #define SPEC_FAIL_ATTR_NOT_IN_DICT 30 #define SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE 31 #define SPEC_FAIL_ATTR_CLASS_ATTR_DESCRIPTOR 32 #define SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD_OBJ 33 /* Binary subscr and store subscr */ #define SPEC_FAIL_SUBSCR_ARRAY_INT 9 #define SPEC_FAIL_SUBSCR_ARRAY_SLICE 10 #define SPEC_FAIL_SUBSCR_LIST_SLICE 11 #define SPEC_FAIL_SUBSCR_TUPLE_SLICE 12 #define SPEC_FAIL_SUBSCR_STRING_INT 13 #define SPEC_FAIL_SUBSCR_STRING_SLICE 14 #define SPEC_FAIL_SUBSCR_BUFFER_INT 15 #define SPEC_FAIL_SUBSCR_BUFFER_SLICE 16 #define SPEC_FAIL_SUBSCR_SEQUENCE_INT 17 /* Store subscr */ #define SPEC_FAIL_SUBSCR_BYTEARRAY_INT 18 #define SPEC_FAIL_SUBSCR_BYTEARRAY_SLICE 19 #define SPEC_FAIL_SUBSCR_PY_SIMPLE 20 #define SPEC_FAIL_SUBSCR_PY_OTHER 21 #define SPEC_FAIL_SUBSCR_DICT_SUBCLASS_NO_OVERRIDE 22 #define SPEC_FAIL_SUBSCR_NOT_HEAP_TYPE 23 /* Binary op */ #define SPEC_FAIL_BINARY_OP_ADD_DIFFERENT_TYPES 9 #define SPEC_FAIL_BINARY_OP_ADD_OTHER 10 #define SPEC_FAIL_BINARY_OP_AND_DIFFERENT_TYPES 11 #define SPEC_FAIL_BINARY_OP_AND_INT 12 #define SPEC_FAIL_BINARY_OP_AND_OTHER 13 #define SPEC_FAIL_BINARY_OP_FLOOR_DIVIDE 14 #define SPEC_FAIL_BINARY_OP_LSHIFT 15 #define SPEC_FAIL_BINARY_OP_MATRIX_MULTIPLY 16 #define SPEC_FAIL_BINARY_OP_MULTIPLY_DIFFERENT_TYPES 17 #define SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER 18 #define SPEC_FAIL_BINARY_OP_OR 19 #define SPEC_FAIL_BINARY_OP_POWER 20 #define SPEC_FAIL_BINARY_OP_REMAINDER 21 #define SPEC_FAIL_BINARY_OP_RSHIFT 22 #define SPEC_FAIL_BINARY_OP_SUBTRACT_DIFFERENT_TYPES 23 #define SPEC_FAIL_BINARY_OP_SUBTRACT_OTHER 24 #define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_DIFFERENT_TYPES 25 #define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT 26 #define SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER 27 #define SPEC_FAIL_BINARY_OP_XOR 28 /* Calls */ #define SPEC_FAIL_CALL_INSTANCE_METHOD 11 #define SPEC_FAIL_CALL_CMETHOD 12 #define SPEC_FAIL_CALL_CFUNC_VARARGS 13 #define SPEC_FAIL_CALL_CFUNC_VARARGS_KEYWORDS 14 #define SPEC_FAIL_CALL_CFUNC_NOARGS 15 #define SPEC_FAIL_CALL_CFUNC_METHOD_FASTCALL_KEYWORDS 16 #define SPEC_FAIL_CALL_METH_DESCR_VARARGS 17 #define SPEC_FAIL_CALL_METH_DESCR_VARARGS_KEYWORDS 18 #define SPEC_FAIL_CALL_METH_DESCR_METHOD_FASTCALL_KEYWORDS 19 #define SPEC_FAIL_CALL_BAD_CALL_FLAGS 20 #define SPEC_FAIL_CALL_PYTHON_CLASS 21 #define SPEC_FAIL_CALL_PEP_523 22 #define SPEC_FAIL_CALL_BOUND_METHOD 23 #define SPEC_FAIL_CALL_STR 24 #define SPEC_FAIL_CALL_CLASS_NO_VECTORCALL 25 #define SPEC_FAIL_CALL_CLASS_MUTABLE 26 #define SPEC_FAIL_CALL_KWNAMES 27 #define SPEC_FAIL_CALL_METHOD_WRAPPER 28 #define SPEC_FAIL_CALL_OPERATOR_WRAPPER 29 /* COMPARE_OP */ #define SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES 12 #define SPEC_FAIL_COMPARE_OP_STRING 13 #define SPEC_FAIL_COMPARE_OP_BIG_INT 14 #define SPEC_FAIL_COMPARE_OP_BYTES 15 #define SPEC_FAIL_COMPARE_OP_TUPLE 16 #define SPEC_FAIL_COMPARE_OP_LIST 17 #define SPEC_FAIL_COMPARE_OP_SET 18 #define SPEC_FAIL_COMPARE_OP_BOOL 19 #define SPEC_FAIL_COMPARE_OP_BASEOBJECT 20 #define SPEC_FAIL_COMPARE_OP_FLOAT_LONG 21 #define SPEC_FAIL_COMPARE_OP_LONG_FLOAT 22 /* FOR_ITER and SEND */ #define SPEC_FAIL_ITER_GENERATOR 10 #define SPEC_FAIL_ITER_COROUTINE 11 #define SPEC_FAIL_ITER_ASYNC_GENERATOR 12 #define SPEC_FAIL_ITER_LIST 13 #define SPEC_FAIL_ITER_TUPLE 14 #define SPEC_FAIL_ITER_SET 15 #define SPEC_FAIL_ITER_STRING 16 #define SPEC_FAIL_ITER_BYTES 17 #define SPEC_FAIL_ITER_RANGE 18 #define SPEC_FAIL_ITER_ITERTOOLS 19 #define SPEC_FAIL_ITER_DICT_KEYS 20 #define SPEC_FAIL_ITER_DICT_ITEMS 21 #define SPEC_FAIL_ITER_DICT_VALUES 22 #define SPEC_FAIL_ITER_ENUMERATE 23 #define SPEC_FAIL_ITER_MAP 24 #define SPEC_FAIL_ITER_ZIP 25 #define SPEC_FAIL_ITER_SEQ_ITER 26 #define SPEC_FAIL_ITER_REVERSED_LIST 27 #define SPEC_FAIL_ITER_CALLABLE 28 #define SPEC_FAIL_ITER_ASCII_STRING 29 #define SPEC_FAIL_ITER_ASYNC_GENERATOR_SEND 30 // UNPACK_SEQUENCE #define SPEC_FAIL_UNPACK_SEQUENCE_ITERATOR 9 #define SPEC_FAIL_UNPACK_SEQUENCE_SEQUENCE 10 static int function_kind(PyCodeObject *code); static bool function_check_args(PyObject *o, int expected_argcount, int opcode); static uint32_t function_get_version(PyObject *o, int opcode); static int specialize_module_load_attr( PyObject *owner, _Py_CODEUNIT *instr, PyObject *name ) { _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); PyModuleObject *m = (PyModuleObject *)owner; assert((owner->ob_type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0); PyDictObject *dict = (PyDictObject *)m->md_dict; if (dict == NULL) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_NO_DICT); return -1; } if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_STRING_OR_SPLIT); return -1; } Py_ssize_t index = _PyDict_LookupIndex(dict, &_Py_ID(__getattr__)); assert(index != DKIX_ERROR); if (index != DKIX_EMPTY) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND); return -1; } index = _PyDict_LookupIndex(dict, name); assert (index != DKIX_ERROR); if (index != (uint16_t)index) { SPECIALIZATION_FAIL(LOAD_ATTR, index == DKIX_EMPTY ? SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND : SPEC_FAIL_OUT_OF_RANGE); return -1; } uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState( _PyInterpreterState_GET(), dict->ma_keys); if (keys_version == 0) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); return -1; } write_u32(cache->version, keys_version); cache->index = (uint16_t)index; instr->op.code = LOAD_ATTR_MODULE; return 0; } /* Attribute specialization */ void _Py_Specialize_LoadSuperAttr(PyObject *global_super, PyObject *cls, _Py_CODEUNIT *instr, int load_method) { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[LOAD_SUPER_ATTR] == INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR); _PySuperAttrCache *cache = (_PySuperAttrCache *)(instr + 1); if (global_super != (PyObject *)&PySuper_Type) { SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_SHADOWED); goto fail; } if (!PyType_Check(cls)) { SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_BAD_CLASS); goto fail; } instr->op.code = load_method ? LOAD_SUPER_ATTR_METHOD : LOAD_SUPER_ATTR_ATTR; goto success; fail: STAT_INC(LOAD_SUPER_ATTR, failure); assert(!PyErr_Occurred()); instr->op.code = LOAD_SUPER_ATTR; cache->counter = adaptive_counter_backoff(cache->counter); return; success: STAT_INC(LOAD_SUPER_ATTR, success); assert(!PyErr_Occurred()); cache->counter = adaptive_counter_cooldown(); } typedef enum { OVERRIDING, /* Is an overriding descriptor, and will remain so. */ METHOD, /* Attribute has Py_TPFLAGS_METHOD_DESCRIPTOR set */ PROPERTY, /* Is a property */ OBJECT_SLOT, /* Is an object slot descriptor */ OTHER_SLOT, /* Is a slot descriptor of another type */ NON_OVERRIDING, /* Is another non-overriding descriptor, and is an instance of an immutable class*/ BUILTIN_CLASSMETHOD, /* Builtin methods with METH_CLASS */ PYTHON_CLASSMETHOD, /* Python classmethod(func) object */ NON_DESCRIPTOR, /* Is not a descriptor, and is an instance of an immutable class */ MUTABLE, /* Instance of a mutable class; might, or might not, be a descriptor */ ABSENT, /* Attribute is not present on the class */ DUNDER_CLASS, /* __class__ attribute */ GETSET_OVERRIDDEN, /* __getattribute__ or __setattr__ has been overridden */ GETATTRIBUTE_IS_PYTHON_FUNCTION /* Descriptor requires calling a Python __getattribute__ */ } DescriptorClassification; static DescriptorClassification analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int store) { bool has_getattr = false; if (store) { if (type->tp_setattro != PyObject_GenericSetAttr) { *descr = NULL; return GETSET_OVERRIDDEN; } } else { getattrofunc getattro_slot = type->tp_getattro; if (getattro_slot == PyObject_GenericGetAttr) { /* Normal attribute lookup; */ has_getattr = false; } else if (getattro_slot == _Py_slot_tp_getattr_hook || getattro_slot == _Py_slot_tp_getattro) { /* One or both of __getattribute__ or __getattr__ may have been overridden See typeobject.c for why these functions are special. */ PyObject *getattribute = _PyType_Lookup(type, &_Py_ID(__getattribute__)); PyInterpreterState *interp = _PyInterpreterState_GET(); bool has_custom_getattribute = getattribute != NULL && getattribute != interp->callable_cache.object__getattribute__; has_getattr = _PyType_Lookup(type, &_Py_ID(__getattr__)) != NULL; if (has_custom_getattribute) { if (getattro_slot == _Py_slot_tp_getattro && !has_getattr && Py_IS_TYPE(getattribute, &PyFunction_Type)) { *descr = getattribute; return GETATTRIBUTE_IS_PYTHON_FUNCTION; } /* Potentially both __getattr__ and __getattribute__ are set. Too complicated */ *descr = NULL; return GETSET_OVERRIDDEN; } /* Potentially has __getattr__ but no custom __getattribute__. Fall through to usual descriptor analysis. Usual attribute lookup should only be allowed at runtime if we can guarantee that there is no way an exception can be raised. This means some specializations, e.g. specializing for property() isn't safe. */ } else { *descr = NULL; return GETSET_OVERRIDDEN; } } PyObject *descriptor = _PyType_Lookup(type, name); *descr = descriptor; if (descriptor == NULL) { return ABSENT; } PyTypeObject *desc_cls = Py_TYPE(descriptor); if (!(desc_cls->tp_flags & Py_TPFLAGS_IMMUTABLETYPE)) { return MUTABLE; } if (desc_cls->tp_descr_set) { if (desc_cls == &PyMemberDescr_Type) { PyMemberDescrObject *member = (PyMemberDescrObject *)descriptor; struct PyMemberDef *dmem = member->d_member; if (dmem->type == T_OBJECT_EX) { return OBJECT_SLOT; } return OTHER_SLOT; } if (desc_cls == &PyProperty_Type) { /* We can't detect at runtime whether an attribute exists with property. So that means we may have to call __getattr__. */ return has_getattr ? GETSET_OVERRIDDEN : PROPERTY; } if (PyUnicode_CompareWithASCIIString(name, "__class__") == 0) { if (descriptor == _PyType_Lookup(&PyBaseObject_Type, name)) { return DUNDER_CLASS; } } if (store) { return OVERRIDING; } } if (desc_cls->tp_descr_get) { if (desc_cls->tp_flags & Py_TPFLAGS_METHOD_DESCRIPTOR) { return METHOD; } if (Py_IS_TYPE(descriptor, &PyClassMethodDescr_Type)) { return BUILTIN_CLASSMETHOD; } if (Py_IS_TYPE(descriptor, &PyClassMethod_Type)) { return PYTHON_CLASSMETHOD; } return NON_OVERRIDING; } return NON_DESCRIPTOR; } static int specialize_dict_access( PyObject *owner, _Py_CODEUNIT *instr, PyTypeObject *type, DescriptorClassification kind, PyObject *name, int base_op, int values_op, int hint_op) { assert(kind == NON_OVERRIDING || kind == NON_DESCRIPTOR || kind == ABSENT || kind == BUILTIN_CLASSMETHOD || kind == PYTHON_CLASSMETHOD); // No descriptor, or non overriding. if ((type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) { SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NOT_MANAGED_DICT); return 0; } _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); if (_PyDictOrValues_IsValues(dorv)) { // Virtual dictionary PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys; assert(PyUnicode_CheckExact(name)); Py_ssize_t index = _PyDictKeys_StringLookup(keys, name); assert (index != DKIX_ERROR); if (index != (uint16_t)index) { SPECIALIZATION_FAIL(base_op, index == DKIX_EMPTY ? SPEC_FAIL_ATTR_NOT_IN_KEYS : SPEC_FAIL_OUT_OF_RANGE); return 0; } write_u32(cache->version, type->tp_version_tag); cache->index = (uint16_t)index; instr->op.code = values_op; } else { PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); if (dict == NULL || !PyDict_CheckExact(dict)) { SPECIALIZATION_FAIL(base_op, SPEC_FAIL_NO_DICT); return 0; } // We found an instance with a __dict__. Py_ssize_t index = _PyDict_LookupIndex(dict, name); if (index != (uint16_t)index) { SPECIALIZATION_FAIL(base_op, index == DKIX_EMPTY ? SPEC_FAIL_ATTR_NOT_IN_DICT : SPEC_FAIL_OUT_OF_RANGE); return 0; } cache->index = (uint16_t)index; write_u32(cache->version, type->tp_version_tag); instr->op.code = hint_op; } return 1; } static int specialize_attr_loadmethod(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name, PyObject* descr, DescriptorClassification kind); static int specialize_class_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name); void _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[LOAD_ATTR] == INLINE_CACHE_ENTRIES_LOAD_ATTR); _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); PyTypeObject *type = Py_TYPE(owner); if (!_PyType_IsReady(type)) { // We *might* not really need this check, but we inherited it from // PyObject_GenericGetAttr and friends... and this way we still do the // right thing if someone forgets to call PyType_Ready(type): SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER); goto fail; } if (PyModule_CheckExact(owner)) { if (specialize_module_load_attr(owner, instr, name)) { goto fail; } goto success; } if (PyType_Check(owner)) { if (specialize_class_load_attr(owner, instr, name)) { goto fail; } goto success; } PyObject *descr = NULL; DescriptorClassification kind = analyze_descriptor(type, name, &descr, 0); assert(descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN); switch(kind) { case OVERRIDING: SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR); goto fail; case METHOD: { int oparg = instr->op.arg; if (oparg & 1) { if (specialize_attr_loadmethod(owner, instr, name, descr, kind)) { goto success; } } else { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD); } goto fail; } case PROPERTY: { _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1); assert(Py_TYPE(descr) == &PyProperty_Type); PyObject *fget = ((_PyPropertyObject *)descr)->prop_get; if (fget == NULL) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR); goto fail; } if (!Py_IS_TYPE(fget, &PyFunction_Type)) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION); goto fail; } if (!function_check_args(fget, 1, LOAD_ATTR)) { goto fail; } uint32_t version = function_get_version(fget, LOAD_ATTR); if (version == 0) { goto fail; } if (_PyInterpreterState_GET()->eval_frame) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER); goto fail; } write_u32(lm_cache->keys_version, version); assert(type->tp_version_tag != 0); write_u32(lm_cache->type_version, type->tp_version_tag); /* borrowed */ write_obj(lm_cache->descr, fget); instr->op.code = LOAD_ATTR_PROPERTY; goto success; } case OBJECT_SLOT: { PyMemberDescrObject *member = (PyMemberDescrObject *)descr; struct PyMemberDef *dmem = member->d_member; Py_ssize_t offset = dmem->offset; if (!PyObject_TypeCheck(owner, member->d_common.d_type)) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR); goto fail; } if (dmem->flags & PY_AUDIT_READ) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_AUDITED_SLOT); goto fail; } if (offset != (uint16_t)offset) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE); goto fail; } assert(dmem->type == T_OBJECT_EX); assert(offset > 0); cache->index = (uint16_t)offset; write_u32(cache->version, type->tp_version_tag); instr->op.code = LOAD_ATTR_SLOT; goto success; } case DUNDER_CLASS: { Py_ssize_t offset = offsetof(PyObject, ob_type); assert(offset == (uint16_t)offset); cache->index = (uint16_t)offset; write_u32(cache->version, type->tp_version_tag); instr->op.code = LOAD_ATTR_SLOT; goto success; } case OTHER_SLOT: SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_OBJECT_SLOT); goto fail; case MUTABLE: SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS); goto fail; case GETSET_OVERRIDDEN: SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OVERRIDDEN); goto fail; case GETATTRIBUTE_IS_PYTHON_FUNCTION: { assert(type->tp_getattro == _Py_slot_tp_getattro); assert(Py_IS_TYPE(descr, &PyFunction_Type)); _PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1); if (!function_check_args(descr, 2, LOAD_ATTR)) { goto fail; } uint32_t version = function_get_version(descr, LOAD_ATTR); if (version == 0) { goto fail; } if (_PyInterpreterState_GET()->eval_frame) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER); goto fail; } write_u32(lm_cache->keys_version, version); /* borrowed */ write_obj(lm_cache->descr, descr); write_u32(lm_cache->type_version, type->tp_version_tag); instr->op.code = LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN; goto success; } case BUILTIN_CLASSMETHOD: SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD_OBJ); goto fail; case PYTHON_CLASSMETHOD: SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_CLASS_METHOD_OBJ); goto fail; case NON_OVERRIDING: SPECIALIZATION_FAIL(LOAD_ATTR, (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) ? SPEC_FAIL_ATTR_CLASS_ATTR_DESCRIPTOR : SPEC_FAIL_ATTR_NOT_MANAGED_DICT); goto fail; case NON_DESCRIPTOR: SPECIALIZATION_FAIL(LOAD_ATTR, (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) ? SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE : SPEC_FAIL_ATTR_NOT_MANAGED_DICT); goto fail; case ABSENT: if (specialize_dict_access(owner, instr, type, kind, name, LOAD_ATTR, LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_WITH_HINT)) { goto success; } } fail: STAT_INC(LOAD_ATTR, failure); assert(!PyErr_Occurred()); instr->op.code = LOAD_ATTR; cache->counter = adaptive_counter_backoff(cache->counter); return; success: STAT_INC(LOAD_ATTR, success); assert(!PyErr_Occurred()); cache->counter = adaptive_counter_cooldown(); } void _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[STORE_ATTR] == INLINE_CACHE_ENTRIES_STORE_ATTR); _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); PyTypeObject *type = Py_TYPE(owner); if (!_PyType_IsReady(type)) { // We *might* not really need this check, but we inherited it from // PyObject_GenericSetAttr and friends... and this way we still do the // right thing if someone forgets to call PyType_Ready(type): SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OTHER); goto fail; } if (PyModule_CheckExact(owner)) { SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OVERRIDDEN); goto fail; } PyObject *descr; DescriptorClassification kind = analyze_descriptor(type, name, &descr, 1); switch(kind) { case OVERRIDING: SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR); goto fail; case METHOD: SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_METHOD); goto fail; case PROPERTY: SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_PROPERTY); goto fail; case OBJECT_SLOT: { PyMemberDescrObject *member = (PyMemberDescrObject *)descr; struct PyMemberDef *dmem = member->d_member; Py_ssize_t offset = dmem->offset; if (!PyObject_TypeCheck(owner, member->d_common.d_type)) { SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_EXPECTED_ERROR); goto fail; } if (dmem->flags & READONLY) { SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_READ_ONLY); goto fail; } if (offset != (uint16_t)offset) { SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OUT_OF_RANGE); goto fail; } assert(dmem->type == T_OBJECT_EX); assert(offset > 0); cache->index = (uint16_t)offset; write_u32(cache->version, type->tp_version_tag); instr->op.code = STORE_ATTR_SLOT; goto success; } case DUNDER_CLASS: case OTHER_SLOT: SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_NON_OBJECT_SLOT); goto fail; case MUTABLE: SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS); goto fail; case GETATTRIBUTE_IS_PYTHON_FUNCTION: case GETSET_OVERRIDDEN: SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OVERRIDDEN); goto fail; case BUILTIN_CLASSMETHOD: SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD_OBJ); goto fail; case PYTHON_CLASSMETHOD: SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_CLASS_METHOD_OBJ); goto fail; case NON_OVERRIDING: SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_CLASS_ATTR_DESCRIPTOR); goto fail; case NON_DESCRIPTOR: SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE); goto fail; case ABSENT: if (specialize_dict_access(owner, instr, type, kind, name, STORE_ATTR, STORE_ATTR_INSTANCE_VALUE, STORE_ATTR_WITH_HINT)) { goto success; } } fail: STAT_INC(STORE_ATTR, failure); assert(!PyErr_Occurred()); instr->op.code = STORE_ATTR; cache->counter = adaptive_counter_backoff(cache->counter); return; success: STAT_INC(STORE_ATTR, success); assert(!PyErr_Occurred()); cache->counter = adaptive_counter_cooldown(); } #ifdef Py_STATS static int load_attr_fail_kind(DescriptorClassification kind) { switch (kind) { case OVERRIDING: return SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR; case METHOD: return SPEC_FAIL_ATTR_METHOD; case PROPERTY: return SPEC_FAIL_ATTR_PROPERTY; case OBJECT_SLOT: return SPEC_FAIL_ATTR_OBJECT_SLOT; case OTHER_SLOT: return SPEC_FAIL_ATTR_NON_OBJECT_SLOT; case DUNDER_CLASS: return SPEC_FAIL_OTHER; case MUTABLE: return SPEC_FAIL_ATTR_MUTABLE_CLASS; case GETSET_OVERRIDDEN: case GETATTRIBUTE_IS_PYTHON_FUNCTION: return SPEC_FAIL_OVERRIDDEN; case BUILTIN_CLASSMETHOD: return SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD; case PYTHON_CLASSMETHOD: return SPEC_FAIL_ATTR_CLASS_METHOD_OBJ; case NON_OVERRIDING: return SPEC_FAIL_ATTR_NON_OVERRIDING_DESCRIPTOR; case NON_DESCRIPTOR: return SPEC_FAIL_ATTR_NOT_DESCRIPTOR; case ABSENT: return SPEC_FAIL_ATTR_INSTANCE_ATTRIBUTE; } Py_UNREACHABLE(); } #endif static int specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) { _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1); if (!PyType_CheckExact(owner) || _PyType_Lookup(Py_TYPE(owner), name)) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE); return -1; } PyObject *descr = NULL; DescriptorClassification kind = 0; kind = analyze_descriptor((PyTypeObject *)owner, name, &descr, 0); switch (kind) { case METHOD: case NON_DESCRIPTOR: write_u32(cache->type_version, ((PyTypeObject *)owner)->tp_version_tag); write_obj(cache->descr, descr); instr->op.code = LOAD_ATTR_CLASS; return 0; #ifdef Py_STATS case ABSENT: SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR); return -1; #endif default: SPECIALIZATION_FAIL(LOAD_ATTR, load_attr_fail_kind(kind)); return -1; } } // Please collect stats carefully before and after modifying. A subtle change // can cause a significant drop in cache hits. A possible test is // python.exe -m test_typing test_re test_dis test_zlib. static int specialize_attr_loadmethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, PyObject *descr, DescriptorClassification kind) { _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1); PyTypeObject *owner_cls = Py_TYPE(owner); assert(kind == METHOD && descr != NULL); if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) { PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); PyDictKeysObject *keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys; if (!_PyDictOrValues_IsValues(dorv)) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_HAS_MANAGED_DICT); return 0; } Py_ssize_t index = _PyDictKeys_StringLookup(keys, name); if (index != DKIX_EMPTY) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_SHADOWED); return 0; } uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState( _PyInterpreterState_GET(), keys); if (keys_version == 0) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); return 0; } write_u32(cache->keys_version, keys_version); instr->op.code = LOAD_ATTR_METHOD_WITH_VALUES; } else { Py_ssize_t dictoffset = owner_cls->tp_dictoffset; if (dictoffset < 0 || dictoffset > INT16_MAX) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE); return 0; } if (dictoffset == 0) { instr->op.code = LOAD_ATTR_METHOD_NO_DICT; } else { PyObject *dict = *(PyObject **) ((char *)owner + dictoffset); if (dict) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NOT_MANAGED_DICT); return 0; } assert(owner_cls->tp_dictoffset > 0); assert(owner_cls->tp_dictoffset <= INT16_MAX); instr->op.code = LOAD_ATTR_METHOD_LAZY_DICT; } } /* `descr` is borrowed. This is safe for methods (even inherited ones from * super classes!) as long as tp_version_tag is validated for two main reasons: * * 1. The class will always hold a reference to the method so it will * usually not be GC-ed. Should it be deleted in Python, e.g. * `del obj.meth`, tp_version_tag will be invalidated, because of reason 2. * * 2. The pre-existing type method cache (MCACHE) uses the same principles * of caching a borrowed descriptor. The MCACHE infrastructure does all the * heavy lifting for us. E.g. it invalidates tp_version_tag on any MRO * modification, on any type object change along said MRO, etc. (see * PyType_Modified usages in typeobject.c). The MCACHE has been * working since Python 2.6 and it's battle-tested. */ write_u32(cache->type_version, owner_cls->tp_version_tag); write_obj(cache->descr, descr); return 1; } void _Py_Specialize_LoadGlobal( PyObject *globals, PyObject *builtins, _Py_CODEUNIT *instr, PyObject *name) { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[LOAD_GLOBAL] == INLINE_CACHE_ENTRIES_LOAD_GLOBAL); /* Use inline cache */ _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)(instr + 1); assert(PyUnicode_CheckExact(name)); if (!PyDict_CheckExact(globals)) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_DICT); goto fail; } PyDictKeysObject * globals_keys = ((PyDictObject *)globals)->ma_keys; if (!DK_IS_UNICODE(globals_keys)) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT); goto fail; } Py_ssize_t index = _PyDictKeys_StringLookup(globals_keys, name); if (index == DKIX_ERROR) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_EXPECTED_ERROR); goto fail; } PyInterpreterState *interp = _PyInterpreterState_GET(); if (index != DKIX_EMPTY) { if (index != (uint16_t)index) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE); goto fail; } uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState( interp, globals_keys); if (keys_version == 0) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; } if (keys_version != (uint16_t)keys_version) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE); goto fail; } cache->index = (uint16_t)index; cache->module_keys_version = (uint16_t)keys_version; instr->op.code = LOAD_GLOBAL_MODULE; goto success; } if (!PyDict_CheckExact(builtins)) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_DICT); goto fail; } PyDictKeysObject * builtin_keys = ((PyDictObject *)builtins)->ma_keys; if (!DK_IS_UNICODE(builtin_keys)) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT); goto fail; } index = _PyDictKeys_StringLookup(builtin_keys, name); if (index == DKIX_ERROR) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_EXPECTED_ERROR); goto fail; } if (index != (uint16_t)index) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE); goto fail; } uint32_t globals_version = _PyDictKeys_GetVersionForCurrentState( interp, globals_keys); if (globals_version == 0) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; } if (globals_version != (uint16_t)globals_version) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE); goto fail; } uint32_t builtins_version = _PyDictKeys_GetVersionForCurrentState( interp, builtin_keys); if (builtins_version == 0) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; } if (builtins_version > UINT16_MAX) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE); goto fail; } cache->index = (uint16_t)index; cache->module_keys_version = (uint16_t)globals_version; cache->builtin_keys_version = (uint16_t)builtins_version; instr->op.code = LOAD_GLOBAL_BUILTIN; goto success; fail: STAT_INC(LOAD_GLOBAL, failure); assert(!PyErr_Occurred()); instr->op.code = LOAD_GLOBAL; cache->counter = adaptive_counter_backoff(cache->counter); return; success: STAT_INC(LOAD_GLOBAL, success); assert(!PyErr_Occurred()); cache->counter = adaptive_counter_cooldown(); } #ifdef Py_STATS static int binary_subscr_fail_kind(PyTypeObject *container_type, PyObject *sub) { if (container_type == &PyUnicode_Type) { if (PyLong_CheckExact(sub)) { return SPEC_FAIL_SUBSCR_STRING_INT; } if (PySlice_Check(sub)) { return SPEC_FAIL_SUBSCR_STRING_SLICE; } return SPEC_FAIL_OTHER; } else if (strcmp(container_type->tp_name, "array.array") == 0) { if (PyLong_CheckExact(sub)) { return SPEC_FAIL_SUBSCR_ARRAY_INT; } if (PySlice_Check(sub)) { return SPEC_FAIL_SUBSCR_ARRAY_SLICE; } return SPEC_FAIL_OTHER; } else if (container_type->tp_as_buffer) { if (PyLong_CheckExact(sub)) { return SPEC_FAIL_SUBSCR_BUFFER_INT; } if (PySlice_Check(sub)) { return SPEC_FAIL_SUBSCR_BUFFER_SLICE; } return SPEC_FAIL_OTHER; } else if (container_type->tp_as_sequence) { if (PyLong_CheckExact(sub) && container_type->tp_as_sequence->sq_item) { return SPEC_FAIL_SUBSCR_SEQUENCE_INT; } } return SPEC_FAIL_OTHER; } #endif static int function_kind(PyCodeObject *code) { int flags = code->co_flags; if ((flags & (CO_VARKEYWORDS | CO_VARARGS)) || code->co_kwonlyargcount) { return SPEC_FAIL_CODE_COMPLEX_PARAMETERS; } if ((flags & CO_OPTIMIZED) == 0) { return SPEC_FAIL_CODE_NOT_OPTIMIZED; } return SIMPLE_FUNCTION; } /* Returning false indicates a failure. */ static bool function_check_args(PyObject *o, int expected_argcount, int opcode) { assert(Py_IS_TYPE(o, &PyFunction_Type)); PyFunctionObject *func = (PyFunctionObject *)o; PyCodeObject *fcode = (PyCodeObject *)func->func_code; int kind = function_kind(fcode); if (kind != SIMPLE_FUNCTION) { SPECIALIZATION_FAIL(opcode, kind); return false; } if (fcode->co_argcount != expected_argcount) { SPECIALIZATION_FAIL(opcode, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); return false; } return true; } /* Returning 0 indicates a failure. */ static uint32_t function_get_version(PyObject *o, int opcode) { assert(Py_IS_TYPE(o, &PyFunction_Type)); PyFunctionObject *func = (PyFunctionObject *)o; uint32_t version = _PyFunction_GetVersionForCurrentState(func); if (version == 0) { SPECIALIZATION_FAIL(opcode, SPEC_FAIL_OUT_OF_VERSIONS); return 0; } return version; } void _Py_Specialize_BinarySubscr( PyObject *container, PyObject *sub, _Py_CODEUNIT *instr) { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[BINARY_SUBSCR] == INLINE_CACHE_ENTRIES_BINARY_SUBSCR); _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)(instr + 1); PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { instr->op.code = BINARY_SUBSCR_LIST_INT; goto success; } SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_RANGE); goto fail; } SPECIALIZATION_FAIL(BINARY_SUBSCR, PySlice_Check(sub) ? SPEC_FAIL_SUBSCR_LIST_SLICE : SPEC_FAIL_OTHER); goto fail; } if (container_type == &PyTuple_Type) { if (PyLong_CheckExact(sub)) { if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { instr->op.code = BINARY_SUBSCR_TUPLE_INT; goto success; } SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_RANGE); goto fail; } SPECIALIZATION_FAIL(BINARY_SUBSCR, PySlice_Check(sub) ? SPEC_FAIL_SUBSCR_TUPLE_SLICE : SPEC_FAIL_OTHER); goto fail; } if (container_type == &PyDict_Type) { instr->op.code = BINARY_SUBSCR_DICT; goto success; } PyTypeObject *cls = Py_TYPE(container); PyObject *descriptor = _PyType_Lookup(cls, &_Py_ID(__getitem__)); if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type) { if (!(container_type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_SUBSCR_NOT_HEAP_TYPE); goto fail; } PyFunctionObject *func = (PyFunctionObject *)descriptor; PyCodeObject *fcode = (PyCodeObject *)func->func_code; int kind = function_kind(fcode); if (kind != SIMPLE_FUNCTION) { SPECIALIZATION_FAIL(BINARY_SUBSCR, kind); goto fail; } if (fcode->co_argcount != 2) { SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); goto fail; } uint32_t version = _PyFunction_GetVersionForCurrentState(func); if (version == 0) { SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; } if (_PyInterpreterState_GET()->eval_frame) { SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OTHER); goto fail; } PyHeapTypeObject *ht = (PyHeapTypeObject *)container_type; // This pointer is invalidated by PyType_Modified (see the comment on // struct _specialization_cache): ht->_spec_cache.getitem = descriptor; ht->_spec_cache.getitem_version = version; instr->op.code = BINARY_SUBSCR_GETITEM; goto success; } SPECIALIZATION_FAIL(BINARY_SUBSCR, binary_subscr_fail_kind(container_type, sub)); fail: STAT_INC(BINARY_SUBSCR, failure); assert(!PyErr_Occurred()); instr->op.code = BINARY_SUBSCR; cache->counter = adaptive_counter_backoff(cache->counter); return; success: STAT_INC(BINARY_SUBSCR, success); assert(!PyErr_Occurred()); cache->counter = adaptive_counter_cooldown(); } void _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr) { assert(ENABLE_SPECIALIZATION); _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)(instr + 1); PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub) && ((PyLongObject *)sub)->long_value.ob_digit[0] < (size_t)PyList_GET_SIZE(container)) { instr->op.code = STORE_SUBSCR_LIST_INT; goto success; } else { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OUT_OF_RANGE); goto fail; } } else if (PySlice_Check(sub)) { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_LIST_SLICE); goto fail; } else { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER); goto fail; } } if (container_type == &PyDict_Type) { instr->op.code = STORE_SUBSCR_DICT; goto success; } #ifdef Py_STATS PyMappingMethods *as_mapping = container_type->tp_as_mapping; if (as_mapping && (as_mapping->mp_ass_subscript == PyDict_Type.tp_as_mapping->mp_ass_subscript)) { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_DICT_SUBCLASS_NO_OVERRIDE); goto fail; } if (PyObject_CheckBuffer(container)) { if (PyLong_CheckExact(sub) && (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub))) { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OUT_OF_RANGE); } else if (strcmp(container_type->tp_name, "array.array") == 0) { if (PyLong_CheckExact(sub)) { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_ARRAY_INT); } else if (PySlice_Check(sub)) { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_ARRAY_SLICE); } else { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER); } } else if (PyByteArray_CheckExact(container)) { if (PyLong_CheckExact(sub)) { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BYTEARRAY_INT); } else if (PySlice_Check(sub)) { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BYTEARRAY_SLICE); } else { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER); } } else { if (PyLong_CheckExact(sub)) { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BUFFER_INT); } else if (PySlice_Check(sub)) { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_BUFFER_SLICE); } else { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER); } } goto fail; } PyObject *descriptor = _PyType_Lookup(container_type, &_Py_ID(__setitem__)); if (descriptor && Py_TYPE(descriptor) == &PyFunction_Type) { PyFunctionObject *func = (PyFunctionObject *)descriptor; PyCodeObject *code = (PyCodeObject *)func->func_code; int kind = function_kind(code); if (kind == SIMPLE_FUNCTION) { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_PY_SIMPLE); } else { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_SUBSCR_PY_OTHER); } goto fail; } #endif SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OTHER); fail: STAT_INC(STORE_SUBSCR, failure); assert(!PyErr_Occurred()); instr->op.code = STORE_SUBSCR; cache->counter = adaptive_counter_backoff(cache->counter); return; success: STAT_INC(STORE_SUBSCR, success); assert(!PyErr_Occurred()); cache->counter = adaptive_counter_cooldown(); } static int specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, PyObject *kwnames) { PyTypeObject *tp = _PyType_CAST(callable); if (tp->tp_new == PyBaseObject_Type.tp_new) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PYTHON_CLASS); return -1; } if (tp->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) { int oparg = instr->op.arg; if (nargs == 1 && kwnames == NULL && oparg == 1) { if (tp == &PyUnicode_Type) { instr->op.code = CALL_NO_KW_STR_1; return 0; } else if (tp == &PyType_Type) { instr->op.code = CALL_NO_KW_TYPE_1; return 0; } else if (tp == &PyTuple_Type) { instr->op.code = CALL_NO_KW_TUPLE_1; return 0; } } if (tp->tp_vectorcall != NULL) { instr->op.code = CALL_BUILTIN_CLASS; return 0; } SPECIALIZATION_FAIL(CALL, tp == &PyUnicode_Type ? SPEC_FAIL_CALL_STR : SPEC_FAIL_CALL_CLASS_NO_VECTORCALL); return -1; } SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_CLASS_MUTABLE); return -1; } #ifdef Py_STATS static int builtin_call_fail_kind(int ml_flags) { switch (ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { case METH_VARARGS: return SPEC_FAIL_CALL_CFUNC_VARARGS; case METH_VARARGS | METH_KEYWORDS: return SPEC_FAIL_CALL_CFUNC_VARARGS_KEYWORDS; case METH_NOARGS: return SPEC_FAIL_CALL_CFUNC_NOARGS; case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: return SPEC_FAIL_CALL_CFUNC_METHOD_FASTCALL_KEYWORDS; /* These cases should be optimized, but return "other" just in case */ case METH_O: case METH_FASTCALL: case METH_FASTCALL | METH_KEYWORDS: return SPEC_FAIL_OTHER; default: return SPEC_FAIL_CALL_BAD_CALL_FLAGS; } } static int meth_descr_call_fail_kind(int ml_flags) { switch (ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { case METH_VARARGS: return SPEC_FAIL_CALL_METH_DESCR_VARARGS; case METH_VARARGS | METH_KEYWORDS: return SPEC_FAIL_CALL_METH_DESCR_VARARGS_KEYWORDS; case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: return SPEC_FAIL_CALL_METH_DESCR_METHOD_FASTCALL_KEYWORDS; /* These cases should be optimized, but return "other" just in case */ case METH_NOARGS: case METH_O: case METH_FASTCALL: case METH_FASTCALL | METH_KEYWORDS: return SPEC_FAIL_OTHER; default: return SPEC_FAIL_CALL_BAD_CALL_FLAGS; } } #endif static int specialize_method_descriptor(PyMethodDescrObject *descr, _Py_CODEUNIT *instr, int nargs, PyObject *kwnames) { if (kwnames) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES); return -1; } switch (descr->d_method->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { case METH_NOARGS: { if (nargs != 1) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); return -1; } instr->op.code = CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS; return 0; } case METH_O: { if (nargs != 2) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); return -1; } PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *list_append = interp->callable_cache.list_append; _Py_CODEUNIT next = instr[INLINE_CACHE_ENTRIES_CALL + 1]; bool pop = (next.op.code == POP_TOP); int oparg = instr->op.arg; if ((PyObject *)descr == list_append && oparg == 1 && pop) { instr->op.code = CALL_NO_KW_LIST_APPEND; return 0; } instr->op.code = CALL_NO_KW_METHOD_DESCRIPTOR_O; return 0; } case METH_FASTCALL: { instr->op.code = CALL_NO_KW_METHOD_DESCRIPTOR_FAST; return 0; } case METH_FASTCALL | METH_KEYWORDS: { instr->op.code = CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS; return 0; } } SPECIALIZATION_FAIL(CALL, meth_descr_call_fail_kind(descr->d_method->ml_flags)); return -1; } static int specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs, PyObject *kwnames, bool bound_method) { _PyCallCache *cache = (_PyCallCache *)(instr + 1); PyCodeObject *code = (PyCodeObject *)func->func_code; int kind = function_kind(code); /* Don't specialize if PEP 523 is active */ if (_PyInterpreterState_GET()->eval_frame) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PEP_523); return -1; } if (kwnames) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES); return -1; } if (kind != SIMPLE_FUNCTION) { SPECIALIZATION_FAIL(CALL, kind); return -1; } int argcount = code->co_argcount; int defcount = func->func_defaults == NULL ? 0 : (int)PyTuple_GET_SIZE(func->func_defaults); assert(defcount <= argcount); int min_args = argcount-defcount; if (nargs > argcount || nargs < min_args) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); return -1; } assert(nargs <= argcount && nargs >= min_args); assert(min_args >= 0 && defcount >= 0); assert(defcount == 0 || func->func_defaults != NULL); int version = _PyFunction_GetVersionForCurrentState(func); if (version == 0) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_VERSIONS); return -1; } write_u32(cache->func_version, version); if (argcount == nargs) { instr->op.code = bound_method ? CALL_BOUND_METHOD_EXACT_ARGS : CALL_PY_EXACT_ARGS; } else if (bound_method) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_BOUND_METHOD); return -1; } else { instr->op.code = CALL_PY_WITH_DEFAULTS; } return 0; } static int specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, PyObject *kwnames) { if (PyCFunction_GET_FUNCTION(callable) == NULL) { return 1; } switch (PyCFunction_GET_FLAGS(callable) & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { case METH_O: { if (kwnames) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES); return -1; } if (nargs != 1) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); return 1; } /* len(o) */ PyInterpreterState *interp = _PyInterpreterState_GET(); if (callable == interp->callable_cache.len) { instr->op.code = CALL_NO_KW_LEN; return 0; } instr->op.code = CALL_NO_KW_BUILTIN_O; return 0; } case METH_FASTCALL: { if (kwnames) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES); return -1; } if (nargs == 2) { /* isinstance(o1, o2) */ PyInterpreterState *interp = _PyInterpreterState_GET(); if (callable == interp->callable_cache.isinstance) { instr->op.code = CALL_NO_KW_ISINSTANCE; return 0; } } instr->op.code = CALL_NO_KW_BUILTIN_FAST; return 0; } case METH_FASTCALL | METH_KEYWORDS: { instr->op.code = CALL_BUILTIN_FAST_WITH_KEYWORDS; return 0; } default: SPECIALIZATION_FAIL(CALL, builtin_call_fail_kind(PyCFunction_GET_FLAGS(callable))); return 1; } } #ifdef Py_STATS static int call_fail_kind(PyObject *callable) { assert(!PyCFunction_CheckExact(callable)); assert(!PyFunction_Check(callable)); assert(!PyType_Check(callable)); assert(!Py_IS_TYPE(callable, &PyMethodDescr_Type)); assert(!PyMethod_Check(callable)); if (PyInstanceMethod_Check(callable)) { return SPEC_FAIL_CALL_INSTANCE_METHOD; } // builtin method else if (PyCMethod_Check(callable)) { return SPEC_FAIL_CALL_CMETHOD; } else if (Py_TYPE(callable) == &PyWrapperDescr_Type) { return SPEC_FAIL_CALL_OPERATOR_WRAPPER; } else if (Py_TYPE(callable) == &_PyMethodWrapper_Type) { return SPEC_FAIL_CALL_METHOD_WRAPPER; } return SPEC_FAIL_OTHER; } #endif /* TODO: - Specialize calling classes. */ void _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, PyObject *kwnames) { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[CALL] == INLINE_CACHE_ENTRIES_CALL); assert(_Py_OPCODE(*instr) != INSTRUMENTED_CALL); _PyCallCache *cache = (_PyCallCache *)(instr + 1); int fail; if (PyCFunction_CheckExact(callable)) { fail = specialize_c_call(callable, instr, nargs, kwnames); } else if (PyFunction_Check(callable)) { fail = specialize_py_call((PyFunctionObject *)callable, instr, nargs, kwnames, false); } else if (PyType_Check(callable)) { fail = specialize_class_call(callable, instr, nargs, kwnames); } else if (Py_IS_TYPE(callable, &PyMethodDescr_Type)) { fail = specialize_method_descriptor((PyMethodDescrObject *)callable, instr, nargs, kwnames); } else if (PyMethod_Check(callable)) { PyObject *func = ((PyMethodObject *)callable)->im_func; if (PyFunction_Check(func)) { fail = specialize_py_call((PyFunctionObject *)func, instr, nargs+1, kwnames, true); } else { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_BOUND_METHOD); fail = -1; } } else { SPECIALIZATION_FAIL(CALL, call_fail_kind(callable)); fail = -1; } if (fail) { STAT_INC(CALL, failure); assert(!PyErr_Occurred()); instr->op.code = CALL; cache->counter = adaptive_counter_backoff(cache->counter); } else { STAT_INC(CALL, success); assert(!PyErr_Occurred()); cache->counter = adaptive_counter_cooldown(); } } #ifdef Py_STATS static int binary_op_fail_kind(int oparg, PyObject *lhs, PyObject *rhs) { switch (oparg) { case NB_ADD: case NB_INPLACE_ADD: if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { return SPEC_FAIL_BINARY_OP_ADD_DIFFERENT_TYPES; } return SPEC_FAIL_BINARY_OP_ADD_OTHER; case NB_AND: case NB_INPLACE_AND: if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { return SPEC_FAIL_BINARY_OP_AND_DIFFERENT_TYPES; } if (PyLong_CheckExact(lhs)) { return SPEC_FAIL_BINARY_OP_AND_INT; } return SPEC_FAIL_BINARY_OP_AND_OTHER; case NB_FLOOR_DIVIDE: case NB_INPLACE_FLOOR_DIVIDE: return SPEC_FAIL_BINARY_OP_FLOOR_DIVIDE; case NB_LSHIFT: case NB_INPLACE_LSHIFT: return SPEC_FAIL_BINARY_OP_LSHIFT; case NB_MATRIX_MULTIPLY: case NB_INPLACE_MATRIX_MULTIPLY: return SPEC_FAIL_BINARY_OP_MATRIX_MULTIPLY; case NB_MULTIPLY: case NB_INPLACE_MULTIPLY: if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { return SPEC_FAIL_BINARY_OP_MULTIPLY_DIFFERENT_TYPES; } return SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER; case NB_OR: case NB_INPLACE_OR: return SPEC_FAIL_BINARY_OP_OR; case NB_POWER: case NB_INPLACE_POWER: return SPEC_FAIL_BINARY_OP_POWER; case NB_REMAINDER: case NB_INPLACE_REMAINDER: return SPEC_FAIL_BINARY_OP_REMAINDER; case NB_RSHIFT: case NB_INPLACE_RSHIFT: return SPEC_FAIL_BINARY_OP_RSHIFT; case NB_SUBTRACT: case NB_INPLACE_SUBTRACT: if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { return SPEC_FAIL_BINARY_OP_SUBTRACT_DIFFERENT_TYPES; } return SPEC_FAIL_BINARY_OP_SUBTRACT_OTHER; case NB_TRUE_DIVIDE: case NB_INPLACE_TRUE_DIVIDE: if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_DIFFERENT_TYPES; } if (PyFloat_CheckExact(lhs)) { return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT; } return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER; case NB_XOR: case NB_INPLACE_XOR: return SPEC_FAIL_BINARY_OP_XOR; } Py_UNREACHABLE(); } #endif void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, int oparg, PyObject **locals) { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[BINARY_OP] == INLINE_CACHE_ENTRIES_BINARY_OP); _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(instr + 1); switch (oparg) { case NB_ADD: case NB_INPLACE_ADD: if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { break; } if (PyUnicode_CheckExact(lhs)) { _Py_CODEUNIT next = instr[INLINE_CACHE_ENTRIES_BINARY_OP + 1]; bool to_store = (next.op.code == STORE_FAST || next.op.code == STORE_FAST__LOAD_FAST); if (to_store && locals[next.op.arg] == lhs) { instr->op.code = BINARY_OP_INPLACE_ADD_UNICODE; goto success; } instr->op.code = BINARY_OP_ADD_UNICODE; goto success; } if (PyLong_CheckExact(lhs)) { instr->op.code = BINARY_OP_ADD_INT; goto success; } if (PyFloat_CheckExact(lhs)) { instr->op.code = BINARY_OP_ADD_FLOAT; goto success; } break; case NB_MULTIPLY: case NB_INPLACE_MULTIPLY: if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { break; } if (PyLong_CheckExact(lhs)) { instr->op.code = BINARY_OP_MULTIPLY_INT; goto success; } if (PyFloat_CheckExact(lhs)) { instr->op.code = BINARY_OP_MULTIPLY_FLOAT; goto success; } break; case NB_SUBTRACT: case NB_INPLACE_SUBTRACT: if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { break; } if (PyLong_CheckExact(lhs)) { instr->op.code = BINARY_OP_SUBTRACT_INT; goto success; } if (PyFloat_CheckExact(lhs)) { instr->op.code = BINARY_OP_SUBTRACT_FLOAT; goto success; } break; } SPECIALIZATION_FAIL(BINARY_OP, binary_op_fail_kind(oparg, lhs, rhs)); STAT_INC(BINARY_OP, failure); instr->op.code = BINARY_OP; cache->counter = adaptive_counter_backoff(cache->counter); return; success: STAT_INC(BINARY_OP, success); cache->counter = adaptive_counter_cooldown(); } #ifdef Py_STATS static int compare_op_fail_kind(PyObject *lhs, PyObject *rhs) { if (Py_TYPE(lhs) != Py_TYPE(rhs)) { if (PyFloat_CheckExact(lhs) && PyLong_CheckExact(rhs)) { return SPEC_FAIL_COMPARE_OP_FLOAT_LONG; } if (PyLong_CheckExact(lhs) && PyFloat_CheckExact(rhs)) { return SPEC_FAIL_COMPARE_OP_LONG_FLOAT; } return SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES; } if (PyBytes_CheckExact(lhs)) { return SPEC_FAIL_COMPARE_OP_BYTES; } if (PyTuple_CheckExact(lhs)) { return SPEC_FAIL_COMPARE_OP_TUPLE; } if (PyList_CheckExact(lhs)) { return SPEC_FAIL_COMPARE_OP_LIST; } if (PySet_CheckExact(lhs) || PyFrozenSet_CheckExact(lhs)) { return SPEC_FAIL_COMPARE_OP_SET; } if (PyBool_Check(lhs)) { return SPEC_FAIL_COMPARE_OP_BOOL; } if (Py_TYPE(lhs)->tp_richcompare == PyBaseObject_Type.tp_richcompare) { return SPEC_FAIL_COMPARE_OP_BASEOBJECT; } return SPEC_FAIL_OTHER; } #endif void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, int oparg) { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[COMPARE_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP); _PyCompareOpCache *cache = (_PyCompareOpCache *)(instr + 1); if (Py_TYPE(lhs) != Py_TYPE(rhs)) { SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); goto failure; } if (PyFloat_CheckExact(lhs)) { instr->op.code = COMPARE_OP_FLOAT; goto success; } if (PyLong_CheckExact(lhs)) { if (_PyLong_IsCompact((PyLongObject *)lhs) && _PyLong_IsCompact((PyLongObject *)rhs)) { instr->op.code = COMPARE_OP_INT; goto success; } else { SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_BIG_INT); goto failure; } } if (PyUnicode_CheckExact(lhs)) { int cmp = oparg >> 4; if (cmp != Py_EQ && cmp != Py_NE) { SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_STRING); goto failure; } else { instr->op.code = COMPARE_OP_STR; goto success; } } SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); failure: STAT_INC(COMPARE_OP, failure); instr->op.code = COMPARE_OP; cache->counter = adaptive_counter_backoff(cache->counter); return; success: STAT_INC(COMPARE_OP, success); cache->counter = adaptive_counter_cooldown(); } #ifdef Py_STATS static int unpack_sequence_fail_kind(PyObject *seq) { if (PySequence_Check(seq)) { return SPEC_FAIL_UNPACK_SEQUENCE_SEQUENCE; } if (PyIter_Check(seq)) { return SPEC_FAIL_UNPACK_SEQUENCE_ITERATOR; } return SPEC_FAIL_OTHER; } #endif void _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr, int oparg) { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[UNPACK_SEQUENCE] == INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)(instr + 1); if (PyTuple_CheckExact(seq)) { if (PyTuple_GET_SIZE(seq) != oparg) { SPECIALIZATION_FAIL(UNPACK_SEQUENCE, SPEC_FAIL_EXPECTED_ERROR); goto failure; } if (PyTuple_GET_SIZE(seq) == 2) { instr->op.code = UNPACK_SEQUENCE_TWO_TUPLE; goto success; } instr->op.code = UNPACK_SEQUENCE_TUPLE; goto success; } if (PyList_CheckExact(seq)) { if (PyList_GET_SIZE(seq) != oparg) { SPECIALIZATION_FAIL(UNPACK_SEQUENCE, SPEC_FAIL_EXPECTED_ERROR); goto failure; } instr->op.code = UNPACK_SEQUENCE_LIST; goto success; } SPECIALIZATION_FAIL(UNPACK_SEQUENCE, unpack_sequence_fail_kind(seq)); failure: STAT_INC(UNPACK_SEQUENCE, failure); instr->op.code = UNPACK_SEQUENCE; cache->counter = adaptive_counter_backoff(cache->counter); return; success: STAT_INC(UNPACK_SEQUENCE, success); cache->counter = adaptive_counter_cooldown(); } #ifdef Py_STATS int _PySpecialization_ClassifyIterator(PyObject *iter) { if (PyGen_CheckExact(iter)) { return SPEC_FAIL_ITER_GENERATOR; } if (PyCoro_CheckExact(iter)) { return SPEC_FAIL_ITER_COROUTINE; } if (PyAsyncGen_CheckExact(iter)) { return SPEC_FAIL_ITER_ASYNC_GENERATOR; } if (PyAsyncGenASend_CheckExact(iter)) { return SPEC_FAIL_ITER_ASYNC_GENERATOR_SEND; } PyTypeObject *t = Py_TYPE(iter); if (t == &PyListIter_Type) { return SPEC_FAIL_ITER_LIST; } if (t == &PyTupleIter_Type) { return SPEC_FAIL_ITER_TUPLE; } if (t == &PyDictIterKey_Type) { return SPEC_FAIL_ITER_DICT_KEYS; } if (t == &PyDictIterValue_Type) { return SPEC_FAIL_ITER_DICT_VALUES; } if (t == &PyDictIterItem_Type) { return SPEC_FAIL_ITER_DICT_ITEMS; } if (t == &PySetIter_Type) { return SPEC_FAIL_ITER_SET; } if (t == &PyUnicodeIter_Type) { return SPEC_FAIL_ITER_STRING; } if (t == &PyBytesIter_Type) { return SPEC_FAIL_ITER_BYTES; } if (t == &PyRangeIter_Type) { return SPEC_FAIL_ITER_RANGE; } if (t == &PyEnum_Type) { return SPEC_FAIL_ITER_ENUMERATE; } if (t == &PyMap_Type) { return SPEC_FAIL_ITER_MAP; } if (t == &PyZip_Type) { return SPEC_FAIL_ITER_ZIP; } if (t == &PySeqIter_Type) { return SPEC_FAIL_ITER_SEQ_ITER; } if (t == &PyListRevIter_Type) { return SPEC_FAIL_ITER_REVERSED_LIST; } if (t == &_PyUnicodeASCIIIter_Type) { return SPEC_FAIL_ITER_ASCII_STRING; } const char *name = t->tp_name; if (strncmp(name, "itertools", 9) == 0) { return SPEC_FAIL_ITER_ITERTOOLS; } if (strncmp(name, "callable_iterator", 17) == 0) { return SPEC_FAIL_ITER_CALLABLE; } return SPEC_FAIL_OTHER; } #endif void _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg) { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[FOR_ITER] == INLINE_CACHE_ENTRIES_FOR_ITER); _PyForIterCache *cache = (_PyForIterCache *)(instr + 1); PyTypeObject *tp = Py_TYPE(iter); if (tp == &PyListIter_Type) { instr->op.code = FOR_ITER_LIST; goto success; } else if (tp == &PyTupleIter_Type) { instr->op.code = FOR_ITER_TUPLE; goto success; } else if (tp == &PyRangeIter_Type) { instr->op.code = FOR_ITER_RANGE; goto success; } else if (tp == &PyGen_Type && oparg <= SHRT_MAX) { assert(instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == END_FOR || instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == INSTRUMENTED_END_FOR ); if (_PyInterpreterState_GET()->eval_frame) { SPECIALIZATION_FAIL(FOR_ITER, SPEC_FAIL_OTHER); goto failure; } instr->op.code = FOR_ITER_GEN; goto success; } SPECIALIZATION_FAIL(FOR_ITER, _PySpecialization_ClassifyIterator(iter)); failure: STAT_INC(FOR_ITER, failure); instr->op.code = FOR_ITER; cache->counter = adaptive_counter_backoff(cache->counter); return; success: STAT_INC(FOR_ITER, success); cache->counter = adaptive_counter_cooldown(); } void _Py_Specialize_Send(PyObject *receiver, _Py_CODEUNIT *instr) { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[SEND] == INLINE_CACHE_ENTRIES_SEND); _PySendCache *cache = (_PySendCache *)(instr + 1); PyTypeObject *tp = Py_TYPE(receiver); if (tp == &PyGen_Type || tp == &PyCoro_Type) { if (_PyInterpreterState_GET()->eval_frame) { SPECIALIZATION_FAIL(SEND, SPEC_FAIL_OTHER); goto failure; } instr->op.code = SEND_GEN; goto success; } SPECIALIZATION_FAIL(SEND, _PySpecialization_ClassifyIterator(receiver)); failure: STAT_INC(SEND, failure); instr->op.code = SEND; cache->counter = adaptive_counter_backoff(cache->counter); return; success: STAT_INC(SEND, success); cache->counter = adaptive_counter_cooldown(); } ================================================ FILE: Stdlib_Module_Names.h ================================================ // Auto-generated by Tools/build/generate_stdlib_module_names.py. // List used to create sys.stdlib_module_names. static const char* _Py_stdlib_module_names[] = { "__future__", "_abc", "_aix_support", "_ast", "_asyncio", "_bisect", "_blake2", "_bz2", "_codecs", "_codecs_cn", "_codecs_hk", "_codecs_iso2022", "_codecs_jp", "_codecs_kr", "_codecs_tw", "_collections", "_collections_abc", "_compat_pickle", "_compression", "_contextvars", "_csv", "_ctypes", "_curses", "_curses_panel", "_datetime", "_dbm", "_decimal", "_elementtree", "_frozen_importlib", "_frozen_importlib_external", "_functools", "_gdbm", "_hashlib", "_heapq", "_imp", "_io", "_json", "_locale", "_lsprof", "_lzma", "_markupbase", "_md5", "_multibytecodec", "_multiprocessing", "_opcode", "_operator", "_osx_support", "_overlapped", "_pickle", "_posixshmem", "_posixsubprocess", "_py_abc", "_pydatetime", "_pydecimal", "_pyio", "_pylong", "_queue", "_random", "_scproxy", "_sha1", "_sha2", "_sha3", "_signal", "_sitebuiltins", "_socket", "_sqlite3", "_sre", "_ssl", "_stat", "_statistics", "_string", "_strptime", "_struct", "_symtable", "_thread", "_threading_local", "_tkinter", "_tokenize", "_tracemalloc", "_typing", "_uuid", "_warnings", "_weakref", "_weakrefset", "_winapi", "_zoneinfo", "abc", "antigravity", "argparse", "array", "ast", "asyncio", "atexit", "base64", "bdb", "binascii", "bisect", "builtins", "bz2", "cProfile", "calendar", "cmath", "cmd", "code", "codecs", "codeop", "collections", "colorsys", "compileall", "concurrent", "configparser", "contextlib", "contextvars", "copy", "copyreg", "csv", "ctypes", "curses", "dataclasses", "datetime", "dbm", "decimal", "difflib", "dis", "doctest", "email", "encodings", "ensurepip", "enum", "errno", "faulthandler", "fcntl", "filecmp", "fileinput", "fnmatch", "fractions", "ftplib", "functools", "gc", "genericpath", "getopt", "getpass", "gettext", "glob", "graphlib", "grp", "gzip", "hashlib", "heapq", "hmac", "html", "http", "idlelib", "imaplib", "importlib", "inspect", "io", "ipaddress", "itertools", "json", "keyword", "linecache", "locale", "logging", "lzma", "mailbox", "marshal", "math", "mimetypes", "mmap", "modulefinder", "msvcrt", "multiprocessing", "netrc", "nt", "ntpath", "nturl2path", "numbers", "opcode", "operator", "optparse", "os", "pathlib", "pdb", "pickle", "pickletools", "pkgutil", "platform", "plistlib", "poplib", "posix", "posixpath", "pprint", "profile", "pstats", "pty", "pwd", "py_compile", "pyclbr", "pydoc", "pydoc_data", "pyexpat", "queue", "quopri", "random", "re", "readline", "reprlib", "resource", "rlcompleter", "runpy", "sched", "secrets", "select", "selectors", "shelve", "shlex", "shutil", "signal", "site", "smtplib", "socket", "socketserver", "sqlite3", "sre_compile", "sre_constants", "sre_parse", "ssl", "stat", "statistics", "string", "stringprep", "struct", "subprocess", "symtable", "sys", "sysconfig", "syslog", "tabnanny", "tarfile", "tempfile", "termios", "textwrap", "this", "threading", "time", "timeit", "tkinter", "token", "tokenize", "tomllib", "trace", "traceback", "tracemalloc", "tty", "turtle", "turtledemo", "types", "typing", "unicodedata", "unittest", "urllib", "uuid", "venv", "warnings", "wave", "weakref", "webbrowser", "winreg", "winsound", "wsgiref", "xml", "xmlrpc", "zipapp", "zipfile", "zipimport", "zlib", "zoneinfo", }; ================================================ FILE: StrucMember.c ================================================ /* Map C struct members to Python object attributes */ #include "Python.h" #include "structmember.h" // PyMemberDef PyObject * PyMember_GetOne(const char *obj_addr, PyMemberDef *l) { PyObject *v; if (l->flags & Py_RELATIVE_OFFSET) { PyErr_SetString( PyExc_SystemError, "PyMember_GetOne used with Py_RELATIVE_OFFSET"); return NULL; } const char* addr = obj_addr + l->offset; switch (l->type) { case T_BOOL: v = PyBool_FromLong(*(char*)addr); break; case T_BYTE: v = PyLong_FromLong(*(char*)addr); break; case T_UBYTE: v = PyLong_FromUnsignedLong(*(unsigned char*)addr); break; case T_SHORT: v = PyLong_FromLong(*(short*)addr); break; case T_USHORT: v = PyLong_FromUnsignedLong(*(unsigned short*)addr); break; case T_INT: v = PyLong_FromLong(*(int*)addr); break; case T_UINT: v = PyLong_FromUnsignedLong(*(unsigned int*)addr); break; case T_LONG: v = PyLong_FromLong(*(long*)addr); break; case T_ULONG: v = PyLong_FromUnsignedLong(*(unsigned long*)addr); break; case T_PYSSIZET: v = PyLong_FromSsize_t(*(Py_ssize_t*)addr); break; case T_FLOAT: v = PyFloat_FromDouble((double)*(float*)addr); break; case T_DOUBLE: v = PyFloat_FromDouble(*(double*)addr); break; case T_STRING: if (*(char**)addr == NULL) { v = Py_NewRef(Py_None); } else v = PyUnicode_FromString(*(char**)addr); break; case T_STRING_INPLACE: v = PyUnicode_FromString((char*)addr); break; case T_CHAR: v = PyUnicode_FromStringAndSize((char*)addr, 1); break; case T_OBJECT: v = *(PyObject **)addr; if (v == NULL) v = Py_None; Py_INCREF(v); break; case T_OBJECT_EX: v = *(PyObject **)addr; if (v == NULL) { PyObject *obj = (PyObject *)obj_addr; PyTypeObject *tp = Py_TYPE(obj); PyErr_Format(PyExc_AttributeError, "'%.200s' object has no attribute '%s'", tp->tp_name, l->name); } Py_XINCREF(v); break; case T_LONGLONG: v = PyLong_FromLongLong(*(long long *)addr); break; case T_ULONGLONG: v = PyLong_FromUnsignedLongLong(*(unsigned long long *)addr); break; case T_NONE: v = Py_NewRef(Py_None); break; default: PyErr_SetString(PyExc_SystemError, "bad memberdescr type"); v = NULL; } return v; } #define WARN(msg) \ do { \ if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 1) < 0) \ return -1; \ } while (0) int PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) { PyObject *oldv; if (l->flags & Py_RELATIVE_OFFSET) { PyErr_SetString( PyExc_SystemError, "PyMember_SetOne used with Py_RELATIVE_OFFSET"); return -1; } addr += l->offset; if ((l->flags & READONLY)) { PyErr_SetString(PyExc_AttributeError, "readonly attribute"); return -1; } if (v == NULL) { if (l->type == T_OBJECT_EX) { /* Check if the attribute is set. */ if (*(PyObject **)addr == NULL) { PyErr_SetString(PyExc_AttributeError, l->name); return -1; } } else if (l->type != T_OBJECT) { PyErr_SetString(PyExc_TypeError, "can't delete numeric/char attribute"); return -1; } } switch (l->type) { case T_BOOL:{ if (!PyBool_Check(v)) { PyErr_SetString(PyExc_TypeError, "attribute value type must be bool"); return -1; } if (v == Py_True) *(char*)addr = (char) 1; else *(char*)addr = (char) 0; break; } case T_BYTE:{ long long_val = PyLong_AsLong(v); if ((long_val == -1) && PyErr_Occurred()) return -1; *(char*)addr = (char)long_val; /* XXX: For compatibility, only warn about truncations for now. */ if ((long_val > CHAR_MAX) || (long_val < CHAR_MIN)) WARN("Truncation of value to char"); break; } case T_UBYTE:{ long long_val = PyLong_AsLong(v); if ((long_val == -1) && PyErr_Occurred()) return -1; *(unsigned char*)addr = (unsigned char)long_val; if ((long_val > UCHAR_MAX) || (long_val < 0)) WARN("Truncation of value to unsigned char"); break; } case T_SHORT:{ long long_val = PyLong_AsLong(v); if ((long_val == -1) && PyErr_Occurred()) return -1; *(short*)addr = (short)long_val; if ((long_val > SHRT_MAX) || (long_val < SHRT_MIN)) WARN("Truncation of value to short"); break; } case T_USHORT:{ long long_val = PyLong_AsLong(v); if ((long_val == -1) && PyErr_Occurred()) return -1; *(unsigned short*)addr = (unsigned short)long_val; if ((long_val > USHRT_MAX) || (long_val < 0)) WARN("Truncation of value to unsigned short"); break; } case T_INT:{ long long_val = PyLong_AsLong(v); if ((long_val == -1) && PyErr_Occurred()) return -1; *(int *)addr = (int)long_val; if ((long_val > INT_MAX) || (long_val < INT_MIN)) WARN("Truncation of value to int"); break; } case T_UINT:{ unsigned long ulong_val = PyLong_AsUnsignedLong(v); if ((ulong_val == (unsigned long)-1) && PyErr_Occurred()) { /* XXX: For compatibility, accept negative int values as well. */ PyErr_Clear(); ulong_val = PyLong_AsLong(v); if ((ulong_val == (unsigned long)-1) && PyErr_Occurred()) return -1; *(unsigned int *)addr = (unsigned int)ulong_val; WARN("Writing negative value into unsigned field"); } else *(unsigned int *)addr = (unsigned int)ulong_val; if (ulong_val > UINT_MAX) WARN("Truncation of value to unsigned int"); break; } case T_LONG:{ *(long*)addr = PyLong_AsLong(v); if ((*(long*)addr == -1) && PyErr_Occurred()) return -1; break; } case T_ULONG:{ *(unsigned long*)addr = PyLong_AsUnsignedLong(v); if ((*(unsigned long*)addr == (unsigned long)-1) && PyErr_Occurred()) { /* XXX: For compatibility, accept negative int values as well. */ PyErr_Clear(); *(unsigned long*)addr = PyLong_AsLong(v); if ((*(unsigned long*)addr == (unsigned long)-1) && PyErr_Occurred()) return -1; WARN("Writing negative value into unsigned field"); } break; } case T_PYSSIZET:{ *(Py_ssize_t*)addr = PyLong_AsSsize_t(v); if ((*(Py_ssize_t*)addr == (Py_ssize_t)-1) && PyErr_Occurred()) return -1; break; } case T_FLOAT:{ double double_val = PyFloat_AsDouble(v); if ((double_val == -1) && PyErr_Occurred()) return -1; *(float*)addr = (float)double_val; break; } case T_DOUBLE: *(double*)addr = PyFloat_AsDouble(v); if ((*(double*)addr == -1) && PyErr_Occurred()) return -1; break; case T_OBJECT: case T_OBJECT_EX: oldv = *(PyObject **)addr; *(PyObject **)addr = Py_XNewRef(v); Py_XDECREF(oldv); break; case T_CHAR: { const char *string; Py_ssize_t len; string = PyUnicode_AsUTF8AndSize(v, &len); if (string == NULL || len != 1) { PyErr_BadArgument(); return -1; } *(char*)addr = string[0]; break; } case T_STRING: case T_STRING_INPLACE: PyErr_SetString(PyExc_TypeError, "readonly attribute"); return -1; case T_LONGLONG:{ long long value; *(long long*)addr = value = PyLong_AsLongLong(v); if ((value == -1) && PyErr_Occurred()) return -1; break; } case T_ULONGLONG:{ unsigned long long value; /* ??? PyLong_AsLongLong accepts an int, but PyLong_AsUnsignedLongLong doesn't ??? */ if (PyLong_Check(v)) *(unsigned long long*)addr = value = PyLong_AsUnsignedLongLong(v); else *(unsigned long long*)addr = value = PyLong_AsLong(v); if ((value == (unsigned long long)-1) && PyErr_Occurred()) return -1; break; } default: PyErr_Format(PyExc_SystemError, "bad memberdescr type for %s", l->name); return -1; } return 0; } ================================================ FILE: Suggestions.c ================================================ #include "Python.h" #include "pycore_frame.h" #include "pycore_runtime.h" // _PyRuntime #include "pycore_global_objects.h" // _Py_ID() #include "pycore_pyerrors.h" #include "pycore_code.h" // _PyCode_GetVarnames() #include "stdlib_module_names.h" // _Py_stdlib_module_names #define MAX_CANDIDATE_ITEMS 750 #define MAX_STRING_SIZE 40 #define MOVE_COST 2 #define CASE_COST 1 #define LEAST_FIVE_BITS(n) ((n) & 31) static inline int substitution_cost(char a, char b) { if (LEAST_FIVE_BITS(a) != LEAST_FIVE_BITS(b)) { // Not the same, not a case flip. return MOVE_COST; } if (a == b) { return 0; } if ('A' <= a && a <= 'Z') { a += ('a' - 'A'); } if ('A' <= b && b <= 'Z') { b += ('a' - 'A'); } if (a == b) { return CASE_COST; } return MOVE_COST; } /* Calculate the Levenshtein distance between string1 and string2 */ static Py_ssize_t levenshtein_distance(const char *a, size_t a_size, const char *b, size_t b_size, size_t max_cost, size_t *buffer) { // Both strings are the same (by identity) if (a == b) { return 0; } // Trim away common affixes. while (a_size && b_size && a[0] == b[0]) { a++; a_size--; b++; b_size--; } while (a_size && b_size && a[a_size-1] == b[b_size-1]) { a_size--; b_size--; } if (a_size == 0 || b_size == 0) { return (a_size + b_size) * MOVE_COST; } if (a_size > MAX_STRING_SIZE || b_size > MAX_STRING_SIZE) { return max_cost + 1; } // Prefer shorter buffer if (b_size < a_size) { const char *t = a; a = b; b = t; size_t t_size = a_size; a_size = b_size; b_size = t_size; } // quick fail when a match is impossible. if ((b_size - a_size) * MOVE_COST > max_cost) { return max_cost + 1; } // Instead of producing the whole traditional len(a)-by-len(b) // matrix, we can update just one row in place. // Initialize the buffer row size_t tmp = MOVE_COST; for (size_t i = 0; i < a_size; i++) { // cost from b[:0] to a[:i+1] buffer[i] = tmp; tmp += MOVE_COST; } size_t result = 0; for (size_t b_index = 0; b_index < b_size; b_index++) { char code = b[b_index]; // cost(b[:b_index], a[:0]) == b_index * MOVE_COST size_t distance = result = b_index * MOVE_COST; size_t minimum = SIZE_MAX; for (size_t index = 0; index < a_size; index++) { // cost(b[:b_index+1], a[:index+1]) = min( // // 1) substitute // cost(b[:b_index], a[:index]) // + substitution_cost(b[b_index], a[index]), // // 2) delete from b // cost(b[:b_index], a[:index+1]) + MOVE_COST, // // 3) delete from a // cost(b[:b_index+1], a[index]) + MOVE_COST // ) // 1) Previous distance in this row is cost(b[:b_index], a[:index]) size_t substitute = distance + substitution_cost(code, a[index]); // 2) cost(b[:b_index], a[:index+1]) from previous row distance = buffer[index]; // 3) existing result is cost(b[:b_index+1], a[index]) size_t insert_delete = Py_MIN(result, distance) + MOVE_COST; result = Py_MIN(insert_delete, substitute); // cost(b[:b_index+1], a[:index+1]) buffer[index] = result; if (result < minimum) { minimum = result; } } if (minimum > max_cost) { // Everything in this row is too big, so bail early. return max_cost + 1; } } return result; } static inline PyObject * calculate_suggestions(PyObject *dir, PyObject *name) { assert(!PyErr_Occurred()); assert(PyList_CheckExact(dir)); Py_ssize_t dir_size = PyList_GET_SIZE(dir); if (dir_size >= MAX_CANDIDATE_ITEMS) { return NULL; } Py_ssize_t suggestion_distance = PY_SSIZE_T_MAX; PyObject *suggestion = NULL; Py_ssize_t name_size; const char *name_str = PyUnicode_AsUTF8AndSize(name, &name_size); if (name_str == NULL) { return NULL; } size_t *buffer = PyMem_New(size_t, MAX_STRING_SIZE); if (buffer == NULL) { return PyErr_NoMemory(); } for (int i = 0; i < dir_size; ++i) { PyObject *item = PyList_GET_ITEM(dir, i); Py_ssize_t item_size; const char *item_str = PyUnicode_AsUTF8AndSize(item, &item_size); if (item_str == NULL) { PyMem_Free(buffer); return NULL; } if (PyUnicode_CompareWithASCIIString(name, item_str) == 0) { continue; } // No more than 1/3 of the involved characters should need changed. Py_ssize_t max_distance = (name_size + item_size + 3) * MOVE_COST / 6; // Don't take matches we've already beaten. max_distance = Py_MIN(max_distance, suggestion_distance - 1); Py_ssize_t current_distance = levenshtein_distance(name_str, name_size, item_str, item_size, max_distance, buffer); if (current_distance > max_distance) { continue; } if (!suggestion || current_distance < suggestion_distance) { suggestion = item; suggestion_distance = current_distance; } } PyMem_Free(buffer); return Py_XNewRef(suggestion); } static PyObject * get_suggestions_for_attribute_error(PyAttributeErrorObject *exc) { PyObject *name = exc->name; // borrowed reference PyObject *obj = exc->obj; // borrowed reference // Abort if we don't have an attribute name or we have an invalid one if (name == NULL || obj == NULL || !PyUnicode_CheckExact(name)) { return NULL; } PyObject *dir = PyObject_Dir(obj); if (dir == NULL) { return NULL; } PyObject *suggestions = calculate_suggestions(dir, name); Py_DECREF(dir); return suggestions; } static PyObject * offer_suggestions_for_attribute_error(PyAttributeErrorObject *exc) { PyObject* suggestion = get_suggestions_for_attribute_error(exc); if (suggestion == NULL) { return NULL; } // Add a trailer ". Did you mean: (...)?" PyObject* result = PyUnicode_FromFormat(". Did you mean: %R?", suggestion); Py_DECREF(suggestion); return result; } static PyObject * get_suggestions_for_name_error(PyObject* name, PyFrameObject* frame) { PyCodeObject *code = PyFrame_GetCode(frame); assert(code != NULL && code->co_localsplusnames != NULL); PyObject *varnames = _PyCode_GetVarnames(code); if (varnames == NULL) { return NULL; } PyObject *dir = PySequence_List(varnames); Py_DECREF(varnames); Py_DECREF(code); if (dir == NULL) { return NULL; } // Are we inside a method and the instance has an attribute called 'name'? if (PySequence_Contains(dir, &_Py_ID(self)) > 0) { PyObject* locals = PyFrame_GetLocals(frame); if (!locals) { goto error; } PyObject* self = PyDict_GetItem(locals, &_Py_ID(self)); /* borrowed */ Py_DECREF(locals); if (!self) { goto error; } if (PyObject_HasAttr(self, name)) { Py_DECREF(dir); return PyUnicode_FromFormat("self.%S", name); } } PyObject *suggestions = calculate_suggestions(dir, name); Py_DECREF(dir); if (suggestions != NULL) { return suggestions; } dir = PySequence_List(frame->f_frame->f_globals); if (dir == NULL) { return NULL; } suggestions = calculate_suggestions(dir, name); Py_DECREF(dir); if (suggestions != NULL) { return suggestions; } dir = PySequence_List(frame->f_frame->f_builtins); if (dir == NULL) { return NULL; } suggestions = calculate_suggestions(dir, name); Py_DECREF(dir); return suggestions; error: Py_DECREF(dir); return NULL; } static bool is_name_stdlib_module(PyObject* name) { const char* the_name = PyUnicode_AsUTF8(name); Py_ssize_t len = Py_ARRAY_LENGTH(_Py_stdlib_module_names); for (Py_ssize_t i = 0; i < len; i++) { if (strcmp(the_name, _Py_stdlib_module_names[i]) == 0) { return 1; } } return 0; } static PyObject * offer_suggestions_for_name_error(PyNameErrorObject *exc) { PyObject *name = exc->name; // borrowed reference PyTracebackObject *traceback = (PyTracebackObject *) exc->traceback; // borrowed reference // Abort if we don't have a variable name or we have an invalid one // or if we don't have a traceback to work with if (name == NULL || !PyUnicode_CheckExact(name) || traceback == NULL || !Py_IS_TYPE(traceback, &PyTraceBack_Type) ) { return NULL; } // Move to the traceback of the exception while (1) { PyTracebackObject *next = traceback->tb_next; if (next == NULL || !Py_IS_TYPE(next, &PyTraceBack_Type)) { break; } else { traceback = next; } } PyFrameObject *frame = traceback->tb_frame; assert(frame != NULL); PyObject* suggestion = get_suggestions_for_name_error(name, frame); bool is_stdlib_module = is_name_stdlib_module(name); if (suggestion == NULL && !is_stdlib_module) { return NULL; } // Add a trailer ". Did you mean: (...)?" PyObject* result = NULL; if (!is_stdlib_module) { result = PyUnicode_FromFormat(". Did you mean: %R?", suggestion); } else if (suggestion == NULL) { result = PyUnicode_FromFormat(". Did you forget to import %R?", name); } else { result = PyUnicode_FromFormat(". Did you mean: %R? Or did you forget to import %R?", suggestion, name); } Py_XDECREF(suggestion); return result; } static PyObject * offer_suggestions_for_import_error(PyImportErrorObject *exc) { PyObject *mod_name = exc->name; // borrowed reference PyObject *name = exc->name_from; // borrowed reference if (name == NULL || mod_name == NULL || name == Py_None || !PyUnicode_CheckExact(name) || !PyUnicode_CheckExact(mod_name)) { return NULL; } PyObject* mod = PyImport_GetModule(mod_name); if (mod == NULL) { return NULL; } PyObject *dir = PyObject_Dir(mod); Py_DECREF(mod); if (dir == NULL) { return NULL; } PyObject *suggestion = calculate_suggestions(dir, name); Py_DECREF(dir); if (!suggestion) { return NULL; } PyObject* result = PyUnicode_FromFormat(". Did you mean: %R?", suggestion); Py_DECREF(suggestion); return result; } // Offer suggestions for a given exception. Returns a python string object containing the // suggestions. This function returns NULL if no suggestion was found or if an exception happened, // users must call PyErr_Occurred() to disambiguate. PyObject * _Py_Offer_Suggestions(PyObject *exception) { PyObject *result = NULL; assert(!PyErr_Occurred()); if (Py_IS_TYPE(exception, (PyTypeObject*)PyExc_AttributeError)) { result = offer_suggestions_for_attribute_error((PyAttributeErrorObject *) exception); } else if (Py_IS_TYPE(exception, (PyTypeObject*)PyExc_NameError)) { result = offer_suggestions_for_name_error((PyNameErrorObject *) exception); } else if (Py_IS_TYPE(exception, (PyTypeObject*)PyExc_ImportError)) { result = offer_suggestions_for_import_error((PyImportErrorObject *) exception); } return result; } Py_ssize_t _Py_UTF8_Edit_Cost(PyObject *a, PyObject *b, Py_ssize_t max_cost) { assert(PyUnicode_Check(a) && PyUnicode_Check(b)); Py_ssize_t size_a, size_b; const char *utf8_a = PyUnicode_AsUTF8AndSize(a, &size_a); if (utf8_a == NULL) { return -1; } const char *utf8_b = PyUnicode_AsUTF8AndSize(b, &size_b); if (utf8_b == NULL) { return -1; } if (max_cost == -1) { max_cost = MOVE_COST * Py_MAX(size_a, size_b); } size_t *buffer = PyMem_New(size_t, MAX_STRING_SIZE); if (buffer == NULL) { PyErr_NoMemory(); return -1; } Py_ssize_t res = levenshtein_distance(utf8_a, size_a, utf8_b, size_b, max_cost, buffer); PyMem_Free(buffer); return res; } ================================================ FILE: SyMTable.c ================================================ #include "Python.h" #include "pycore_ast.h" // identifier, stmt_ty #include "pycore_parser.h" // _PyParser_ASTFromString() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_symtable.h" // PySTEntryObject #include "structmember.h" // PyMemberDef /* error strings used for warnings */ #define GLOBAL_PARAM \ "name '%U' is parameter and global" #define NONLOCAL_PARAM \ "name '%U' is parameter and nonlocal" #define GLOBAL_AFTER_ASSIGN \ "name '%U' is assigned to before global declaration" #define NONLOCAL_AFTER_ASSIGN \ "name '%U' is assigned to before nonlocal declaration" #define GLOBAL_AFTER_USE \ "name '%U' is used prior to global declaration" #define NONLOCAL_AFTER_USE \ "name '%U' is used prior to nonlocal declaration" #define GLOBAL_ANNOT \ "annotated name '%U' can't be global" #define NONLOCAL_ANNOT \ "annotated name '%U' can't be nonlocal" #define IMPORT_STAR_WARNING "import * only allowed at module level" #define NAMED_EXPR_COMP_IN_CLASS \ "assignment expression within a comprehension cannot be used in a class body" #define NAMED_EXPR_COMP_IN_TYPEVAR_BOUND \ "assignment expression within a comprehension cannot be used in a TypeVar bound" #define NAMED_EXPR_COMP_IN_TYPEALIAS \ "assignment expression within a comprehension cannot be used in a type alias" #define NAMED_EXPR_COMP_IN_TYPEPARAM \ "assignment expression within a comprehension cannot be used within the definition of a generic" #define NAMED_EXPR_COMP_CONFLICT \ "assignment expression cannot rebind comprehension iteration variable '%U'" #define NAMED_EXPR_COMP_INNER_LOOP_CONFLICT \ "comprehension inner loop cannot rebind assignment expression target '%U'" #define NAMED_EXPR_COMP_ITER_EXPR \ "assignment expression cannot be used in a comprehension iterable expression" #define ANNOTATION_NOT_ALLOWED \ "%s cannot be used within an annotation" #define TYPEVAR_BOUND_NOT_ALLOWED \ "%s cannot be used within a TypeVar bound" #define TYPEALIAS_NOT_ALLOWED \ "%s cannot be used within a type alias" #define TYPEPARAM_NOT_ALLOWED \ "%s cannot be used within the definition of a generic" #define DUPLICATE_TYPE_PARAM \ "duplicate type parameter '%U'" #define LOCATION(x) \ (x)->lineno, (x)->col_offset, (x)->end_lineno, (x)->end_col_offset #define ST_LOCATION(x) \ (x)->ste_lineno, (x)->ste_col_offset, (x)->ste_end_lineno, (x)->ste_end_col_offset static PySTEntryObject * ste_new(struct symtable *st, identifier name, _Py_block_ty block, void *key, int lineno, int col_offset, int end_lineno, int end_col_offset) { PySTEntryObject *ste = NULL; PyObject *k = NULL; k = PyLong_FromVoidPtr(key); if (k == NULL) goto fail; ste = PyObject_New(PySTEntryObject, &PySTEntry_Type); if (ste == NULL) { Py_DECREF(k); goto fail; } ste->ste_table = st; ste->ste_id = k; /* ste owns reference to k */ ste->ste_name = Py_NewRef(name); ste->ste_symbols = NULL; ste->ste_varnames = NULL; ste->ste_children = NULL; ste->ste_directives = NULL; ste->ste_type = block; ste->ste_nested = 0; ste->ste_free = 0; ste->ste_varargs = 0; ste->ste_varkeywords = 0; ste->ste_opt_lineno = 0; ste->ste_opt_col_offset = 0; ste->ste_lineno = lineno; ste->ste_col_offset = col_offset; ste->ste_end_lineno = end_lineno; ste->ste_end_col_offset = end_col_offset; if (st->st_cur != NULL && (st->st_cur->ste_nested || _PyST_IsFunctionLike(st->st_cur))) ste->ste_nested = 1; ste->ste_child_free = 0; ste->ste_generator = 0; ste->ste_coroutine = 0; ste->ste_comprehension = NoComprehension; ste->ste_returns_value = 0; ste->ste_needs_class_closure = 0; ste->ste_comp_inlined = 0; ste->ste_comp_iter_target = 0; ste->ste_can_see_class_scope = 0; ste->ste_comp_iter_expr = 0; ste->ste_needs_classdict = 0; ste->ste_symbols = PyDict_New(); ste->ste_varnames = PyList_New(0); ste->ste_children = PyList_New(0); if (ste->ste_symbols == NULL || ste->ste_varnames == NULL || ste->ste_children == NULL) goto fail; if (PyDict_SetItem(st->st_blocks, ste->ste_id, (PyObject *)ste) < 0) goto fail; return ste; fail: Py_XDECREF(ste); return NULL; } static PyObject * ste_repr(PySTEntryObject *ste) { return PyUnicode_FromFormat("", ste->ste_name, PyLong_AS_LONG(ste->ste_id), ste->ste_lineno); } static void ste_dealloc(PySTEntryObject *ste) { ste->ste_table = NULL; Py_XDECREF(ste->ste_id); Py_XDECREF(ste->ste_name); Py_XDECREF(ste->ste_symbols); Py_XDECREF(ste->ste_varnames); Py_XDECREF(ste->ste_children); Py_XDECREF(ste->ste_directives); PyObject_Free(ste); } #define OFF(x) offsetof(PySTEntryObject, x) static PyMemberDef ste_memberlist[] = { {"id", T_OBJECT, OFF(ste_id), READONLY}, {"name", T_OBJECT, OFF(ste_name), READONLY}, {"symbols", T_OBJECT, OFF(ste_symbols), READONLY}, {"varnames", T_OBJECT, OFF(ste_varnames), READONLY}, {"children", T_OBJECT, OFF(ste_children), READONLY}, {"nested", T_INT, OFF(ste_nested), READONLY}, {"type", T_INT, OFF(ste_type), READONLY}, {"lineno", T_INT, OFF(ste_lineno), READONLY}, {NULL} }; PyTypeObject PySTEntry_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "symtable entry", sizeof(PySTEntryObject), 0, (destructor)ste_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ (reprfunc)ste_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ ste_memberlist, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ }; static int symtable_analyze(struct symtable *st); static int symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block, void *ast, int lineno, int col_offset, int end_lineno, int end_col_offset); static int symtable_exit_block(struct symtable *st); static int symtable_visit_stmt(struct symtable *st, stmt_ty s); static int symtable_visit_expr(struct symtable *st, expr_ty s); static int symtable_visit_type_param(struct symtable *st, type_param_ty s); static int symtable_visit_genexp(struct symtable *st, expr_ty s); static int symtable_visit_listcomp(struct symtable *st, expr_ty s); static int symtable_visit_setcomp(struct symtable *st, expr_ty s); static int symtable_visit_dictcomp(struct symtable *st, expr_ty s); static int symtable_visit_arguments(struct symtable *st, arguments_ty); static int symtable_visit_excepthandler(struct symtable *st, excepthandler_ty); static int symtable_visit_alias(struct symtable *st, alias_ty); static int symtable_visit_comprehension(struct symtable *st, comprehension_ty); static int symtable_visit_keyword(struct symtable *st, keyword_ty); static int symtable_visit_params(struct symtable *st, asdl_arg_seq *args); static int symtable_visit_annotation(struct symtable *st, expr_ty annotation); static int symtable_visit_argannotations(struct symtable *st, asdl_arg_seq *args); static int symtable_implicit_arg(struct symtable *st, int pos); static int symtable_visit_annotations(struct symtable *st, stmt_ty, arguments_ty, expr_ty); static int symtable_visit_withitem(struct symtable *st, withitem_ty item); static int symtable_visit_match_case(struct symtable *st, match_case_ty m); static int symtable_visit_pattern(struct symtable *st, pattern_ty s); static int symtable_raise_if_annotation_block(struct symtable *st, const char *, expr_ty); static int symtable_raise_if_comprehension_block(struct symtable *st, expr_ty); #define DUPLICATE_ARGUMENT \ "duplicate argument '%U' in function definition" static struct symtable * symtable_new(void) { struct symtable *st; st = (struct symtable *)PyMem_Malloc(sizeof(struct symtable)); if (st == NULL) { PyErr_NoMemory(); return NULL; } st->st_filename = NULL; st->st_blocks = NULL; if ((st->st_stack = PyList_New(0)) == NULL) goto fail; if ((st->st_blocks = PyDict_New()) == NULL) goto fail; st->st_cur = NULL; st->st_private = NULL; return st; fail: _PySymtable_Free(st); return NULL; } /* When compiling the use of C stack is probably going to be a lot lighter than when executing Python code but still can overflow and causing a Python crash if not checked (e.g. eval("()"*300000)). Using the current recursion limit for the compiler seems too restrictive (it caused at least one test to fail) so a factor is used to allow deeper recursion when compiling an expression. Using a scaling factor means this should automatically adjust when the recursion limit is adjusted for small or large C stack allocations. */ #define COMPILER_STACK_FRAME_SCALE 3 struct symtable * _PySymtable_Build(mod_ty mod, PyObject *filename, PyFutureFeatures *future) { struct symtable *st = symtable_new(); asdl_stmt_seq *seq; int i; PyThreadState *tstate; int starting_recursion_depth; if (st == NULL) return NULL; if (filename == NULL) { _PySymtable_Free(st); return NULL; } st->st_filename = Py_NewRef(filename); st->st_future = future; /* Setup recursion depth check counters */ tstate = _PyThreadState_GET(); if (!tstate) { _PySymtable_Free(st); return NULL; } /* Be careful here to prevent overflow. */ int recursion_depth = C_RECURSION_LIMIT - tstate->c_recursion_remaining; starting_recursion_depth = recursion_depth * COMPILER_STACK_FRAME_SCALE; st->recursion_depth = starting_recursion_depth; st->recursion_limit = C_RECURSION_LIMIT * COMPILER_STACK_FRAME_SCALE; /* Make the initial symbol information gathering pass */ if (!symtable_enter_block(st, &_Py_ID(top), ModuleBlock, (void *)mod, 0, 0, 0, 0)) { _PySymtable_Free(st); return NULL; } st->st_top = st->st_cur; switch (mod->kind) { case Module_kind: seq = mod->v.Module.body; for (i = 0; i < asdl_seq_LEN(seq); i++) if (!symtable_visit_stmt(st, (stmt_ty)asdl_seq_GET(seq, i))) goto error; break; case Expression_kind: if (!symtable_visit_expr(st, mod->v.Expression.body)) goto error; break; case Interactive_kind: seq = mod->v.Interactive.body; for (i = 0; i < asdl_seq_LEN(seq); i++) if (!symtable_visit_stmt(st, (stmt_ty)asdl_seq_GET(seq, i))) goto error; break; case FunctionType_kind: PyErr_SetString(PyExc_RuntimeError, "this compiler does not handle FunctionTypes"); goto error; } if (!symtable_exit_block(st)) { _PySymtable_Free(st); return NULL; } /* Check that the recursion depth counting balanced correctly */ if (st->recursion_depth != starting_recursion_depth) { PyErr_Format(PyExc_SystemError, "symtable analysis recursion depth mismatch (before=%d, after=%d)", starting_recursion_depth, st->recursion_depth); _PySymtable_Free(st); return NULL; } /* Make the second symbol analysis pass */ if (symtable_analyze(st)) return st; _PySymtable_Free(st); return NULL; error: (void) symtable_exit_block(st); _PySymtable_Free(st); return NULL; } void _PySymtable_Free(struct symtable *st) { Py_XDECREF(st->st_filename); Py_XDECREF(st->st_blocks); Py_XDECREF(st->st_stack); PyMem_Free((void *)st); } PySTEntryObject * PySymtable_Lookup(struct symtable *st, void *key) { PyObject *k, *v; k = PyLong_FromVoidPtr(key); if (k == NULL) return NULL; v = PyDict_GetItemWithError(st->st_blocks, k); Py_DECREF(k); if (v) { assert(PySTEntry_Check(v)); } else if (!PyErr_Occurred()) { PyErr_SetString(PyExc_KeyError, "unknown symbol table entry"); } return (PySTEntryObject *)Py_XNewRef(v); } long _PyST_GetSymbol(PySTEntryObject *ste, PyObject *name) { PyObject *v = PyDict_GetItemWithError(ste->ste_symbols, name); if (!v) return 0; assert(PyLong_Check(v)); return PyLong_AS_LONG(v); } int _PyST_GetScope(PySTEntryObject *ste, PyObject *name) { long symbol = _PyST_GetSymbol(ste, name); return (symbol >> SCOPE_OFFSET) & SCOPE_MASK; } int _PyST_IsFunctionLike(PySTEntryObject *ste) { return ste->ste_type == FunctionBlock || ste->ste_type == TypeVarBoundBlock || ste->ste_type == TypeAliasBlock || ste->ste_type == TypeParamBlock; } static int error_at_directive(PySTEntryObject *ste, PyObject *name) { Py_ssize_t i; PyObject *data; assert(ste->ste_directives); for (i = 0; i < PyList_GET_SIZE(ste->ste_directives); i++) { data = PyList_GET_ITEM(ste->ste_directives, i); assert(PyTuple_CheckExact(data)); assert(PyUnicode_CheckExact(PyTuple_GET_ITEM(data, 0))); if (PyUnicode_Compare(PyTuple_GET_ITEM(data, 0), name) == 0) { PyErr_RangedSyntaxLocationObject(ste->ste_table->st_filename, PyLong_AsLong(PyTuple_GET_ITEM(data, 1)), PyLong_AsLong(PyTuple_GET_ITEM(data, 2)) + 1, PyLong_AsLong(PyTuple_GET_ITEM(data, 3)), PyLong_AsLong(PyTuple_GET_ITEM(data, 4)) + 1); return 0; } } PyErr_SetString(PyExc_RuntimeError, "BUG: internal directive bookkeeping broken"); return 0; } /* Analyze raw symbol information to determine scope of each name. The next several functions are helpers for symtable_analyze(), which determines whether a name is local, global, or free. In addition, it determines which local variables are cell variables; they provide bindings that are used for free variables in enclosed blocks. There are also two kinds of global variables, implicit and explicit. An explicit global is declared with the global statement. An implicit global is a free variable for which the compiler has found no binding in an enclosing function scope. The implicit global is either a global or a builtin. Python's module and class blocks use the xxx_NAME opcodes to handle these names to implement slightly odd semantics. In such a block, the name is treated as global until it is assigned to; then it is treated as a local. The symbol table requires two passes to determine the scope of each name. The first pass collects raw facts from the AST via the symtable_visit_* functions: the name is a parameter here, the name is used but not defined here, etc. The second pass analyzes these facts during a pass over the PySTEntryObjects created during pass 1. When a function is entered during the second pass, the parent passes the set of all name bindings visible to its children. These bindings are used to determine if non-local variables are free or implicit globals. Names which are explicitly declared nonlocal must exist in this set of visible names - if they do not, a syntax error is raised. After doing the local analysis, it analyzes each of its child blocks using an updated set of name bindings. The children update the free variable set. If a local variable is added to the free variable set by the child, the variable is marked as a cell. The function object being defined must provide runtime storage for the variable that may outlive the function's frame. Cell variables are removed from the free set before the analyze function returns to its parent. During analysis, the names are: symbols: dict mapping from symbol names to flag values (including offset scope values) scopes: dict mapping from symbol names to scope values (no offset) local: set of all symbol names local to the current scope bound: set of all symbol names local to a containing function scope free: set of all symbol names referenced but not bound in child scopes global: set of all symbol names explicitly declared as global */ #define SET_SCOPE(DICT, NAME, I) { \ PyObject *o = PyLong_FromLong(I); \ if (!o) \ return 0; \ if (PyDict_SetItem((DICT), (NAME), o) < 0) { \ Py_DECREF(o); \ return 0; \ } \ Py_DECREF(o); \ } /* Decide on scope of name, given flags. The namespace dictionaries may be modified to record information about the new name. For example, a new global will add an entry to global. A name that was global can be changed to local. */ static int analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags, PyObject *bound, PyObject *local, PyObject *free, PyObject *global, PyObject *type_params, PySTEntryObject *class_entry) { if (flags & DEF_GLOBAL) { if (flags & DEF_NONLOCAL) { PyErr_Format(PyExc_SyntaxError, "name '%U' is nonlocal and global", name); return error_at_directive(ste, name); } SET_SCOPE(scopes, name, GLOBAL_EXPLICIT); if (PySet_Add(global, name) < 0) return 0; if (bound && (PySet_Discard(bound, name) < 0)) return 0; return 1; } if (flags & DEF_NONLOCAL) { if (!bound) { PyErr_Format(PyExc_SyntaxError, "nonlocal declaration not allowed at module level"); return error_at_directive(ste, name); } if (!PySet_Contains(bound, name)) { PyErr_Format(PyExc_SyntaxError, "no binding for nonlocal '%U' found", name); return error_at_directive(ste, name); } if (PySet_Contains(type_params, name)) { PyErr_Format(PyExc_SyntaxError, "nonlocal binding not allowed for type parameter '%U'", name); return error_at_directive(ste, name); } SET_SCOPE(scopes, name, FREE); ste->ste_free = 1; return PySet_Add(free, name) >= 0; } if (flags & DEF_BOUND) { SET_SCOPE(scopes, name, LOCAL); if (PySet_Add(local, name) < 0) return 0; if (PySet_Discard(global, name) < 0) return 0; if (flags & DEF_TYPE_PARAM) { if (PySet_Add(type_params, name) < 0) return 0; } else { if (PySet_Discard(type_params, name) < 0) return 0; } return 1; } // If we were passed class_entry (i.e., we're in an ste_can_see_class_scope scope) // and the bound name is in that set, then the name is potentially bound both by // the immediately enclosing class namespace, and also by an outer function namespace. // In that case, we want the runtime name resolution to look at only the class // namespace and the globals (not the namespace providing the bound). // Similarly, if the name is explicitly global in the class namespace (through the // global statement), we want to also treat it as a global in this scope. if (class_entry != NULL) { long class_flags = _PyST_GetSymbol(class_entry, name); if (class_flags & DEF_GLOBAL) { SET_SCOPE(scopes, name, GLOBAL_EXPLICIT); return 1; } else if (class_flags & DEF_BOUND && !(class_flags & DEF_NONLOCAL)) { SET_SCOPE(scopes, name, GLOBAL_IMPLICIT); return 1; } } /* If an enclosing block has a binding for this name, it is a free variable rather than a global variable. Note that having a non-NULL bound implies that the block is nested. */ if (bound && PySet_Contains(bound, name)) { SET_SCOPE(scopes, name, FREE); ste->ste_free = 1; return PySet_Add(free, name) >= 0; } /* If a parent has a global statement, then call it global explicit? It could also be global implicit. */ if (global && PySet_Contains(global, name)) { SET_SCOPE(scopes, name, GLOBAL_IMPLICIT); return 1; } if (ste->ste_nested) ste->ste_free = 1; SET_SCOPE(scopes, name, GLOBAL_IMPLICIT); return 1; } static int is_free_in_any_child(PySTEntryObject *entry, PyObject *key) { for (Py_ssize_t i = 0; i < PyList_GET_SIZE(entry->ste_children); i++) { PySTEntryObject *child_ste = (PySTEntryObject *)PyList_GET_ITEM( entry->ste_children, i); long scope = _PyST_GetScope(child_ste, key); if (scope == FREE) { return 1; } } return 0; } static int inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, PyObject *scopes, PyObject *comp_free, PyObject *inlined_cells) { PyObject *k, *v; Py_ssize_t pos = 0; while (PyDict_Next(comp->ste_symbols, &pos, &k, &v)) { // skip comprehension parameter long comp_flags = PyLong_AS_LONG(v); if (comp_flags & DEF_PARAM) { assert(_PyUnicode_EqualToASCIIString(k, ".0")); continue; } int scope = (comp_flags >> SCOPE_OFFSET) & SCOPE_MASK; int only_flags = comp_flags & ((1 << SCOPE_OFFSET) - 1); if (scope == CELL || only_flags & DEF_COMP_CELL) { if (PySet_Add(inlined_cells, k) < 0) { return 0; } } PyObject *existing = PyDict_GetItemWithError(ste->ste_symbols, k); if (existing == NULL && PyErr_Occurred()) { return 0; } if (!existing) { // name does not exist in scope, copy from comprehension assert(scope != FREE || PySet_Contains(comp_free, k) == 1); PyObject *v_flags = PyLong_FromLong(only_flags); if (v_flags == NULL) { return 0; } int ok = PyDict_SetItem(ste->ste_symbols, k, v_flags); Py_DECREF(v_flags); if (ok < 0) { return 0; } SET_SCOPE(scopes, k, scope); } else { if (PyLong_AsLong(existing) & DEF_BOUND) { // free vars in comprehension that are locals in outer scope can // now simply be locals, unless they are free in comp children, // or if the outer scope is a class block if (!is_free_in_any_child(comp, k) && ste->ste_type != ClassBlock) { if (PySet_Discard(comp_free, k) < 0) { return 0; } } } } } return 1; } #undef SET_SCOPE /* If a name is defined in free and also in locals, then this block provides the binding for the free variable. The name should be marked CELL in this block and removed from the free list. Note that the current block's free variables are included in free. That's safe because no name can be free and local in the same scope. */ static int analyze_cells(PyObject *scopes, PyObject *free, PyObject *inlined_cells) { PyObject *name, *v, *v_cell; int success = 0; Py_ssize_t pos = 0; v_cell = PyLong_FromLong(CELL); if (!v_cell) return 0; while (PyDict_Next(scopes, &pos, &name, &v)) { long scope; assert(PyLong_Check(v)); scope = PyLong_AS_LONG(v); if (scope != LOCAL) continue; if (!PySet_Contains(free, name) && !PySet_Contains(inlined_cells, name)) continue; /* Replace LOCAL with CELL for this name, and remove from free. It is safe to replace the value of name in the dict, because it will not cause a resize. */ if (PyDict_SetItem(scopes, name, v_cell) < 0) goto error; if (PySet_Discard(free, name) < 0) goto error; } success = 1; error: Py_DECREF(v_cell); return success; } static int drop_class_free(PySTEntryObject *ste, PyObject *free) { int res; res = PySet_Discard(free, &_Py_ID(__class__)); if (res < 0) return 0; if (res) ste->ste_needs_class_closure = 1; res = PySet_Discard(free, &_Py_ID(__classdict__)); if (res < 0) return 0; if (res) ste->ste_needs_classdict = 1; return 1; } /* Enter the final scope information into the ste_symbols dict. * * All arguments are dicts. Modifies symbols, others are read-only. */ static int update_symbols(PyObject *symbols, PyObject *scopes, PyObject *bound, PyObject *free, PyObject *inlined_cells, int classflag) { PyObject *name = NULL, *itr = NULL; PyObject *v = NULL, *v_scope = NULL, *v_new = NULL, *v_free = NULL; Py_ssize_t pos = 0; /* Update scope information for all symbols in this scope */ while (PyDict_Next(symbols, &pos, &name, &v)) { long scope, flags; assert(PyLong_Check(v)); flags = PyLong_AS_LONG(v); if (PySet_Contains(inlined_cells, name)) { flags |= DEF_COMP_CELL; } v_scope = PyDict_GetItemWithError(scopes, name); assert(v_scope && PyLong_Check(v_scope)); scope = PyLong_AS_LONG(v_scope); flags |= (scope << SCOPE_OFFSET); v_new = PyLong_FromLong(flags); if (!v_new) return 0; if (PyDict_SetItem(symbols, name, v_new) < 0) { Py_DECREF(v_new); return 0; } Py_DECREF(v_new); } /* Record not yet resolved free variables from children (if any) */ v_free = PyLong_FromLong(FREE << SCOPE_OFFSET); if (!v_free) return 0; itr = PyObject_GetIter(free); if (itr == NULL) { Py_DECREF(v_free); return 0; } while ((name = PyIter_Next(itr))) { v = PyDict_GetItemWithError(symbols, name); /* Handle symbol that already exists in this scope */ if (v) { /* Handle a free variable in a method of the class that has the same name as a local or global in the class scope. */ if (classflag && PyLong_AS_LONG(v) & (DEF_BOUND | DEF_GLOBAL)) { long flags = PyLong_AS_LONG(v) | DEF_FREE_CLASS; v_new = PyLong_FromLong(flags); if (!v_new) { goto error; } if (PyDict_SetItem(symbols, name, v_new) < 0) { Py_DECREF(v_new); goto error; } Py_DECREF(v_new); } /* It's a cell, or already free in this scope */ Py_DECREF(name); continue; } else if (PyErr_Occurred()) { goto error; } /* Handle global symbol */ if (bound && !PySet_Contains(bound, name)) { Py_DECREF(name); continue; /* it's a global */ } /* Propagate new free symbol up the lexical stack */ if (PyDict_SetItem(symbols, name, v_free) < 0) { goto error; } Py_DECREF(name); } Py_DECREF(itr); Py_DECREF(v_free); return 1; error: Py_XDECREF(v_free); Py_XDECREF(itr); Py_XDECREF(name); return 0; } /* Make final symbol table decisions for block of ste. Arguments: ste -- current symtable entry (input/output) bound -- set of variables bound in enclosing scopes (input). bound is NULL for module blocks. free -- set of free variables in enclosed scopes (output) globals -- set of declared global variables in enclosing scopes (input) The implementation uses two mutually recursive functions, analyze_block() and analyze_child_block(). analyze_block() is responsible for analyzing the individual names defined in a block. analyze_child_block() prepares temporary namespace dictionaries used to evaluated nested blocks. The two functions exist because a child block should see the name bindings of its enclosing blocks, but those bindings should not propagate back to a parent block. */ static int analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free, PyObject *global, PyObject *type_params, PySTEntryObject *class_entry, PyObject **child_free); static int analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, PyObject *global, PyObject *type_params, PySTEntryObject *class_entry) { PyObject *name, *v, *local = NULL, *scopes = NULL, *newbound = NULL; PyObject *newglobal = NULL, *newfree = NULL, *inlined_cells = NULL; PyObject *temp; int success = 0; Py_ssize_t i, pos = 0; local = PySet_New(NULL); /* collect new names bound in block */ if (!local) goto error; scopes = PyDict_New(); /* collect scopes defined for each name */ if (!scopes) goto error; /* Allocate new global, bound and free variable sets. These sets hold the names visible in nested blocks. For ClassBlocks, the bound and global names are initialized before analyzing names, because class bindings aren't visible in methods. For other blocks, they are initialized after names are analyzed. */ /* TODO(jhylton): Package these dicts in a struct so that we can write reasonable helper functions? */ newglobal = PySet_New(NULL); if (!newglobal) goto error; newfree = PySet_New(NULL); if (!newfree) goto error; newbound = PySet_New(NULL); if (!newbound) goto error; inlined_cells = PySet_New(NULL); if (!inlined_cells) goto error; /* Class namespace has no effect on names visible in nested functions, so populate the global and bound sets to be passed to child blocks before analyzing this one. */ if (ste->ste_type == ClassBlock) { /* Pass down known globals */ temp = PyNumber_InPlaceOr(newglobal, global); if (!temp) goto error; Py_DECREF(temp); /* Pass down previously bound symbols */ if (bound) { temp = PyNumber_InPlaceOr(newbound, bound); if (!temp) goto error; Py_DECREF(temp); } } while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) { long flags = PyLong_AS_LONG(v); if (!analyze_name(ste, scopes, name, flags, bound, local, free, global, type_params, class_entry)) goto error; } /* Populate global and bound sets to be passed to children. */ if (ste->ste_type != ClassBlock) { /* Add function locals to bound set */ if (_PyST_IsFunctionLike(ste)) { temp = PyNumber_InPlaceOr(newbound, local); if (!temp) goto error; Py_DECREF(temp); } /* Pass down previously bound symbols */ if (bound) { temp = PyNumber_InPlaceOr(newbound, bound); if (!temp) goto error; Py_DECREF(temp); } /* Pass down known globals */ temp = PyNumber_InPlaceOr(newglobal, global); if (!temp) goto error; Py_DECREF(temp); } else { /* Special-case __class__ and __classdict__ */ if (PySet_Add(newbound, &_Py_ID(__class__)) < 0) goto error; if (PySet_Add(newbound, &_Py_ID(__classdict__)) < 0) goto error; } /* Recursively call analyze_child_block() on each child block. newbound, newglobal now contain the names visible in nested blocks. The free variables in the children will be added to newfree. */ for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) { PyObject *child_free = NULL; PyObject *c = PyList_GET_ITEM(ste->ste_children, i); PySTEntryObject* entry; assert(c && PySTEntry_Check(c)); entry = (PySTEntryObject*)c; PySTEntryObject *new_class_entry = NULL; if (entry->ste_can_see_class_scope) { if (ste->ste_type == ClassBlock) { new_class_entry = ste; } else if (class_entry) { new_class_entry = class_entry; } } // we inline all non-generator-expression comprehensions int inline_comp = entry->ste_comprehension && !entry->ste_generator; if (!analyze_child_block(entry, newbound, newfree, newglobal, type_params, new_class_entry, &child_free)) { goto error; } if (inline_comp) { if (!inline_comprehension(ste, entry, scopes, child_free, inlined_cells)) { Py_DECREF(child_free); goto error; } entry->ste_comp_inlined = 1; } temp = PyNumber_InPlaceOr(newfree, child_free); Py_DECREF(child_free); if (!temp) goto error; Py_DECREF(temp); /* Check if any children have free variables */ if (entry->ste_free || entry->ste_child_free) ste->ste_child_free = 1; } /* Splice children of inlined comprehensions into our children list */ for (i = PyList_GET_SIZE(ste->ste_children) - 1; i >= 0; --i) { PyObject* c = PyList_GET_ITEM(ste->ste_children, i); PySTEntryObject* entry; assert(c && PySTEntry_Check(c)); entry = (PySTEntryObject*)c; if (entry->ste_comp_inlined && PyList_SetSlice(ste->ste_children, i, i + 1, entry->ste_children) < 0) { goto error; } } /* Check if any local variables must be converted to cell variables */ if (_PyST_IsFunctionLike(ste) && !analyze_cells(scopes, newfree, inlined_cells)) goto error; else if (ste->ste_type == ClassBlock && !drop_class_free(ste, newfree)) goto error; /* Records the results of the analysis in the symbol table entry */ if (!update_symbols(ste->ste_symbols, scopes, bound, newfree, inlined_cells, ste->ste_type == ClassBlock)) goto error; temp = PyNumber_InPlaceOr(free, newfree); if (!temp) goto error; Py_DECREF(temp); success = 1; error: Py_XDECREF(scopes); Py_XDECREF(local); Py_XDECREF(newbound); Py_XDECREF(newglobal); Py_XDECREF(newfree); Py_XDECREF(inlined_cells); if (!success) assert(PyErr_Occurred()); return success; } static int analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free, PyObject *global, PyObject *type_params, PySTEntryObject *class_entry, PyObject** child_free) { PyObject *temp_bound = NULL, *temp_global = NULL, *temp_free = NULL; PyObject *temp_type_params = NULL; /* Copy the bound/global/free sets. These sets are used by all blocks enclosed by the current block. The analyze_block() call modifies these sets. */ temp_bound = PySet_New(bound); if (!temp_bound) goto error; temp_free = PySet_New(free); if (!temp_free) goto error; temp_global = PySet_New(global); if (!temp_global) goto error; temp_type_params = PySet_New(type_params); if (!temp_type_params) goto error; if (!analyze_block(entry, temp_bound, temp_free, temp_global, temp_type_params, class_entry)) goto error; *child_free = temp_free; Py_DECREF(temp_bound); Py_DECREF(temp_global); Py_DECREF(temp_type_params); return 1; error: Py_XDECREF(temp_bound); Py_XDECREF(temp_free); Py_XDECREF(temp_global); Py_XDECREF(temp_type_params); return 0; } static int symtable_analyze(struct symtable *st) { PyObject *free, *global, *type_params; int r; free = PySet_New(NULL); if (!free) return 0; global = PySet_New(NULL); if (!global) { Py_DECREF(free); return 0; } type_params = PySet_New(NULL); if (!type_params) { Py_DECREF(free); Py_DECREF(global); return 0; } r = analyze_block(st->st_top, NULL, free, global, type_params, NULL); Py_DECREF(free); Py_DECREF(global); Py_DECREF(type_params); return r; } /* symtable_enter_block() gets a reference via ste_new. This reference is released when the block is exited, via the DECREF in symtable_exit_block(). */ static int symtable_exit_block(struct symtable *st) { Py_ssize_t size; st->st_cur = NULL; size = PyList_GET_SIZE(st->st_stack); if (size) { if (PyList_SetSlice(st->st_stack, size - 1, size, NULL) < 0) return 0; if (--size) st->st_cur = (PySTEntryObject *)PyList_GET_ITEM(st->st_stack, size - 1); } return 1; } static int symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block, void *ast, int lineno, int col_offset, int end_lineno, int end_col_offset) { PySTEntryObject *prev = NULL, *ste; ste = ste_new(st, name, block, ast, lineno, col_offset, end_lineno, end_col_offset); if (ste == NULL) return 0; if (PyList_Append(st->st_stack, (PyObject *)ste) < 0) { Py_DECREF(ste); return 0; } prev = st->st_cur; /* bpo-37757: For now, disallow *all* assignment expressions in the * outermost iterator expression of a comprehension, even those inside * a nested comprehension or a lambda expression. */ if (prev) { ste->ste_comp_iter_expr = prev->ste_comp_iter_expr; } /* The entry is owned by the stack. Borrow it for st_cur. */ Py_DECREF(ste); st->st_cur = ste; /* Annotation blocks shouldn't have any affect on the symbol table since in * the compilation stage, they will all be transformed to strings. They are * only created if future 'annotations' feature is activated. */ if (block == AnnotationBlock) { return 1; } if (block == ModuleBlock) st->st_global = st->st_cur->ste_symbols; if (prev) { if (PyList_Append(prev->ste_children, (PyObject *)ste) < 0) { return 0; } } return 1; } static long symtable_lookup(struct symtable *st, PyObject *name) { PyObject *mangled = _Py_Mangle(st->st_private, name); if (!mangled) return 0; long ret = _PyST_GetSymbol(st->st_cur, mangled); Py_DECREF(mangled); return ret; } static int symtable_add_def_helper(struct symtable *st, PyObject *name, int flag, struct _symtable_entry *ste, int lineno, int col_offset, int end_lineno, int end_col_offset) { PyObject *o; PyObject *dict; long val; PyObject *mangled = _Py_Mangle(st->st_private, name); if (!mangled) return 0; dict = ste->ste_symbols; if ((o = PyDict_GetItemWithError(dict, mangled))) { val = PyLong_AS_LONG(o); if ((flag & DEF_PARAM) && (val & DEF_PARAM)) { /* Is it better to use 'mangled' or 'name' here? */ PyErr_Format(PyExc_SyntaxError, DUPLICATE_ARGUMENT, name); PyErr_RangedSyntaxLocationObject(st->st_filename, lineno, col_offset + 1, end_lineno, end_col_offset + 1); goto error; } if ((flag & DEF_TYPE_PARAM) && (val & DEF_TYPE_PARAM)) { PyErr_Format(PyExc_SyntaxError, DUPLICATE_TYPE_PARAM, name); PyErr_RangedSyntaxLocationObject(st->st_filename, lineno, col_offset + 1, end_lineno, end_col_offset + 1); goto error; } val |= flag; } else if (PyErr_Occurred()) { goto error; } else { val = flag; } if (ste->ste_comp_iter_target) { /* This name is an iteration variable in a comprehension, * so check for a binding conflict with any named expressions. * Otherwise, mark it as an iteration variable so subsequent * named expressions can check for conflicts. */ if (val & (DEF_GLOBAL | DEF_NONLOCAL)) { PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_INNER_LOOP_CONFLICT, name); PyErr_RangedSyntaxLocationObject(st->st_filename, lineno, col_offset + 1, end_lineno, end_col_offset + 1); goto error; } val |= DEF_COMP_ITER; } o = PyLong_FromLong(val); if (o == NULL) goto error; if (PyDict_SetItem(dict, mangled, o) < 0) { Py_DECREF(o); goto error; } Py_DECREF(o); if (flag & DEF_PARAM) { if (PyList_Append(ste->ste_varnames, mangled) < 0) goto error; } else if (flag & DEF_GLOBAL) { /* XXX need to update DEF_GLOBAL for other flags too; perhaps only DEF_FREE_GLOBAL */ val = flag; if ((o = PyDict_GetItemWithError(st->st_global, mangled))) { val |= PyLong_AS_LONG(o); } else if (PyErr_Occurred()) { goto error; } o = PyLong_FromLong(val); if (o == NULL) goto error; if (PyDict_SetItem(st->st_global, mangled, o) < 0) { Py_DECREF(o); goto error; } Py_DECREF(o); } Py_DECREF(mangled); return 1; error: Py_DECREF(mangled); return 0; } static int symtable_add_def(struct symtable *st, PyObject *name, int flag, int lineno, int col_offset, int end_lineno, int end_col_offset) { return symtable_add_def_helper(st, name, flag, st->st_cur, lineno, col_offset, end_lineno, end_col_offset); } static int symtable_enter_type_param_block(struct symtable *st, identifier name, void *ast, int has_defaults, int has_kwdefaults, enum _stmt_kind kind, int lineno, int col_offset, int end_lineno, int end_col_offset) { _Py_block_ty current_type = st->st_cur->ste_type; if(!symtable_enter_block(st, name, TypeParamBlock, ast, lineno, col_offset, end_lineno, end_col_offset)) { return 0; } if (current_type == ClassBlock) { st->st_cur->ste_can_see_class_scope = 1; if (!symtable_add_def(st, &_Py_ID(__classdict__), USE, lineno, col_offset, end_lineno, end_col_offset)) { return 0; } } if (kind == ClassDef_kind) { _Py_DECLARE_STR(type_params, ".type_params"); // It gets "set" when we create the type params tuple and // "used" when we build up the bases. if (!symtable_add_def(st, &_Py_STR(type_params), DEF_LOCAL, lineno, col_offset, end_lineno, end_col_offset)) { return 0; } if (!symtable_add_def(st, &_Py_STR(type_params), USE, lineno, col_offset, end_lineno, end_col_offset)) { return 0; } st->st_private = name; // This is used for setting the generic base _Py_DECLARE_STR(generic_base, ".generic_base"); if (!symtable_add_def(st, &_Py_STR(generic_base), DEF_LOCAL, lineno, col_offset, end_lineno, end_col_offset)) { return 0; } if (!symtable_add_def(st, &_Py_STR(generic_base), USE, lineno, col_offset, end_lineno, end_col_offset)) { return 0; } } if (has_defaults) { _Py_DECLARE_STR(defaults, ".defaults"); if (!symtable_add_def(st, &_Py_STR(defaults), DEF_PARAM, lineno, col_offset, end_lineno, end_col_offset)) { return 0; } } if (has_kwdefaults) { _Py_DECLARE_STR(kwdefaults, ".kwdefaults"); if (!symtable_add_def(st, &_Py_STR(kwdefaults), DEF_PARAM, lineno, col_offset, end_lineno, end_col_offset)) { return 0; } } return 1; } /* VISIT, VISIT_SEQ and VIST_SEQ_TAIL take an ASDL type as their second argument. They use the ASDL name to synthesize the name of the C type and the visit function. VISIT_SEQ_TAIL permits the start of an ASDL sequence to be skipped, which is useful if the first node in the sequence requires special treatment. VISIT_QUIT macro returns the specified value exiting from the function but first adjusts current recursion counter depth. */ #define VISIT_QUIT(ST, X) \ return --(ST)->recursion_depth,(X) #define VISIT(ST, TYPE, V) \ if (!symtable_visit_ ## TYPE((ST), (V))) \ VISIT_QUIT((ST), 0); #define VISIT_SEQ(ST, TYPE, SEQ) { \ int i; \ asdl_ ## TYPE ## _seq *seq = (SEQ); /* avoid variable capture */ \ for (i = 0; i < asdl_seq_LEN(seq); i++) { \ TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \ if (!symtable_visit_ ## TYPE((ST), elt)) \ VISIT_QUIT((ST), 0); \ } \ } #define VISIT_SEQ_TAIL(ST, TYPE, SEQ, START) { \ int i; \ asdl_ ## TYPE ## _seq *seq = (SEQ); /* avoid variable capture */ \ for (i = (START); i < asdl_seq_LEN(seq); i++) { \ TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \ if (!symtable_visit_ ## TYPE((ST), elt)) \ VISIT_QUIT((ST), 0); \ } \ } #define VISIT_SEQ_WITH_NULL(ST, TYPE, SEQ) { \ int i = 0; \ asdl_ ## TYPE ## _seq *seq = (SEQ); /* avoid variable capture */ \ for (i = 0; i < asdl_seq_LEN(seq); i++) { \ TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \ if (!elt) continue; /* can be NULL */ \ if (!symtable_visit_ ## TYPE((ST), elt)) \ VISIT_QUIT((ST), 0); \ } \ } static int symtable_record_directive(struct symtable *st, identifier name, int lineno, int col_offset, int end_lineno, int end_col_offset) { PyObject *data, *mangled; int res; if (!st->st_cur->ste_directives) { st->st_cur->ste_directives = PyList_New(0); if (!st->st_cur->ste_directives) return 0; } mangled = _Py_Mangle(st->st_private, name); if (!mangled) return 0; data = Py_BuildValue("(Niiii)", mangled, lineno, col_offset, end_lineno, end_col_offset); if (!data) return 0; res = PyList_Append(st->st_cur->ste_directives, data); Py_DECREF(data); return res == 0; } static int has_kwonlydefaults(asdl_arg_seq *kwonlyargs, asdl_expr_seq *kw_defaults) { for (int i = 0; i < asdl_seq_LEN(kwonlyargs); i++) { expr_ty default_ = asdl_seq_GET(kw_defaults, i); if (default_) { return 1; } } return 0; } static int symtable_visit_stmt(struct symtable *st, stmt_ty s) { if (++st->recursion_depth > st->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); VISIT_QUIT(st, 0); } switch (s->kind) { case FunctionDef_kind: if (!symtable_add_def(st, s->v.FunctionDef.name, DEF_LOCAL, LOCATION(s))) VISIT_QUIT(st, 0); if (s->v.FunctionDef.args->defaults) VISIT_SEQ(st, expr, s->v.FunctionDef.args->defaults); if (s->v.FunctionDef.args->kw_defaults) VISIT_SEQ_WITH_NULL(st, expr, s->v.FunctionDef.args->kw_defaults); if (s->v.FunctionDef.decorator_list) VISIT_SEQ(st, expr, s->v.FunctionDef.decorator_list); if (asdl_seq_LEN(s->v.FunctionDef.type_params) > 0) { if (!symtable_enter_type_param_block( st, s->v.FunctionDef.name, (void *)s->v.FunctionDef.type_params, s->v.FunctionDef.args->defaults != NULL, has_kwonlydefaults(s->v.FunctionDef.args->kwonlyargs, s->v.FunctionDef.args->kw_defaults), s->kind, LOCATION(s))) { VISIT_QUIT(st, 0); } VISIT_SEQ(st, type_param, s->v.FunctionDef.type_params); } if (!symtable_visit_annotations(st, s, s->v.FunctionDef.args, s->v.FunctionDef.returns)) VISIT_QUIT(st, 0); if (!symtable_enter_block(st, s->v.FunctionDef.name, FunctionBlock, (void *)s, LOCATION(s))) VISIT_QUIT(st, 0); VISIT(st, arguments, s->v.FunctionDef.args); VISIT_SEQ(st, stmt, s->v.FunctionDef.body); if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); if (asdl_seq_LEN(s->v.FunctionDef.type_params) > 0) { if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); } break; case ClassDef_kind: { PyObject *tmp; if (!symtable_add_def(st, s->v.ClassDef.name, DEF_LOCAL, LOCATION(s))) VISIT_QUIT(st, 0); if (s->v.ClassDef.decorator_list) VISIT_SEQ(st, expr, s->v.ClassDef.decorator_list); if (asdl_seq_LEN(s->v.ClassDef.type_params) > 0) { if (!symtable_enter_type_param_block(st, s->v.ClassDef.name, (void *)s->v.ClassDef.type_params, false, false, s->kind, LOCATION(s))) { VISIT_QUIT(st, 0); } VISIT_SEQ(st, type_param, s->v.ClassDef.type_params); } VISIT_SEQ(st, expr, s->v.ClassDef.bases); VISIT_SEQ(st, keyword, s->v.ClassDef.keywords); if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock, (void *)s, s->lineno, s->col_offset, s->end_lineno, s->end_col_offset)) VISIT_QUIT(st, 0); tmp = st->st_private; st->st_private = s->v.ClassDef.name; if (asdl_seq_LEN(s->v.ClassDef.type_params) > 0) { if (!symtable_add_def(st, &_Py_ID(__type_params__), DEF_LOCAL, LOCATION(s))) { VISIT_QUIT(st, 0); } _Py_DECLARE_STR(type_params, ".type_params"); if (!symtable_add_def(st, &_Py_STR(type_params), USE, LOCATION(s))) { VISIT_QUIT(st, 0); } } VISIT_SEQ(st, stmt, s->v.ClassDef.body); st->st_private = tmp; if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); if (asdl_seq_LEN(s->v.ClassDef.type_params) > 0) { if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); } break; } case TypeAlias_kind: { VISIT(st, expr, s->v.TypeAlias.name); assert(s->v.TypeAlias.name->kind == Name_kind); PyObject *name = s->v.TypeAlias.name->v.Name.id; int is_in_class = st->st_cur->ste_type == ClassBlock; int is_generic = asdl_seq_LEN(s->v.TypeAlias.type_params) > 0; if (is_generic) { if (!symtable_enter_type_param_block( st, name, (void *)s->v.TypeAlias.type_params, false, false, s->kind, LOCATION(s))) { VISIT_QUIT(st, 0); } VISIT_SEQ(st, type_param, s->v.TypeAlias.type_params); } if (!symtable_enter_block(st, name, TypeAliasBlock, (void *)s, LOCATION(s))) VISIT_QUIT(st, 0); st->st_cur->ste_can_see_class_scope = is_in_class; if (is_in_class && !symtable_add_def(st, &_Py_ID(__classdict__), USE, LOCATION(s->v.TypeAlias.value))) { VISIT_QUIT(st, 0); } VISIT(st, expr, s->v.TypeAlias.value); if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); if (is_generic) { if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); } break; } case Return_kind: if (s->v.Return.value) { VISIT(st, expr, s->v.Return.value); st->st_cur->ste_returns_value = 1; } break; case Delete_kind: VISIT_SEQ(st, expr, s->v.Delete.targets); break; case Assign_kind: VISIT_SEQ(st, expr, s->v.Assign.targets); VISIT(st, expr, s->v.Assign.value); break; case AnnAssign_kind: if (s->v.AnnAssign.target->kind == Name_kind) { expr_ty e_name = s->v.AnnAssign.target; long cur = symtable_lookup(st, e_name->v.Name.id); if (cur < 0) { VISIT_QUIT(st, 0); } if ((cur & (DEF_GLOBAL | DEF_NONLOCAL)) && (st->st_cur->ste_symbols != st->st_global) && s->v.AnnAssign.simple) { PyErr_Format(PyExc_SyntaxError, cur & DEF_GLOBAL ? GLOBAL_ANNOT : NONLOCAL_ANNOT, e_name->v.Name.id); PyErr_RangedSyntaxLocationObject(st->st_filename, s->lineno, s->col_offset + 1, s->end_lineno, s->end_col_offset + 1); VISIT_QUIT(st, 0); } if (s->v.AnnAssign.simple && !symtable_add_def(st, e_name->v.Name.id, DEF_ANNOT | DEF_LOCAL, LOCATION(e_name))) { VISIT_QUIT(st, 0); } else { if (s->v.AnnAssign.value && !symtable_add_def(st, e_name->v.Name.id, DEF_LOCAL, LOCATION(e_name))) { VISIT_QUIT(st, 0); } } } else { VISIT(st, expr, s->v.AnnAssign.target); } if (!symtable_visit_annotation(st, s->v.AnnAssign.annotation)) { VISIT_QUIT(st, 0); } if (s->v.AnnAssign.value) { VISIT(st, expr, s->v.AnnAssign.value); } break; case AugAssign_kind: VISIT(st, expr, s->v.AugAssign.target); VISIT(st, expr, s->v.AugAssign.value); break; case For_kind: VISIT(st, expr, s->v.For.target); VISIT(st, expr, s->v.For.iter); VISIT_SEQ(st, stmt, s->v.For.body); if (s->v.For.orelse) VISIT_SEQ(st, stmt, s->v.For.orelse); break; case While_kind: VISIT(st, expr, s->v.While.test); VISIT_SEQ(st, stmt, s->v.While.body); if (s->v.While.orelse) VISIT_SEQ(st, stmt, s->v.While.orelse); break; case If_kind: /* XXX if 0: and lookup_yield() hacks */ VISIT(st, expr, s->v.If.test); VISIT_SEQ(st, stmt, s->v.If.body); if (s->v.If.orelse) VISIT_SEQ(st, stmt, s->v.If.orelse); break; case Match_kind: VISIT(st, expr, s->v.Match.subject); VISIT_SEQ(st, match_case, s->v.Match.cases); break; case Raise_kind: if (s->v.Raise.exc) { VISIT(st, expr, s->v.Raise.exc); if (s->v.Raise.cause) { VISIT(st, expr, s->v.Raise.cause); } } break; case Try_kind: VISIT_SEQ(st, stmt, s->v.Try.body); VISIT_SEQ(st, stmt, s->v.Try.orelse); VISIT_SEQ(st, excepthandler, s->v.Try.handlers); VISIT_SEQ(st, stmt, s->v.Try.finalbody); break; case TryStar_kind: VISIT_SEQ(st, stmt, s->v.TryStar.body); VISIT_SEQ(st, stmt, s->v.TryStar.orelse); VISIT_SEQ(st, excepthandler, s->v.TryStar.handlers); VISIT_SEQ(st, stmt, s->v.TryStar.finalbody); break; case Assert_kind: VISIT(st, expr, s->v.Assert.test); if (s->v.Assert.msg) VISIT(st, expr, s->v.Assert.msg); break; case Import_kind: VISIT_SEQ(st, alias, s->v.Import.names); break; case ImportFrom_kind: VISIT_SEQ(st, alias, s->v.ImportFrom.names); break; case Global_kind: { int i; asdl_identifier_seq *seq = s->v.Global.names; for (i = 0; i < asdl_seq_LEN(seq); i++) { identifier name = (identifier)asdl_seq_GET(seq, i); long cur = symtable_lookup(st, name); if (cur < 0) VISIT_QUIT(st, 0); if (cur & (DEF_PARAM | DEF_LOCAL | USE | DEF_ANNOT)) { const char* msg; if (cur & DEF_PARAM) { msg = GLOBAL_PARAM; } else if (cur & USE) { msg = GLOBAL_AFTER_USE; } else if (cur & DEF_ANNOT) { msg = GLOBAL_ANNOT; } else { /* DEF_LOCAL */ msg = GLOBAL_AFTER_ASSIGN; } PyErr_Format(PyExc_SyntaxError, msg, name); PyErr_RangedSyntaxLocationObject(st->st_filename, s->lineno, s->col_offset + 1, s->end_lineno, s->end_col_offset + 1); VISIT_QUIT(st, 0); } if (!symtable_add_def(st, name, DEF_GLOBAL, LOCATION(s))) VISIT_QUIT(st, 0); if (!symtable_record_directive(st, name, s->lineno, s->col_offset, s->end_lineno, s->end_col_offset)) VISIT_QUIT(st, 0); } break; } case Nonlocal_kind: { int i; asdl_identifier_seq *seq = s->v.Nonlocal.names; for (i = 0; i < asdl_seq_LEN(seq); i++) { identifier name = (identifier)asdl_seq_GET(seq, i); long cur = symtable_lookup(st, name); if (cur < 0) VISIT_QUIT(st, 0); if (cur & (DEF_PARAM | DEF_LOCAL | USE | DEF_ANNOT)) { const char* msg; if (cur & DEF_PARAM) { msg = NONLOCAL_PARAM; } else if (cur & USE) { msg = NONLOCAL_AFTER_USE; } else if (cur & DEF_ANNOT) { msg = NONLOCAL_ANNOT; } else { /* DEF_LOCAL */ msg = NONLOCAL_AFTER_ASSIGN; } PyErr_Format(PyExc_SyntaxError, msg, name); PyErr_RangedSyntaxLocationObject(st->st_filename, s->lineno, s->col_offset + 1, s->end_lineno, s->end_col_offset + 1); VISIT_QUIT(st, 0); } if (!symtable_add_def(st, name, DEF_NONLOCAL, LOCATION(s))) VISIT_QUIT(st, 0); if (!symtable_record_directive(st, name, s->lineno, s->col_offset, s->end_lineno, s->end_col_offset)) VISIT_QUIT(st, 0); } break; } case Expr_kind: VISIT(st, expr, s->v.Expr.value); break; case Pass_kind: case Break_kind: case Continue_kind: /* nothing to do here */ break; case With_kind: VISIT_SEQ(st, withitem, s->v.With.items); VISIT_SEQ(st, stmt, s->v.With.body); break; case AsyncFunctionDef_kind: if (!symtable_add_def(st, s->v.AsyncFunctionDef.name, DEF_LOCAL, LOCATION(s))) VISIT_QUIT(st, 0); if (s->v.AsyncFunctionDef.args->defaults) VISIT_SEQ(st, expr, s->v.AsyncFunctionDef.args->defaults); if (s->v.AsyncFunctionDef.args->kw_defaults) VISIT_SEQ_WITH_NULL(st, expr, s->v.AsyncFunctionDef.args->kw_defaults); if (s->v.AsyncFunctionDef.decorator_list) VISIT_SEQ(st, expr, s->v.AsyncFunctionDef.decorator_list); if (asdl_seq_LEN(s->v.AsyncFunctionDef.type_params) > 0) { if (!symtable_enter_type_param_block( st, s->v.AsyncFunctionDef.name, (void *)s->v.AsyncFunctionDef.type_params, s->v.AsyncFunctionDef.args->defaults != NULL, has_kwonlydefaults(s->v.AsyncFunctionDef.args->kwonlyargs, s->v.AsyncFunctionDef.args->kw_defaults), s->kind, LOCATION(s))) { VISIT_QUIT(st, 0); } VISIT_SEQ(st, type_param, s->v.AsyncFunctionDef.type_params); } if (!symtable_visit_annotations(st, s, s->v.AsyncFunctionDef.args, s->v.AsyncFunctionDef.returns)) VISIT_QUIT(st, 0); if (!symtable_enter_block(st, s->v.AsyncFunctionDef.name, FunctionBlock, (void *)s, s->lineno, s->col_offset, s->end_lineno, s->end_col_offset)) VISIT_QUIT(st, 0); st->st_cur->ste_coroutine = 1; VISIT(st, arguments, s->v.AsyncFunctionDef.args); VISIT_SEQ(st, stmt, s->v.AsyncFunctionDef.body); if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); if (asdl_seq_LEN(s->v.AsyncFunctionDef.type_params) > 0) { if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); } break; case AsyncWith_kind: VISIT_SEQ(st, withitem, s->v.AsyncWith.items); VISIT_SEQ(st, stmt, s->v.AsyncWith.body); break; case AsyncFor_kind: VISIT(st, expr, s->v.AsyncFor.target); VISIT(st, expr, s->v.AsyncFor.iter); VISIT_SEQ(st, stmt, s->v.AsyncFor.body); if (s->v.AsyncFor.orelse) VISIT_SEQ(st, stmt, s->v.AsyncFor.orelse); break; } VISIT_QUIT(st, 1); } static int symtable_extend_namedexpr_scope(struct symtable *st, expr_ty e) { assert(st->st_stack); assert(e->kind == Name_kind); PyObject *target_name = e->v.Name.id; Py_ssize_t i, size; struct _symtable_entry *ste; size = PyList_GET_SIZE(st->st_stack); assert(size); /* Iterate over the stack in reverse and add to the nearest adequate scope */ for (i = size - 1; i >= 0; i--) { ste = (struct _symtable_entry *) PyList_GET_ITEM(st->st_stack, i); /* If we find a comprehension scope, check for a target * binding conflict with iteration variables, otherwise skip it */ if (ste->ste_comprehension) { long target_in_scope = _PyST_GetSymbol(ste, target_name); if ((target_in_scope & DEF_COMP_ITER) && (target_in_scope & DEF_LOCAL)) { PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_CONFLICT, target_name); PyErr_RangedSyntaxLocationObject(st->st_filename, e->lineno, e->col_offset + 1, e->end_lineno, e->end_col_offset + 1); VISIT_QUIT(st, 0); } continue; } /* If we find a FunctionBlock entry, add as GLOBAL/LOCAL or NONLOCAL/LOCAL */ if (ste->ste_type == FunctionBlock) { long target_in_scope = _PyST_GetSymbol(ste, target_name); if (target_in_scope & DEF_GLOBAL) { if (!symtable_add_def(st, target_name, DEF_GLOBAL, LOCATION(e))) VISIT_QUIT(st, 0); } else { if (!symtable_add_def(st, target_name, DEF_NONLOCAL, LOCATION(e))) VISIT_QUIT(st, 0); } if (!symtable_record_directive(st, target_name, LOCATION(e))) VISIT_QUIT(st, 0); return symtable_add_def_helper(st, target_name, DEF_LOCAL, ste, LOCATION(e)); } /* If we find a ModuleBlock entry, add as GLOBAL */ if (ste->ste_type == ModuleBlock) { if (!symtable_add_def(st, target_name, DEF_GLOBAL, LOCATION(e))) VISIT_QUIT(st, 0); if (!symtable_record_directive(st, target_name, LOCATION(e))) VISIT_QUIT(st, 0); return symtable_add_def_helper(st, target_name, DEF_GLOBAL, ste, LOCATION(e)); } /* Disallow usage in ClassBlock and type scopes */ if (ste->ste_type == ClassBlock || ste->ste_type == TypeParamBlock || ste->ste_type == TypeAliasBlock || ste->ste_type == TypeVarBoundBlock) { switch (ste->ste_type) { case ClassBlock: PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_IN_CLASS); break; case TypeParamBlock: PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_IN_TYPEPARAM); break; case TypeAliasBlock: PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_IN_TYPEALIAS); break; case TypeVarBoundBlock: PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_IN_TYPEVAR_BOUND); break; default: Py_UNREACHABLE(); } PyErr_RangedSyntaxLocationObject(st->st_filename, e->lineno, e->col_offset + 1, e->end_lineno, e->end_col_offset + 1); VISIT_QUIT(st, 0); } } /* We should always find either a function-like block, ModuleBlock or ClassBlock and should never fall to this case */ Py_UNREACHABLE(); return 0; } static int symtable_handle_namedexpr(struct symtable *st, expr_ty e) { if (st->st_cur->ste_comp_iter_expr > 0) { /* Assignment isn't allowed in a comprehension iterable expression */ PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_ITER_EXPR); PyErr_RangedSyntaxLocationObject(st->st_filename, e->lineno, e->col_offset + 1, e->end_lineno, e->end_col_offset + 1); return 0; } if (st->st_cur->ste_comprehension) { /* Inside a comprehension body, so find the right target scope */ if (!symtable_extend_namedexpr_scope(st, e->v.NamedExpr.target)) return 0; } VISIT(st, expr, e->v.NamedExpr.value); VISIT(st, expr, e->v.NamedExpr.target); return 1; } static int symtable_visit_expr(struct symtable *st, expr_ty e) { if (++st->recursion_depth > st->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); VISIT_QUIT(st, 0); } switch (e->kind) { case NamedExpr_kind: if (!symtable_raise_if_annotation_block(st, "named expression", e)) { VISIT_QUIT(st, 0); } if(!symtable_handle_namedexpr(st, e)) VISIT_QUIT(st, 0); break; case BoolOp_kind: VISIT_SEQ(st, expr, e->v.BoolOp.values); break; case BinOp_kind: VISIT(st, expr, e->v.BinOp.left); VISIT(st, expr, e->v.BinOp.right); break; case UnaryOp_kind: VISIT(st, expr, e->v.UnaryOp.operand); break; case Lambda_kind: { if (e->v.Lambda.args->defaults) VISIT_SEQ(st, expr, e->v.Lambda.args->defaults); if (e->v.Lambda.args->kw_defaults) VISIT_SEQ_WITH_NULL(st, expr, e->v.Lambda.args->kw_defaults); if (!symtable_enter_block(st, &_Py_ID(lambda), FunctionBlock, (void *)e, e->lineno, e->col_offset, e->end_lineno, e->end_col_offset)) VISIT_QUIT(st, 0); VISIT(st, arguments, e->v.Lambda.args); VISIT(st, expr, e->v.Lambda.body); if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); break; } case IfExp_kind: VISIT(st, expr, e->v.IfExp.test); VISIT(st, expr, e->v.IfExp.body); VISIT(st, expr, e->v.IfExp.orelse); break; case Dict_kind: VISIT_SEQ_WITH_NULL(st, expr, e->v.Dict.keys); VISIT_SEQ(st, expr, e->v.Dict.values); break; case Set_kind: VISIT_SEQ(st, expr, e->v.Set.elts); break; case GeneratorExp_kind: if (!symtable_visit_genexp(st, e)) VISIT_QUIT(st, 0); break; case ListComp_kind: if (!symtable_visit_listcomp(st, e)) VISIT_QUIT(st, 0); break; case SetComp_kind: if (!symtable_visit_setcomp(st, e)) VISIT_QUIT(st, 0); break; case DictComp_kind: if (!symtable_visit_dictcomp(st, e)) VISIT_QUIT(st, 0); break; case Yield_kind: if (!symtable_raise_if_annotation_block(st, "yield expression", e)) { VISIT_QUIT(st, 0); } if (e->v.Yield.value) VISIT(st, expr, e->v.Yield.value); st->st_cur->ste_generator = 1; if (st->st_cur->ste_comprehension) { return symtable_raise_if_comprehension_block(st, e); } break; case YieldFrom_kind: if (!symtable_raise_if_annotation_block(st, "yield expression", e)) { VISIT_QUIT(st, 0); } VISIT(st, expr, e->v.YieldFrom.value); st->st_cur->ste_generator = 1; if (st->st_cur->ste_comprehension) { return symtable_raise_if_comprehension_block(st, e); } break; case Await_kind: if (!symtable_raise_if_annotation_block(st, "await expression", e)) { VISIT_QUIT(st, 0); } VISIT(st, expr, e->v.Await.value); st->st_cur->ste_coroutine = 1; break; case Compare_kind: VISIT(st, expr, e->v.Compare.left); VISIT_SEQ(st, expr, e->v.Compare.comparators); break; case Call_kind: VISIT(st, expr, e->v.Call.func); VISIT_SEQ(st, expr, e->v.Call.args); VISIT_SEQ_WITH_NULL(st, keyword, e->v.Call.keywords); break; case FormattedValue_kind: VISIT(st, expr, e->v.FormattedValue.value); if (e->v.FormattedValue.format_spec) VISIT(st, expr, e->v.FormattedValue.format_spec); break; case JoinedStr_kind: VISIT_SEQ(st, expr, e->v.JoinedStr.values); break; case Constant_kind: /* Nothing to do here. */ break; /* The following exprs can be assignment targets. */ case Attribute_kind: VISIT(st, expr, e->v.Attribute.value); break; case Subscript_kind: VISIT(st, expr, e->v.Subscript.value); VISIT(st, expr, e->v.Subscript.slice); break; case Starred_kind: VISIT(st, expr, e->v.Starred.value); break; case Slice_kind: if (e->v.Slice.lower) VISIT(st, expr, e->v.Slice.lower) if (e->v.Slice.upper) VISIT(st, expr, e->v.Slice.upper) if (e->v.Slice.step) VISIT(st, expr, e->v.Slice.step) break; case Name_kind: if (!symtable_add_def(st, e->v.Name.id, e->v.Name.ctx == Load ? USE : DEF_LOCAL, LOCATION(e))) VISIT_QUIT(st, 0); /* Special-case super: it counts as a use of __class__ */ if (e->v.Name.ctx == Load && _PyST_IsFunctionLike(st->st_cur) && _PyUnicode_EqualToASCIIString(e->v.Name.id, "super")) { if (!symtable_add_def(st, &_Py_ID(__class__), USE, LOCATION(e))) VISIT_QUIT(st, 0); } break; /* child nodes of List and Tuple will have expr_context set */ case List_kind: VISIT_SEQ(st, expr, e->v.List.elts); break; case Tuple_kind: VISIT_SEQ(st, expr, e->v.Tuple.elts); break; } VISIT_QUIT(st, 1); } static int symtable_visit_type_param(struct symtable *st, type_param_ty tp) { if (++st->recursion_depth > st->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); VISIT_QUIT(st, 0); } switch(tp->kind) { case TypeVar_kind: if (!symtable_add_def(st, tp->v.TypeVar.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp))) VISIT_QUIT(st, 0); if (tp->v.TypeVar.bound) { int is_in_class = st->st_cur->ste_can_see_class_scope; if (!symtable_enter_block(st, tp->v.TypeVar.name, TypeVarBoundBlock, (void *)tp, LOCATION(tp))) VISIT_QUIT(st, 0); st->st_cur->ste_can_see_class_scope = is_in_class; if (is_in_class && !symtable_add_def(st, &_Py_ID(__classdict__), USE, LOCATION(tp->v.TypeVar.bound))) { VISIT_QUIT(st, 0); } VISIT(st, expr, tp->v.TypeVar.bound); if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); } break; case TypeVarTuple_kind: if (!symtable_add_def(st, tp->v.TypeVarTuple.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp))) VISIT_QUIT(st, 0); break; case ParamSpec_kind: if (!symtable_add_def(st, tp->v.ParamSpec.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp))) VISIT_QUIT(st, 0); break; } VISIT_QUIT(st, 1); } static int symtable_visit_pattern(struct symtable *st, pattern_ty p) { if (++st->recursion_depth > st->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); VISIT_QUIT(st, 0); } switch (p->kind) { case MatchValue_kind: VISIT(st, expr, p->v.MatchValue.value); break; case MatchSingleton_kind: /* Nothing to do here. */ break; case MatchSequence_kind: VISIT_SEQ(st, pattern, p->v.MatchSequence.patterns); break; case MatchStar_kind: if (p->v.MatchStar.name) { symtable_add_def(st, p->v.MatchStar.name, DEF_LOCAL, LOCATION(p)); } break; case MatchMapping_kind: VISIT_SEQ(st, expr, p->v.MatchMapping.keys); VISIT_SEQ(st, pattern, p->v.MatchMapping.patterns); if (p->v.MatchMapping.rest) { symtable_add_def(st, p->v.MatchMapping.rest, DEF_LOCAL, LOCATION(p)); } break; case MatchClass_kind: VISIT(st, expr, p->v.MatchClass.cls); VISIT_SEQ(st, pattern, p->v.MatchClass.patterns); VISIT_SEQ(st, pattern, p->v.MatchClass.kwd_patterns); break; case MatchAs_kind: if (p->v.MatchAs.pattern) { VISIT(st, pattern, p->v.MatchAs.pattern); } if (p->v.MatchAs.name) { symtable_add_def(st, p->v.MatchAs.name, DEF_LOCAL, LOCATION(p)); } break; case MatchOr_kind: VISIT_SEQ(st, pattern, p->v.MatchOr.patterns); break; } VISIT_QUIT(st, 1); } static int symtable_implicit_arg(struct symtable *st, int pos) { PyObject *id = PyUnicode_FromFormat(".%d", pos); if (id == NULL) return 0; if (!symtable_add_def(st, id, DEF_PARAM, ST_LOCATION(st->st_cur))) { Py_DECREF(id); return 0; } Py_DECREF(id); return 1; } static int symtable_visit_params(struct symtable *st, asdl_arg_seq *args) { int i; if (!args) return -1; for (i = 0; i < asdl_seq_LEN(args); i++) { arg_ty arg = (arg_ty)asdl_seq_GET(args, i); if (!symtable_add_def(st, arg->arg, DEF_PARAM, LOCATION(arg))) return 0; } return 1; } static int symtable_visit_annotation(struct symtable *st, expr_ty annotation) { int future_annotations = st->st_future->ff_features & CO_FUTURE_ANNOTATIONS; if (future_annotations && !symtable_enter_block(st, &_Py_ID(_annotation), AnnotationBlock, (void *)annotation, annotation->lineno, annotation->col_offset, annotation->end_lineno, annotation->end_col_offset)) { VISIT_QUIT(st, 0); } VISIT(st, expr, annotation); if (future_annotations && !symtable_exit_block(st)) { VISIT_QUIT(st, 0); } return 1; } static int symtable_visit_argannotations(struct symtable *st, asdl_arg_seq *args) { int i; if (!args) return -1; for (i = 0; i < asdl_seq_LEN(args); i++) { arg_ty arg = (arg_ty)asdl_seq_GET(args, i); if (arg->annotation) VISIT(st, expr, arg->annotation); } return 1; } static int symtable_visit_annotations(struct symtable *st, stmt_ty o, arguments_ty a, expr_ty returns) { int future_annotations = st->st_future->ff_features & CO_FUTURE_ANNOTATIONS; if (future_annotations && !symtable_enter_block(st, &_Py_ID(_annotation), AnnotationBlock, (void *)o, o->lineno, o->col_offset, o->end_lineno, o->end_col_offset)) { VISIT_QUIT(st, 0); } if (a->posonlyargs && !symtable_visit_argannotations(st, a->posonlyargs)) return 0; if (a->args && !symtable_visit_argannotations(st, a->args)) return 0; if (a->vararg && a->vararg->annotation) VISIT(st, expr, a->vararg->annotation); if (a->kwarg && a->kwarg->annotation) VISIT(st, expr, a->kwarg->annotation); if (a->kwonlyargs && !symtable_visit_argannotations(st, a->kwonlyargs)) return 0; if (future_annotations && !symtable_exit_block(st)) { VISIT_QUIT(st, 0); } if (returns && !symtable_visit_annotation(st, returns)) { VISIT_QUIT(st, 0); } return 1; } static int symtable_visit_arguments(struct symtable *st, arguments_ty a) { /* skip default arguments inside function block XXX should ast be different? */ if (a->posonlyargs && !symtable_visit_params(st, a->posonlyargs)) return 0; if (a->args && !symtable_visit_params(st, a->args)) return 0; if (a->kwonlyargs && !symtable_visit_params(st, a->kwonlyargs)) return 0; if (a->vararg) { if (!symtable_add_def(st, a->vararg->arg, DEF_PARAM, LOCATION(a->vararg))) return 0; st->st_cur->ste_varargs = 1; } if (a->kwarg) { if (!symtable_add_def(st, a->kwarg->arg, DEF_PARAM, LOCATION(a->kwarg))) return 0; st->st_cur->ste_varkeywords = 1; } return 1; } static int symtable_visit_excepthandler(struct symtable *st, excepthandler_ty eh) { if (eh->v.ExceptHandler.type) VISIT(st, expr, eh->v.ExceptHandler.type); if (eh->v.ExceptHandler.name) if (!symtable_add_def(st, eh->v.ExceptHandler.name, DEF_LOCAL, LOCATION(eh))) return 0; VISIT_SEQ(st, stmt, eh->v.ExceptHandler.body); return 1; } static int symtable_visit_withitem(struct symtable *st, withitem_ty item) { VISIT(st, expr, item->context_expr); if (item->optional_vars) { VISIT(st, expr, item->optional_vars); } return 1; } static int symtable_visit_match_case(struct symtable *st, match_case_ty m) { VISIT(st, pattern, m->pattern); if (m->guard) { VISIT(st, expr, m->guard); } VISIT_SEQ(st, stmt, m->body); return 1; } static int symtable_visit_alias(struct symtable *st, alias_ty a) { /* Compute store_name, the name actually bound by the import operation. It is different than a->name when a->name is a dotted package name (e.g. spam.eggs) */ PyObject *store_name; PyObject *name = (a->asname == NULL) ? a->name : a->asname; Py_ssize_t dot = PyUnicode_FindChar(name, '.', 0, PyUnicode_GET_LENGTH(name), 1); if (dot != -1) { store_name = PyUnicode_Substring(name, 0, dot); if (!store_name) return 0; } else { store_name = Py_NewRef(name); } if (!_PyUnicode_EqualToASCIIString(name, "*")) { int r = symtable_add_def(st, store_name, DEF_IMPORT, LOCATION(a)); Py_DECREF(store_name); return r; } else { if (st->st_cur->ste_type != ModuleBlock) { int lineno = a->lineno; int col_offset = a->col_offset; int end_lineno = a->end_lineno; int end_col_offset = a->end_col_offset; PyErr_SetString(PyExc_SyntaxError, IMPORT_STAR_WARNING); PyErr_RangedSyntaxLocationObject(st->st_filename, lineno, col_offset + 1, end_lineno, end_col_offset + 1); Py_DECREF(store_name); return 0; } Py_DECREF(store_name); return 1; } } static int symtable_visit_comprehension(struct symtable *st, comprehension_ty lc) { st->st_cur->ste_comp_iter_target = 1; VISIT(st, expr, lc->target); st->st_cur->ste_comp_iter_target = 0; st->st_cur->ste_comp_iter_expr++; VISIT(st, expr, lc->iter); st->st_cur->ste_comp_iter_expr--; VISIT_SEQ(st, expr, lc->ifs); if (lc->is_async) { st->st_cur->ste_coroutine = 1; } return 1; } static int symtable_visit_keyword(struct symtable *st, keyword_ty k) { VISIT(st, expr, k->value); return 1; } static int symtable_handle_comprehension(struct symtable *st, expr_ty e, identifier scope_name, asdl_comprehension_seq *generators, expr_ty elt, expr_ty value) { int is_generator = (e->kind == GeneratorExp_kind); comprehension_ty outermost = ((comprehension_ty) asdl_seq_GET(generators, 0)); /* Outermost iterator is evaluated in current scope */ st->st_cur->ste_comp_iter_expr++; VISIT(st, expr, outermost->iter); st->st_cur->ste_comp_iter_expr--; /* Create comprehension scope for the rest */ if (!scope_name || !symtable_enter_block(st, scope_name, FunctionBlock, (void *)e, e->lineno, e->col_offset, e->end_lineno, e->end_col_offset)) { return 0; } switch(e->kind) { case ListComp_kind: st->st_cur->ste_comprehension = ListComprehension; break; case SetComp_kind: st->st_cur->ste_comprehension = SetComprehension; break; case DictComp_kind: st->st_cur->ste_comprehension = DictComprehension; break; default: st->st_cur->ste_comprehension = GeneratorExpression; break; } if (outermost->is_async) { st->st_cur->ste_coroutine = 1; } /* Outermost iter is received as an argument */ if (!symtable_implicit_arg(st, 0)) { symtable_exit_block(st); return 0; } /* Visit iteration variable target, and mark them as such */ st->st_cur->ste_comp_iter_target = 1; VISIT(st, expr, outermost->target); st->st_cur->ste_comp_iter_target = 0; /* Visit the rest of the comprehension body */ VISIT_SEQ(st, expr, outermost->ifs); VISIT_SEQ_TAIL(st, comprehension, generators, 1); if (value) VISIT(st, expr, value); VISIT(st, expr, elt); st->st_cur->ste_generator = is_generator; int is_async = st->st_cur->ste_coroutine && !is_generator; if (!symtable_exit_block(st)) { return 0; } if (is_async) { st->st_cur->ste_coroutine = 1; } return 1; } static int symtable_visit_genexp(struct symtable *st, expr_ty e) { return symtable_handle_comprehension(st, e, &_Py_ID(genexpr), e->v.GeneratorExp.generators, e->v.GeneratorExp.elt, NULL); } static int symtable_visit_listcomp(struct symtable *st, expr_ty e) { return symtable_handle_comprehension(st, e, &_Py_ID(listcomp), e->v.ListComp.generators, e->v.ListComp.elt, NULL); } static int symtable_visit_setcomp(struct symtable *st, expr_ty e) { return symtable_handle_comprehension(st, e, &_Py_ID(setcomp), e->v.SetComp.generators, e->v.SetComp.elt, NULL); } static int symtable_visit_dictcomp(struct symtable *st, expr_ty e) { return symtable_handle_comprehension(st, e, &_Py_ID(dictcomp), e->v.DictComp.generators, e->v.DictComp.key, e->v.DictComp.value); } static int symtable_raise_if_annotation_block(struct symtable *st, const char *name, expr_ty e) { enum _block_type type = st->st_cur->ste_type; if (type == AnnotationBlock) PyErr_Format(PyExc_SyntaxError, ANNOTATION_NOT_ALLOWED, name); else if (type == TypeVarBoundBlock) PyErr_Format(PyExc_SyntaxError, TYPEVAR_BOUND_NOT_ALLOWED, name); else if (type == TypeAliasBlock) PyErr_Format(PyExc_SyntaxError, TYPEALIAS_NOT_ALLOWED, name); else if (type == TypeParamBlock) PyErr_Format(PyExc_SyntaxError, TYPEPARAM_NOT_ALLOWED, name); else return 1; PyErr_RangedSyntaxLocationObject(st->st_filename, e->lineno, e->col_offset + 1, e->end_lineno, e->end_col_offset + 1); return 0; } static int symtable_raise_if_comprehension_block(struct symtable *st, expr_ty e) { _Py_comprehension_ty type = st->st_cur->ste_comprehension; PyErr_SetString(PyExc_SyntaxError, (type == ListComprehension) ? "'yield' inside list comprehension" : (type == SetComprehension) ? "'yield' inside set comprehension" : (type == DictComprehension) ? "'yield' inside dict comprehension" : "'yield' inside generator expression"); PyErr_RangedSyntaxLocationObject(st->st_filename, e->lineno, e->col_offset + 1, e->end_lineno, e->end_col_offset + 1); VISIT_QUIT(st, 0); } struct symtable * _Py_SymtableStringObjectFlags(const char *str, PyObject *filename, int start, PyCompilerFlags *flags) { struct symtable *st; mod_ty mod; PyArena *arena; arena = _PyArena_New(); if (arena == NULL) return NULL; mod = _PyParser_ASTFromString(str, filename, start, flags, arena); if (mod == NULL) { _PyArena_Free(arena); return NULL; } PyFutureFeatures future; if (!_PyFuture_FromAST(mod, filename, &future)) { _PyArena_Free(arena); return NULL; } future.ff_features |= flags->cf_flags; st = _PySymtable_Build(mod, filename, &future); _PyArena_Free(arena); return st; } PyObject * _Py_Mangle(PyObject *privateobj, PyObject *ident) { /* Name mangling: __private becomes _classname__private. This is independent from how the name is used. */ if (privateobj == NULL || !PyUnicode_Check(privateobj) || PyUnicode_READ_CHAR(ident, 0) != '_' || PyUnicode_READ_CHAR(ident, 1) != '_') { return Py_NewRef(ident); } size_t nlen = PyUnicode_GET_LENGTH(ident); size_t plen = PyUnicode_GET_LENGTH(privateobj); /* Don't mangle __id__ or names with dots. The only time a name with a dot can occur is when we are compiling an import statement that has a package name. TODO(jhylton): Decide whether we want to support mangling of the module name, e.g. __M.X. */ if ((PyUnicode_READ_CHAR(ident, nlen-1) == '_' && PyUnicode_READ_CHAR(ident, nlen-2) == '_') || PyUnicode_FindChar(ident, '.', 0, nlen, 1) != -1) { return Py_NewRef(ident); /* Don't mangle __whatever__ */ } /* Strip leading underscores from class name */ size_t ipriv = 0; while (PyUnicode_READ_CHAR(privateobj, ipriv) == '_') { ipriv++; } if (ipriv == plen) { return Py_NewRef(ident); /* Don't mangle if class is just underscores */ } plen -= ipriv; if (plen + nlen >= PY_SSIZE_T_MAX - 1) { PyErr_SetString(PyExc_OverflowError, "private identifier too large to be mangled"); return NULL; } Py_UCS4 maxchar = PyUnicode_MAX_CHAR_VALUE(ident); if (PyUnicode_MAX_CHAR_VALUE(privateobj) > maxchar) { maxchar = PyUnicode_MAX_CHAR_VALUE(privateobj); } PyObject *result = PyUnicode_New(1 + nlen + plen, maxchar); if (!result) { return NULL; } /* ident = "_" + priv[ipriv:] + ident # i.e. 1+plen+nlen bytes */ PyUnicode_WRITE(PyUnicode_KIND(result), PyUnicode_DATA(result), 0, '_'); if (PyUnicode_CopyCharacters(result, 1, privateobj, ipriv, plen) < 0) { Py_DECREF(result); return NULL; } if (PyUnicode_CopyCharacters(result, plen+1, ident, 0, nlen) < 0) { Py_DECREF(result); return NULL; } assert(_PyUnicode_CheckConsistency(result, 1)); return result; } ================================================ FILE: SySModule.c ================================================ /* System module */ /* Various bits of information used by the interpreter are collected in module 'sys'. Function member: - exit(sts): raise SystemExit Data members: - stdin, stdout, stderr: standard file objects - modules: the table of modules (dictionary) - path: module search path (list of strings) - argv: script arguments (list of strings) - ps1, ps2: optional primary and secondary prompts (strings) */ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _PyEval_SetAsyncGenFinalizer() #include "pycore_frame.h" // _PyInterpreterFrame #include "pycore_initconfig.h" // _PyStatus_EXCEPTION() #include "pycore_long.h" // _PY_LONG_MAX_STR_DIGITS_THRESHOLD #include "pycore_namespace.h" // _PyNamespace_New() #include "pycore_object.h" // _PyObject_IS_GC() #include "pycore_pathconfig.h" // _PyPathConfig_ComputeSysPath0() #include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pylifecycle.h" // _PyErr_WriteUnraisableDefaultHook() #include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_structseq.h" // _PyStructSequence_InitBuiltinWithFlags() #include "pycore_tuple.h" // _PyTuple_FromArray() #include "frameobject.h" // PyFrame_FastToLocalsWithError() #include "pydtrace.h" #include "osdefs.h" // DELIM #include "stdlib_module_names.h" // _Py_stdlib_module_names #include #ifdef MS_WINDOWS #define WIN32_LEAN_AND_MEAN #include #endif /* MS_WINDOWS */ #ifdef MS_COREDLL extern void *PyWin_DLLhModule; /* A string loaded from the DLL at startup: */ extern const char *PyWin_DLLVersionString; #endif #ifdef __EMSCRIPTEN__ #include #endif #ifdef HAVE_FCNTL_H #include #endif /*[clinic input] module sys [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=3726b388feee8cea]*/ #include "clinic/sysmodule.c.h" PyObject * _PySys_GetAttr(PyThreadState *tstate, PyObject *name) { PyObject *sd = tstate->interp->sysdict; if (sd == NULL) { return NULL; } PyObject *exc = _PyErr_GetRaisedException(tstate); /* XXX Suppress a new exception if it was raised and restore * the old one. */ PyObject *value = _PyDict_GetItemWithError(sd, name); _PyErr_SetRaisedException(tstate, exc); return value; } static PyObject * _PySys_GetObject(PyInterpreterState *interp, const char *name) { PyObject *sysdict = interp->sysdict; if (sysdict == NULL) { return NULL; } return _PyDict_GetItemStringWithError(sysdict, name); } PyObject * PySys_GetObject(const char *name) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *exc = _PyErr_GetRaisedException(tstate); PyObject *value = _PySys_GetObject(tstate->interp, name); /* XXX Suppress a new exception if it was raised and restore * the old one. */ _PyErr_SetRaisedException(tstate, exc); return value; } static int sys_set_object(PyInterpreterState *interp, PyObject *key, PyObject *v) { if (key == NULL) { return -1; } PyObject *sd = interp->sysdict; if (v == NULL) { v = _PyDict_Pop(sd, key, Py_None); if (v == NULL) { return -1; } Py_DECREF(v); return 0; } else { return PyDict_SetItem(sd, key, v); } } int _PySys_SetAttr(PyObject *key, PyObject *v) { PyInterpreterState *interp = _PyInterpreterState_GET(); return sys_set_object(interp, key, v); } static int sys_set_object_str(PyInterpreterState *interp, const char *name, PyObject *v) { PyObject *key = v ? PyUnicode_InternFromString(name) : PyUnicode_FromString(name); int r = sys_set_object(interp, key, v); Py_XDECREF(key); return r; } int PySys_SetObject(const char *name, PyObject *v) { PyInterpreterState *interp = _PyInterpreterState_GET(); return sys_set_object_str(interp, name, v); } int _PySys_ClearAttrString(PyInterpreterState *interp, const char *name, int verbose) { if (verbose) { PySys_WriteStderr("# clear sys.%s\n", name); } /* To play it safe, we set the attr to None instead of deleting it. */ if (PyDict_SetItemString(interp->sysdict, name, Py_None) < 0) { return -1; } return 0; } static int should_audit(PyInterpreterState *interp) { /* interp must not be NULL, but test it just in case for extra safety */ assert(interp != NULL); if (!interp) { return 0; } return (interp->runtime->audit_hook_head || interp->audit_hooks || PyDTrace_AUDIT_ENABLED()); } static int sys_audit_tstate(PyThreadState *ts, const char *event, const char *argFormat, va_list vargs) { /* N format is inappropriate, because you do not know whether the reference is consumed by the call. Assert rather than exception for perf reasons */ assert(!argFormat || !strchr(argFormat, 'N')); if (!ts) { /* Audit hooks cannot be called with a NULL thread state */ return 0; } /* The current implementation cannot be called if tstate is not the current Python thread state. */ assert(ts == _PyThreadState_GET()); /* Early exit when no hooks are registered */ PyInterpreterState *is = ts->interp; if (!should_audit(is)) { return 0; } PyObject *eventName = NULL; PyObject *eventArgs = NULL; PyObject *hooks = NULL; PyObject *hook = NULL; int res = -1; int dtrace = PyDTrace_AUDIT_ENABLED(); PyObject *exc = _PyErr_GetRaisedException(ts); /* Initialize event args now */ if (argFormat && argFormat[0]) { eventArgs = Py_VaBuildValue(argFormat, vargs); if (eventArgs && !PyTuple_Check(eventArgs)) { PyObject *argTuple = PyTuple_Pack(1, eventArgs); Py_SETREF(eventArgs, argTuple); } } else { eventArgs = PyTuple_New(0); } if (!eventArgs) { goto exit; } /* Call global hooks */ _Py_AuditHookEntry *e = is->runtime->audit_hook_head; for (; e; e = e->next) { if (e->hookCFunction(event, eventArgs, e->userData) < 0) { goto exit; } } /* Dtrace USDT point */ if (dtrace) { PyDTrace_AUDIT(event, (void *)eventArgs); } /* Call interpreter hooks */ if (is->audit_hooks) { eventName = PyUnicode_FromString(event); if (!eventName) { goto exit; } hooks = PyObject_GetIter(is->audit_hooks); if (!hooks) { goto exit; } /* Disallow tracing in hooks unless explicitly enabled */ PyThreadState_EnterTracing(ts); while ((hook = PyIter_Next(hooks)) != NULL) { PyObject *o; int canTrace = _PyObject_LookupAttr(hook, &_Py_ID(__cantrace__), &o); if (o) { canTrace = PyObject_IsTrue(o); Py_DECREF(o); } if (canTrace < 0) { break; } if (canTrace) { PyThreadState_LeaveTracing(ts); } PyObject* args[2] = {eventName, eventArgs}; o = _PyObject_FastCallTstate(ts, hook, args, 2); if (canTrace) { PyThreadState_EnterTracing(ts); } if (!o) { break; } Py_DECREF(o); Py_CLEAR(hook); } PyThreadState_LeaveTracing(ts); if (_PyErr_Occurred(ts)) { goto exit; } } res = 0; exit: Py_XDECREF(hook); Py_XDECREF(hooks); Py_XDECREF(eventName); Py_XDECREF(eventArgs); if (!res) { _PyErr_SetRaisedException(ts, exc); } else { assert(_PyErr_Occurred(ts)); Py_XDECREF(exc); } return res; } int _PySys_Audit(PyThreadState *tstate, const char *event, const char *argFormat, ...) { va_list vargs; va_start(vargs, argFormat); int res = sys_audit_tstate(tstate, event, argFormat, vargs); va_end(vargs); return res; } int PySys_Audit(const char *event, const char *argFormat, ...) { PyThreadState *tstate = _PyThreadState_GET(); va_list vargs; va_start(vargs, argFormat); int res = sys_audit_tstate(tstate, event, argFormat, vargs); va_end(vargs); return res; } /* We expose this function primarily for our own cleanup during * finalization. In general, it should not need to be called, * and as such the function is not exported. * * Must be finalizing to clear hooks */ void _PySys_ClearAuditHooks(PyThreadState *ts) { assert(ts != NULL); if (!ts) { return; } _PyRuntimeState *runtime = ts->interp->runtime; /* The hooks are global so we have to check for runtime finalization. */ PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(runtime); assert(finalizing == ts); if (finalizing != ts) { return; } const PyConfig *config = _PyInterpreterState_GetConfig(ts->interp); if (config->verbose) { PySys_WriteStderr("# clear sys.audit hooks\n"); } /* Hooks can abort later hooks for this event, but cannot abort the clear operation itself. */ _PySys_Audit(ts, "cpython._PySys_ClearAuditHooks", NULL); _PyErr_Clear(ts); _Py_AuditHookEntry *e = runtime->audit_hook_head, *n; runtime->audit_hook_head = NULL; while (e) { n = e->next; PyMem_RawFree(e); e = n; } } int PySys_AddAuditHook(Py_AuditHookFunction hook, void *userData) { /* tstate can be NULL, so access directly _PyRuntime: PySys_AddAuditHook() can be called before Python is initialized. */ _PyRuntimeState *runtime = &_PyRuntime; PyThreadState *tstate; if (runtime->initialized) { tstate = _PyThreadState_GET(); } else { tstate = NULL; } /* Invoke existing audit hooks to allow them an opportunity to abort. */ /* Cannot invoke hooks until we are initialized */ if (tstate != NULL) { if (_PySys_Audit(tstate, "sys.addaudithook", NULL) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_RuntimeError)) { /* We do not report errors derived from RuntimeError */ _PyErr_Clear(tstate); return 0; } return -1; } } _Py_AuditHookEntry *e = runtime->audit_hook_head; if (!e) { e = (_Py_AuditHookEntry*)PyMem_RawMalloc(sizeof(_Py_AuditHookEntry)); runtime->audit_hook_head = e; } else { while (e->next) { e = e->next; } e = e->next = (_Py_AuditHookEntry*)PyMem_RawMalloc( sizeof(_Py_AuditHookEntry)); } if (!e) { if (tstate != NULL) { _PyErr_NoMemory(tstate); } return -1; } e->next = NULL; e->hookCFunction = (Py_AuditHookFunction)hook; e->userData = userData; return 0; } /*[clinic input] sys.addaudithook hook: object Adds a new audit hook callback. [clinic start generated code]*/ static PyObject * sys_addaudithook_impl(PyObject *module, PyObject *hook) /*[clinic end generated code: output=4f9c17aaeb02f44e input=0f3e191217a45e34]*/ { PyThreadState *tstate = _PyThreadState_GET(); /* Invoke existing audit hooks to allow them an opportunity to abort. */ if (_PySys_Audit(tstate, "sys.addaudithook", NULL) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_Exception)) { /* We do not report errors derived from Exception */ _PyErr_Clear(tstate); Py_RETURN_NONE; } return NULL; } PyInterpreterState *interp = tstate->interp; if (interp->audit_hooks == NULL) { interp->audit_hooks = PyList_New(0); if (interp->audit_hooks == NULL) { return NULL; } /* Avoid having our list of hooks show up in the GC module */ PyObject_GC_UnTrack(interp->audit_hooks); } if (PyList_Append(interp->audit_hooks, hook) < 0) { return NULL; } Py_RETURN_NONE; } PyDoc_STRVAR(audit_doc, "audit(event, *args)\n\ \n\ Passes the event to any audit hooks that are attached."); static PyObject * sys_audit(PyObject *self, PyObject *const *args, Py_ssize_t argc) { PyThreadState *tstate = _PyThreadState_GET(); _Py_EnsureTstateNotNULL(tstate); if (argc == 0) { _PyErr_SetString(tstate, PyExc_TypeError, "audit() missing 1 required positional argument: " "'event'"); return NULL; } if (!should_audit(tstate->interp)) { Py_RETURN_NONE; } PyObject *auditEvent = args[0]; if (!auditEvent) { _PyErr_SetString(tstate, PyExc_TypeError, "expected str for argument 'event'"); return NULL; } if (!PyUnicode_Check(auditEvent)) { _PyErr_Format(tstate, PyExc_TypeError, "expected str for argument 'event', not %.200s", Py_TYPE(auditEvent)->tp_name); return NULL; } const char *event = PyUnicode_AsUTF8(auditEvent); if (!event) { return NULL; } PyObject *auditArgs = _PyTuple_FromArray(args + 1, argc - 1); if (!auditArgs) { return NULL; } int res = _PySys_Audit(tstate, event, "O", auditArgs); Py_DECREF(auditArgs); if (res < 0) { return NULL; } Py_RETURN_NONE; } static PyObject * sys_breakpointhook(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *keywords) { PyThreadState *tstate = _PyThreadState_GET(); assert(!_PyErr_Occurred(tstate)); char *envar = Py_GETENV("PYTHONBREAKPOINT"); if (envar == NULL || strlen(envar) == 0) { envar = "pdb.set_trace"; } else if (!strcmp(envar, "0")) { /* The breakpoint is explicitly no-op'd. */ Py_RETURN_NONE; } /* According to POSIX the string returned by getenv() might be invalidated * or the string content might be overwritten by a subsequent call to * getenv(). Since importing a module can performs the getenv() calls, * we need to save a copy of envar. */ envar = _PyMem_RawStrdup(envar); if (envar == NULL) { _PyErr_NoMemory(tstate); return NULL; } const char *last_dot = strrchr(envar, '.'); const char *attrname = NULL; PyObject *modulepath = NULL; if (last_dot == NULL) { /* The breakpoint is a built-in, e.g. PYTHONBREAKPOINT=int */ modulepath = PyUnicode_FromString("builtins"); attrname = envar; } else if (last_dot != envar) { /* Split on the last dot; */ modulepath = PyUnicode_FromStringAndSize(envar, last_dot - envar); attrname = last_dot + 1; } else { goto warn; } if (modulepath == NULL) { PyMem_RawFree(envar); return NULL; } PyObject *module = PyImport_Import(modulepath); Py_DECREF(modulepath); if (module == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_ImportError)) { goto warn; } PyMem_RawFree(envar); return NULL; } PyObject *hook = PyObject_GetAttrString(module, attrname); Py_DECREF(module); if (hook == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { goto warn; } PyMem_RawFree(envar); return NULL; } PyMem_RawFree(envar); PyObject *retval = PyObject_Vectorcall(hook, args, nargs, keywords); Py_DECREF(hook); return retval; warn: /* If any of the imports went wrong, then warn and ignore. */ _PyErr_Clear(tstate); int status = PyErr_WarnFormat( PyExc_RuntimeWarning, 0, "Ignoring unimportable $PYTHONBREAKPOINT: \"%s\"", envar); PyMem_RawFree(envar); if (status < 0) { /* Printing the warning raised an exception. */ return NULL; } /* The warning was (probably) issued. */ Py_RETURN_NONE; } PyDoc_STRVAR(breakpointhook_doc, "breakpointhook(*args, **kws)\n" "\n" "This hook function is called by built-in breakpoint().\n" ); /* Write repr(o) to sys.stdout using sys.stdout.encoding and 'backslashreplace' error handler. If sys.stdout has a buffer attribute, use sys.stdout.buffer.write(encoded), otherwise redecode the string and use sys.stdout.write(redecoded). Helper function for sys_displayhook(). */ static int sys_displayhook_unencodable(PyObject *outf, PyObject *o) { PyObject *stdout_encoding = NULL; PyObject *encoded, *escaped_str, *repr_str, *buffer, *result; const char *stdout_encoding_str; int ret; stdout_encoding = PyObject_GetAttr(outf, &_Py_ID(encoding)); if (stdout_encoding == NULL) goto error; stdout_encoding_str = PyUnicode_AsUTF8(stdout_encoding); if (stdout_encoding_str == NULL) goto error; repr_str = PyObject_Repr(o); if (repr_str == NULL) goto error; encoded = PyUnicode_AsEncodedString(repr_str, stdout_encoding_str, "backslashreplace"); Py_DECREF(repr_str); if (encoded == NULL) goto error; if (_PyObject_LookupAttr(outf, &_Py_ID(buffer), &buffer) < 0) { Py_DECREF(encoded); goto error; } if (buffer) { result = PyObject_CallMethodOneArg(buffer, &_Py_ID(write), encoded); Py_DECREF(buffer); Py_DECREF(encoded); if (result == NULL) goto error; Py_DECREF(result); } else { escaped_str = PyUnicode_FromEncodedObject(encoded, stdout_encoding_str, "strict"); Py_DECREF(encoded); if (PyFile_WriteObject(escaped_str, outf, Py_PRINT_RAW) != 0) { Py_DECREF(escaped_str); goto error; } Py_DECREF(escaped_str); } ret = 0; goto finally; error: ret = -1; finally: Py_XDECREF(stdout_encoding); return ret; } /*[clinic input] sys.displayhook object as o: object / Print an object to sys.stdout and also save it in builtins._ [clinic start generated code]*/ static PyObject * sys_displayhook(PyObject *module, PyObject *o) /*[clinic end generated code: output=347477d006df92ed input=08ba730166d7ef72]*/ { PyObject *outf; PyObject *builtins; PyThreadState *tstate = _PyThreadState_GET(); builtins = PyImport_GetModule(&_Py_ID(builtins)); if (builtins == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_SetString(tstate, PyExc_RuntimeError, "lost builtins module"); } return NULL; } Py_DECREF(builtins); /* Print value except if None */ /* After printing, also assign to '_' */ /* Before, set '_' to None to avoid recursion */ if (o == Py_None) { Py_RETURN_NONE; } if (PyObject_SetAttr(builtins, &_Py_ID(_), Py_None) != 0) return NULL; outf = _PySys_GetAttr(tstate, &_Py_ID(stdout)); if (outf == NULL || outf == Py_None) { _PyErr_SetString(tstate, PyExc_RuntimeError, "lost sys.stdout"); return NULL; } if (PyFile_WriteObject(o, outf, 0) != 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_UnicodeEncodeError)) { int err; /* repr(o) is not encodable to sys.stdout.encoding with * sys.stdout.errors error handler (which is probably 'strict') */ _PyErr_Clear(tstate); err = sys_displayhook_unencodable(outf, o); if (err) { return NULL; } } else { return NULL; } } _Py_DECLARE_STR(newline, "\n"); if (PyFile_WriteObject(&_Py_STR(newline), outf, Py_PRINT_RAW) != 0) return NULL; if (PyObject_SetAttr(builtins, &_Py_ID(_), o) != 0) return NULL; Py_RETURN_NONE; } /*[clinic input] sys.excepthook exctype: object value: object traceback: object / Handle an exception by displaying it with a traceback on sys.stderr. [clinic start generated code]*/ static PyObject * sys_excepthook_impl(PyObject *module, PyObject *exctype, PyObject *value, PyObject *traceback) /*[clinic end generated code: output=18d99fdda21b6b5e input=ecf606fa826f19d9]*/ { PyErr_Display(NULL, value, traceback); Py_RETURN_NONE; } /*[clinic input] sys.exception Return the current exception. Return the most recent exception caught by an except clause in the current stack frame or in an older stack frame, or None if no such exception exists. [clinic start generated code]*/ static PyObject * sys_exception_impl(PyObject *module) /*[clinic end generated code: output=2381ee2f25953e40 input=c88fbb94b6287431]*/ { _PyErr_StackItem *err_info = _PyErr_GetTopmostException(_PyThreadState_GET()); if (err_info->exc_value != NULL) { return Py_NewRef(err_info->exc_value); } Py_RETURN_NONE; } /*[clinic input] sys.exc_info Return current exception information: (type, value, traceback). Return information about the most recent exception caught by an except clause in the current stack frame or in an older stack frame. [clinic start generated code]*/ static PyObject * sys_exc_info_impl(PyObject *module) /*[clinic end generated code: output=3afd0940cf3a4d30 input=b5c5bf077788a3e5]*/ { _PyErr_StackItem *err_info = _PyErr_GetTopmostException(_PyThreadState_GET()); return _PyErr_StackItemToExcInfoTuple(err_info); } /*[clinic input] sys.unraisablehook unraisable: object / Handle an unraisable exception. The unraisable argument has the following attributes: * exc_type: Exception type. * exc_value: Exception value, can be None. * exc_traceback: Exception traceback, can be None. * err_msg: Error message, can be None. * object: Object causing the exception, can be None. [clinic start generated code]*/ static PyObject * sys_unraisablehook(PyObject *module, PyObject *unraisable) /*[clinic end generated code: output=bb92838b32abaa14 input=ec3af148294af8d3]*/ { return _PyErr_WriteUnraisableDefaultHook(unraisable); } /*[clinic input] sys.exit status: object = None / Exit the interpreter by raising SystemExit(status). If the status is omitted or None, it defaults to zero (i.e., success). If the status is an integer, it will be used as the system exit status. If it is another kind of object, it will be printed and the system exit status will be one (i.e., failure). [clinic start generated code]*/ static PyObject * sys_exit_impl(PyObject *module, PyObject *status) /*[clinic end generated code: output=13870986c1ab2ec0 input=b86ca9497baa94f2]*/ { /* Raise SystemExit so callers may catch it or clean up. */ PyErr_SetObject(PyExc_SystemExit, status); return NULL; } /*[clinic input] sys.getdefaultencoding Return the current default encoding used by the Unicode implementation. [clinic start generated code]*/ static PyObject * sys_getdefaultencoding_impl(PyObject *module) /*[clinic end generated code: output=256d19dfcc0711e6 input=d416856ddbef6909]*/ { _Py_DECLARE_STR(utf_8, "utf-8"); PyObject *ret = &_Py_STR(utf_8); return Py_NewRef(ret); } /*[clinic input] sys.getfilesystemencoding Return the encoding used to convert Unicode filenames to OS filenames. [clinic start generated code]*/ static PyObject * sys_getfilesystemencoding_impl(PyObject *module) /*[clinic end generated code: output=1dc4bdbe9be44aa7 input=8475f8649b8c7d8c]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); const PyConfig *config = _PyInterpreterState_GetConfig(interp); return PyUnicode_FromWideChar(config->filesystem_encoding, -1); } /*[clinic input] sys.getfilesystemencodeerrors Return the error mode used Unicode to OS filename conversion. [clinic start generated code]*/ static PyObject * sys_getfilesystemencodeerrors_impl(PyObject *module) /*[clinic end generated code: output=ba77b36bbf7c96f5 input=22a1e8365566f1e5]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); const PyConfig *config = _PyInterpreterState_GetConfig(interp); return PyUnicode_FromWideChar(config->filesystem_errors, -1); } /*[clinic input] sys.intern string as s: unicode / ``Intern'' the given string. This enters the string in the (global) table of interned strings whose purpose is to speed up dictionary lookups. Return the string itself or the previously interned string object with the same value. [clinic start generated code]*/ static PyObject * sys_intern_impl(PyObject *module, PyObject *s) /*[clinic end generated code: output=be680c24f5c9e5d6 input=849483c006924e2f]*/ { if (PyUnicode_CheckExact(s)) { Py_INCREF(s); PyUnicode_InternInPlace(&s); return s; } else { PyErr_Format(PyExc_TypeError, "can't intern %.400s", Py_TYPE(s)->tp_name); return NULL; } } /* * Cached interned string objects used for calling the profile and * trace functions. */ static PyObject *whatstrings[8] = { &_Py_ID(call), &_Py_ID(exception), &_Py_ID(line), &_Py_ID(return), &_Py_ID(c_call), &_Py_ID(c_exception), &_Py_ID(c_return), &_Py_ID(opcode), }; static PyObject * call_trampoline(PyThreadState *tstate, PyObject* callback, PyFrameObject *frame, int what, PyObject *arg) { PyObject *stack[3]; stack[0] = (PyObject *)frame; stack[1] = whatstrings[what]; stack[2] = (arg != NULL) ? arg : Py_None; /* Discard any previous modifications the frame's fast locals */ if (frame->f_fast_as_locals) { if (PyFrame_FastToLocalsWithError(frame) < 0) { return NULL; } } /* call the Python-level function */ PyObject *result = _PyObject_FastCallTstate(tstate, callback, stack, 3); PyFrame_LocalsToFast(frame, 1); return result; } static int profile_trampoline(PyObject *self, PyFrameObject *frame, int what, PyObject *arg) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *result = call_trampoline(tstate, self, frame, what, arg); if (result == NULL) { _PyEval_SetProfile(tstate, NULL, NULL); return -1; } Py_DECREF(result); return 0; } static int trace_trampoline(PyObject *self, PyFrameObject *frame, int what, PyObject *arg) { PyObject *callback; if (what == PyTrace_CALL) { callback = self; } else { callback = frame->f_trace; } if (callback == NULL) { return 0; } PyThreadState *tstate = _PyThreadState_GET(); PyObject *result = call_trampoline(tstate, callback, frame, what, arg); if (result == NULL) { _PyEval_SetTrace(tstate, NULL, NULL); Py_CLEAR(frame->f_trace); return -1; } if (result != Py_None) { Py_XSETREF(frame->f_trace, result); } else { Py_DECREF(result); } return 0; } static PyObject * sys_settrace(PyObject *self, PyObject *args) { PyThreadState *tstate = _PyThreadState_GET(); if (args == Py_None) { if (_PyEval_SetTrace(tstate, NULL, NULL) < 0) { return NULL; } } else { if (_PyEval_SetTrace(tstate, trace_trampoline, args) < 0) { return NULL; } } Py_RETURN_NONE; } PyDoc_STRVAR(settrace_doc, "settrace(function)\n\ \n\ Set the global debug tracing function. It will be called on each\n\ function call. See the debugger chapter in the library manual." ); /*[clinic input] sys._settraceallthreads arg: object / Set the global debug tracing function in all running threads belonging to the current interpreter. It will be called on each function call. See the debugger chapter in the library manual. [clinic start generated code]*/ static PyObject * sys__settraceallthreads(PyObject *module, PyObject *arg) /*[clinic end generated code: output=161cca30207bf3ca input=5906aa1485a50289]*/ { PyObject* argument = NULL; Py_tracefunc func = NULL; if (arg != Py_None) { func = trace_trampoline; argument = arg; } PyEval_SetTraceAllThreads(func, argument); Py_RETURN_NONE; } /*[clinic input] sys.gettrace Return the global debug tracing function set with sys.settrace. See the debugger chapter in the library manual. [clinic start generated code]*/ static PyObject * sys_gettrace_impl(PyObject *module) /*[clinic end generated code: output=e97e3a4d8c971b6e input=373b51bb2147f4d8]*/ { PyThreadState *tstate = _PyThreadState_GET(); PyObject *temp = tstate->c_traceobj; if (temp == NULL) temp = Py_None; return Py_NewRef(temp); } static PyObject * sys_setprofile(PyObject *self, PyObject *args) { PyThreadState *tstate = _PyThreadState_GET(); if (args == Py_None) { if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) { return NULL; } } else { if (_PyEval_SetProfile(tstate, profile_trampoline, args) < 0) { return NULL; } } Py_RETURN_NONE; } PyDoc_STRVAR(setprofile_doc, "setprofile(function)\n\ \n\ Set the profiling function. It will be called on each function call\n\ and return. See the profiler chapter in the library manual." ); /*[clinic input] sys._setprofileallthreads arg: object / Set the profiling function in all running threads belonging to the current interpreter. It will be called on each function call and return. See the profiler chapter in the library manual. [clinic start generated code]*/ static PyObject * sys__setprofileallthreads(PyObject *module, PyObject *arg) /*[clinic end generated code: output=2d61319e27b309fe input=d1a356d3f4f9060a]*/ { PyObject* argument = NULL; Py_tracefunc func = NULL; if (arg != Py_None) { func = profile_trampoline; argument = arg; } PyEval_SetProfileAllThreads(func, argument); Py_RETURN_NONE; } /*[clinic input] sys.getprofile Return the profiling function set with sys.setprofile. See the profiler chapter in the library manual. [clinic start generated code]*/ static PyObject * sys_getprofile_impl(PyObject *module) /*[clinic end generated code: output=579b96b373448188 input=1b3209d89a32965d]*/ { PyThreadState *tstate = _PyThreadState_GET(); PyObject *temp = tstate->c_profileobj; if (temp == NULL) temp = Py_None; return Py_NewRef(temp); } /*[clinic input] sys.setswitchinterval interval: double / Set the ideal thread switching delay inside the Python interpreter. The actual frequency of switching threads can be lower if the interpreter executes long sequences of uninterruptible code (this is implementation-specific and workload-dependent). The parameter must represent the desired switching delay in seconds A typical value is 0.005 (5 milliseconds). [clinic start generated code]*/ static PyObject * sys_setswitchinterval_impl(PyObject *module, double interval) /*[clinic end generated code: output=65a19629e5153983 input=561b477134df91d9]*/ { if (interval <= 0.0) { PyErr_SetString(PyExc_ValueError, "switch interval must be strictly positive"); return NULL; } _PyEval_SetSwitchInterval((unsigned long) (1e6 * interval)); Py_RETURN_NONE; } /*[clinic input] sys.getswitchinterval -> double Return the current thread switch interval; see sys.setswitchinterval(). [clinic start generated code]*/ static double sys_getswitchinterval_impl(PyObject *module) /*[clinic end generated code: output=a38c277c85b5096d input=bdf9d39c0ebbbb6f]*/ { return 1e-6 * _PyEval_GetSwitchInterval(); } /*[clinic input] sys.setrecursionlimit limit as new_limit: int / Set the maximum depth of the Python interpreter stack to n. This limit prevents infinite recursion from causing an overflow of the C stack and crashing Python. The highest possible limit is platform- dependent. [clinic start generated code]*/ static PyObject * sys_setrecursionlimit_impl(PyObject *module, int new_limit) /*[clinic end generated code: output=35e1c64754800ace input=b0f7a23393924af3]*/ { PyThreadState *tstate = _PyThreadState_GET(); if (new_limit < 1) { _PyErr_SetString(tstate, PyExc_ValueError, "recursion limit must be greater or equal than 1"); return NULL; } /* Reject too low new limit if the current recursion depth is higher than the new low-water mark. */ int depth = tstate->py_recursion_limit - tstate->py_recursion_remaining; if (depth >= new_limit) { _PyErr_Format(tstate, PyExc_RecursionError, "cannot set the recursion limit to %i at " "the recursion depth %i: the limit is too low", new_limit, depth); return NULL; } Py_SetRecursionLimit(new_limit); Py_RETURN_NONE; } /*[clinic input] sys.set_coroutine_origin_tracking_depth depth: int Enable or disable origin tracking for coroutine objects in this thread. Coroutine objects will track 'depth' frames of traceback information about where they came from, available in their cr_origin attribute. Set a depth of 0 to disable. [clinic start generated code]*/ static PyObject * sys_set_coroutine_origin_tracking_depth_impl(PyObject *module, int depth) /*[clinic end generated code: output=0a2123c1cc6759c5 input=a1d0a05f89d2c426]*/ { if (_PyEval_SetCoroutineOriginTrackingDepth(depth) < 0) { return NULL; } Py_RETURN_NONE; } /*[clinic input] sys.get_coroutine_origin_tracking_depth -> int Check status of origin tracking for coroutine objects in this thread. [clinic start generated code]*/ static int sys_get_coroutine_origin_tracking_depth_impl(PyObject *module) /*[clinic end generated code: output=3699f7be95a3afb8 input=335266a71205b61a]*/ { return _PyEval_GetCoroutineOriginTrackingDepth(); } static PyTypeObject AsyncGenHooksType; PyDoc_STRVAR(asyncgen_hooks_doc, "asyncgen_hooks\n\ \n\ A named tuple providing information about asynchronous\n\ generators hooks. The attributes are read only."); static PyStructSequence_Field asyncgen_hooks_fields[] = { {"firstiter", "Hook to intercept first iteration"}, {"finalizer", "Hook to intercept finalization"}, {0} }; static PyStructSequence_Desc asyncgen_hooks_desc = { "asyncgen_hooks", /* name */ asyncgen_hooks_doc, /* doc */ asyncgen_hooks_fields , /* fields */ 2 }; static PyObject * sys_set_asyncgen_hooks(PyObject *self, PyObject *args, PyObject *kw) { static char *keywords[] = {"firstiter", "finalizer", NULL}; PyObject *firstiter = NULL; PyObject *finalizer = NULL; if (!PyArg_ParseTupleAndKeywords( args, kw, "|OO", keywords, &firstiter, &finalizer)) { return NULL; } if (finalizer && finalizer != Py_None) { if (!PyCallable_Check(finalizer)) { PyErr_Format(PyExc_TypeError, "callable finalizer expected, got %.50s", Py_TYPE(finalizer)->tp_name); return NULL; } if (_PyEval_SetAsyncGenFinalizer(finalizer) < 0) { return NULL; } } else if (finalizer == Py_None && _PyEval_SetAsyncGenFinalizer(NULL) < 0) { return NULL; } if (firstiter && firstiter != Py_None) { if (!PyCallable_Check(firstiter)) { PyErr_Format(PyExc_TypeError, "callable firstiter expected, got %.50s", Py_TYPE(firstiter)->tp_name); return NULL; } if (_PyEval_SetAsyncGenFirstiter(firstiter) < 0) { return NULL; } } else if (firstiter == Py_None && _PyEval_SetAsyncGenFirstiter(NULL) < 0) { return NULL; } Py_RETURN_NONE; } PyDoc_STRVAR(set_asyncgen_hooks_doc, "set_asyncgen_hooks(* [, firstiter] [, finalizer])\n\ \n\ Set a finalizer for async generators objects." ); /*[clinic input] sys.get_asyncgen_hooks Return the installed asynchronous generators hooks. This returns a namedtuple of the form (firstiter, finalizer). [clinic start generated code]*/ static PyObject * sys_get_asyncgen_hooks_impl(PyObject *module) /*[clinic end generated code: output=53a253707146f6cf input=3676b9ea62b14625]*/ { PyObject *res; PyObject *firstiter = _PyEval_GetAsyncGenFirstiter(); PyObject *finalizer = _PyEval_GetAsyncGenFinalizer(); res = PyStructSequence_New(&AsyncGenHooksType); if (res == NULL) { return NULL; } if (firstiter == NULL) { firstiter = Py_None; } if (finalizer == NULL) { finalizer = Py_None; } PyStructSequence_SET_ITEM(res, 0, Py_NewRef(firstiter)); PyStructSequence_SET_ITEM(res, 1, Py_NewRef(finalizer)); return res; } static PyTypeObject Hash_InfoType; PyDoc_STRVAR(hash_info_doc, "hash_info\n\ \n\ A named tuple providing parameters used for computing\n\ hashes. The attributes are read only."); static PyStructSequence_Field hash_info_fields[] = { {"width", "width of the type used for hashing, in bits"}, {"modulus", "prime number giving the modulus on which the hash " "function is based"}, {"inf", "value to be used for hash of a positive infinity"}, {"nan", "value to be used for hash of a nan"}, {"imag", "multiplier used for the imaginary part of a complex number"}, {"algorithm", "name of the algorithm for hashing of str, bytes and " "memoryviews"}, {"hash_bits", "internal output size of hash algorithm"}, {"seed_bits", "seed size of hash algorithm"}, {"cutoff", "small string optimization cutoff"}, {NULL, NULL} }; static PyStructSequence_Desc hash_info_desc = { "sys.hash_info", hash_info_doc, hash_info_fields, 9, }; static PyObject * get_hash_info(PyThreadState *tstate) { PyObject *hash_info; int field = 0; PyHash_FuncDef *hashfunc; hash_info = PyStructSequence_New(&Hash_InfoType); if (hash_info == NULL) return NULL; hashfunc = PyHash_GetFuncDef(); PyStructSequence_SET_ITEM(hash_info, field++, PyLong_FromLong(8*sizeof(Py_hash_t))); PyStructSequence_SET_ITEM(hash_info, field++, PyLong_FromSsize_t(_PyHASH_MODULUS)); PyStructSequence_SET_ITEM(hash_info, field++, PyLong_FromLong(_PyHASH_INF)); PyStructSequence_SET_ITEM(hash_info, field++, PyLong_FromLong(0)); // This is no longer used PyStructSequence_SET_ITEM(hash_info, field++, PyLong_FromLong(_PyHASH_IMAG)); PyStructSequence_SET_ITEM(hash_info, field++, PyUnicode_FromString(hashfunc->name)); PyStructSequence_SET_ITEM(hash_info, field++, PyLong_FromLong(hashfunc->hash_bits)); PyStructSequence_SET_ITEM(hash_info, field++, PyLong_FromLong(hashfunc->seed_bits)); PyStructSequence_SET_ITEM(hash_info, field++, PyLong_FromLong(Py_HASH_CUTOFF)); if (_PyErr_Occurred(tstate)) { Py_CLEAR(hash_info); return NULL; } return hash_info; } /*[clinic input] sys.getrecursionlimit Return the current value of the recursion limit. The recursion limit is the maximum depth of the Python interpreter stack. This limit prevents infinite recursion from causing an overflow of the C stack and crashing Python. [clinic start generated code]*/ static PyObject * sys_getrecursionlimit_impl(PyObject *module) /*[clinic end generated code: output=d571fb6b4549ef2e input=1c6129fd2efaeea8]*/ { return PyLong_FromLong(Py_GetRecursionLimit()); } #ifdef MS_WINDOWS static PyTypeObject WindowsVersionType = {0, 0, 0, 0, 0, 0}; static PyStructSequence_Field windows_version_fields[] = { {"major", "Major version number"}, {"minor", "Minor version number"}, {"build", "Build number"}, {"platform", "Operating system platform"}, {"service_pack", "Latest Service Pack installed on the system"}, {"service_pack_major", "Service Pack major version number"}, {"service_pack_minor", "Service Pack minor version number"}, {"suite_mask", "Bit mask identifying available product suites"}, {"product_type", "System product type"}, {"platform_version", "Diagnostic version number"}, {0} }; static PyStructSequence_Desc windows_version_desc = { "sys.getwindowsversion", /* name */ sys_getwindowsversion__doc__, /* doc */ windows_version_fields, /* fields */ 5 /* For backward compatibility, only the first 5 items are accessible via indexing, the rest are name only */ }; static PyObject * _sys_getwindowsversion_from_kernel32(void) { #ifndef MS_WINDOWS_DESKTOP return NULL; #else HANDLE hKernel32; wchar_t kernel32_path[MAX_PATH]; LPVOID verblock; DWORD verblock_size; VS_FIXEDFILEINFO *ffi; UINT ffi_len; DWORD realMajor, realMinor, realBuild; Py_BEGIN_ALLOW_THREADS hKernel32 = GetModuleHandleW(L"kernel32.dll"); Py_END_ALLOW_THREADS if (!hKernel32 || !GetModuleFileNameW(hKernel32, kernel32_path, MAX_PATH)) { PyErr_SetFromWindowsErr(0); return NULL; } verblock_size = GetFileVersionInfoSizeW(kernel32_path, NULL); if (!verblock_size) { PyErr_SetFromWindowsErr(0); return NULL; } verblock = PyMem_RawMalloc(verblock_size); if (!verblock || !GetFileVersionInfoW(kernel32_path, 0, verblock_size, verblock) || !VerQueryValueW(verblock, L"", (LPVOID)&ffi, &ffi_len)) { PyErr_SetFromWindowsErr(0); return NULL; } realMajor = HIWORD(ffi->dwProductVersionMS); realMinor = LOWORD(ffi->dwProductVersionMS); realBuild = HIWORD(ffi->dwProductVersionLS); PyMem_RawFree(verblock); return Py_BuildValue("(kkk)", realMajor, realMinor, realBuild); #endif /* !MS_WINDOWS_DESKTOP */ } /* Disable deprecation warnings about GetVersionEx as the result is being passed straight through to the caller, who is responsible for using it correctly. */ #pragma warning(push) #pragma warning(disable:4996) /*[clinic input] sys.getwindowsversion Return info about the running version of Windows as a named tuple. The members are named: major, minor, build, platform, service_pack, service_pack_major, service_pack_minor, suite_mask, product_type and platform_version. For backward compatibility, only the first 5 items are available by indexing. All elements are numbers, except service_pack and platform_type which are strings, and platform_version which is a 3-tuple. Platform is always 2. Product_type may be 1 for a workstation, 2 for a domain controller, 3 for a server. Platform_version is a 3-tuple containing a version number that is intended for identifying the OS rather than feature detection. [clinic start generated code]*/ static PyObject * sys_getwindowsversion_impl(PyObject *module) /*[clinic end generated code: output=1ec063280b932857 input=73a228a328fee63a]*/ { PyObject *version; int pos = 0; OSVERSIONINFOEXW ver; version = PyObject_GetAttrString(module, "_cached_windows_version"); if (version && PyObject_TypeCheck(version, &WindowsVersionType)) { return version; } Py_XDECREF(version); PyErr_Clear(); ver.dwOSVersionInfoSize = sizeof(ver); if (!GetVersionExW((OSVERSIONINFOW*) &ver)) return PyErr_SetFromWindowsErr(0); version = PyStructSequence_New(&WindowsVersionType); if (version == NULL) return NULL; PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.dwMajorVersion)); PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.dwMinorVersion)); PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.dwBuildNumber)); PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.dwPlatformId)); PyStructSequence_SET_ITEM(version, pos++, PyUnicode_FromWideChar(ver.szCSDVersion, -1)); PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wServicePackMajor)); PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wServicePackMinor)); PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wSuiteMask)); PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wProductType)); // GetVersion will lie if we are running in a compatibility mode. // We need to read the version info from a system file resource // to accurately identify the OS version. If we fail for any reason, // just return whatever GetVersion said. PyObject *realVersion = _sys_getwindowsversion_from_kernel32(); if (!realVersion) { PyErr_Clear(); realVersion = Py_BuildValue("(kkk)", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber ); } if (realVersion) { PyStructSequence_SET_ITEM(version, pos++, realVersion); } if (PyErr_Occurred()) { Py_DECREF(version); return NULL; } if (PyObject_SetAttrString(module, "_cached_windows_version", version) < 0) { Py_DECREF(version); return NULL; } return version; } #pragma warning(pop) /*[clinic input] sys._enablelegacywindowsfsencoding Changes the default filesystem encoding to mbcs:replace. This is done for consistency with earlier versions of Python. See PEP 529 for more information. This is equivalent to defining the PYTHONLEGACYWINDOWSFSENCODING environment variable before launching Python. [clinic start generated code]*/ static PyObject * sys__enablelegacywindowsfsencoding_impl(PyObject *module) /*[clinic end generated code: output=f5c3855b45e24fe9 input=2bfa931a20704492]*/ { if (_PyUnicode_EnableLegacyWindowsFSEncoding() < 0) { return NULL; } Py_RETURN_NONE; } #endif /* MS_WINDOWS */ #ifdef HAVE_DLOPEN /*[clinic input] sys.setdlopenflags flags as new_val: int / Set the flags used by the interpreter for dlopen calls. This is used, for example, when the interpreter loads extension modules. Among other things, this will enable a lazy resolving of symbols when importing a module, if called as sys.setdlopenflags(0). To share symbols across extension modules, call as sys.setdlopenflags(os.RTLD_GLOBAL). Symbolic names for the flag modules can be found in the os module (RTLD_xxx constants, e.g. os.RTLD_LAZY). [clinic start generated code]*/ static PyObject * sys_setdlopenflags_impl(PyObject *module, int new_val) /*[clinic end generated code: output=ec918b7fe0a37281 input=4c838211e857a77f]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); _PyImport_SetDLOpenFlags(interp, new_val); Py_RETURN_NONE; } /*[clinic input] sys.getdlopenflags Return the current value of the flags that are used for dlopen calls. The flag constants are defined in the os module. [clinic start generated code]*/ static PyObject * sys_getdlopenflags_impl(PyObject *module) /*[clinic end generated code: output=e92cd1bc5005da6e input=dc4ea0899c53b4b6]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); return PyLong_FromLong( _PyImport_GetDLOpenFlags(interp)); } #endif /* HAVE_DLOPEN */ #ifdef USE_MALLOPT /* Link with -lmalloc (or -lmpc) on an SGI */ #include /*[clinic input] sys.mdebug flag: int / [clinic start generated code]*/ static PyObject * sys_mdebug_impl(PyObject *module, int flag) /*[clinic end generated code: output=5431d545847c3637 input=151d150ae1636f8a]*/ { int flag; mallopt(M_DEBUG, flag); Py_RETURN_NONE; } #endif /* USE_MALLOPT */ /*[clinic input] sys.get_int_max_str_digits Return the maximum string digits limit for non-binary int<->str conversions. [clinic start generated code]*/ static PyObject * sys_get_int_max_str_digits_impl(PyObject *module) /*[clinic end generated code: output=0042f5e8ae0e8631 input=61bf9f99bc8b112d]*/ { PyInterpreterState *interp = _PyInterpreterState_GET(); return PyLong_FromLong(interp->long_state.max_str_digits); } /*[clinic input] sys.set_int_max_str_digits maxdigits: int Set the maximum string digits limit for non-binary int<->str conversions. [clinic start generated code]*/ static PyObject * sys_set_int_max_str_digits_impl(PyObject *module, int maxdigits) /*[clinic end generated code: output=734d4c2511f2a56d input=d7e3f325db6910c5]*/ { PyThreadState *tstate = _PyThreadState_GET(); if ((!maxdigits) || (maxdigits >= _PY_LONG_MAX_STR_DIGITS_THRESHOLD)) { tstate->interp->long_state.max_str_digits = maxdigits; Py_RETURN_NONE; } else { PyErr_Format( PyExc_ValueError, "maxdigits must be 0 or larger than %d", _PY_LONG_MAX_STR_DIGITS_THRESHOLD); return NULL; } } size_t _PySys_GetSizeOf(PyObject *o) { PyObject *res = NULL; PyObject *method; Py_ssize_t size; PyThreadState *tstate = _PyThreadState_GET(); /* Make sure the type is initialized. float gets initialized late */ if (PyType_Ready(Py_TYPE(o)) < 0) { return (size_t)-1; } method = _PyObject_LookupSpecial(o, &_Py_ID(__sizeof__)); if (method == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_Format(tstate, PyExc_TypeError, "Type %.100s doesn't define __sizeof__", Py_TYPE(o)->tp_name); } } else { res = _PyObject_CallNoArgs(method); Py_DECREF(method); } if (res == NULL) return (size_t)-1; size = PyLong_AsSsize_t(res); Py_DECREF(res); if (size == -1 && _PyErr_Occurred(tstate)) return (size_t)-1; if (size < 0) { _PyErr_SetString(tstate, PyExc_ValueError, "__sizeof__() should return >= 0"); return (size_t)-1; } return (size_t)size + _PyType_PreHeaderSize(Py_TYPE(o)); } static PyObject * sys_getsizeof(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"object", "default", 0}; size_t size; PyObject *o, *dflt = NULL; PyThreadState *tstate = _PyThreadState_GET(); if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getsizeof", kwlist, &o, &dflt)) { return NULL; } size = _PySys_GetSizeOf(o); if (size == (size_t)-1 && _PyErr_Occurred(tstate)) { /* Has a default value been given */ if (dflt != NULL && _PyErr_ExceptionMatches(tstate, PyExc_TypeError)) { _PyErr_Clear(tstate); return Py_NewRef(dflt); } else return NULL; } return PyLong_FromSize_t(size); } PyDoc_STRVAR(getsizeof_doc, "getsizeof(object [, default]) -> int\n\ \n\ Return the size of object in bytes."); /*[clinic input] sys.getrefcount -> Py_ssize_t object: object / Return the reference count of object. The count returned is generally one higher than you might expect, because it includes the (temporary) reference as an argument to getrefcount(). [clinic start generated code]*/ static Py_ssize_t sys_getrefcount_impl(PyObject *module, PyObject *object) /*[clinic end generated code: output=5fd477f2264b85b2 input=bf474efd50a21535]*/ { return Py_REFCNT(object); } #ifdef Py_REF_DEBUG /*[clinic input] sys.gettotalrefcount -> Py_ssize_t [clinic start generated code]*/ static Py_ssize_t sys_gettotalrefcount_impl(PyObject *module) /*[clinic end generated code: output=4103886cf17c25bc input=53b744faa5d2e4f6]*/ { /* It may make sense to return the total for the current interpreter or have a second function that does so. */ return _Py_GetGlobalRefTotal(); } #endif /* Py_REF_DEBUG */ /*[clinic input] sys.getallocatedblocks -> Py_ssize_t Return the number of memory blocks currently allocated. [clinic start generated code]*/ static Py_ssize_t sys_getallocatedblocks_impl(PyObject *module) /*[clinic end generated code: output=f0c4e873f0b6dcf7 input=dab13ee346a0673e]*/ { // It might make sense to return the count // for just the current interpreter. return _Py_GetGlobalAllocatedBlocks(); } /*[clinic input] sys.getunicodeinternedsize -> Py_ssize_t Return the number of elements of the unicode interned dictionary [clinic start generated code]*/ static Py_ssize_t sys_getunicodeinternedsize_impl(PyObject *module) /*[clinic end generated code: output=ad0e4c9738ed4129 input=726298eaa063347a]*/ { return _PyUnicode_InternedSize(); } /*[clinic input] sys._getframe depth: int = 0 / Return a frame object from the call stack. If optional integer depth is given, return the frame object that many calls below the top of the stack. If that is deeper than the call stack, ValueError is raised. The default for depth is zero, returning the frame at the top of the call stack. This function should be used for internal and specialized purposes only. [clinic start generated code]*/ static PyObject * sys__getframe_impl(PyObject *module, int depth) /*[clinic end generated code: output=d438776c04d59804 input=c1be8a6464b11ee5]*/ { PyThreadState *tstate = _PyThreadState_GET(); _PyInterpreterFrame *frame = tstate->cframe->current_frame; if (frame != NULL) { while (depth > 0) { frame = _PyFrame_GetFirstComplete(frame->previous); if (frame == NULL) { break; } --depth; } } if (frame == NULL) { _PyErr_SetString(tstate, PyExc_ValueError, "call stack is not deep enough"); return NULL; } PyObject *pyFrame = Py_XNewRef((PyObject *)_PyFrame_GetFrameObject(frame)); if (pyFrame && _PySys_Audit(tstate, "sys._getframe", "(O)", pyFrame) < 0) { Py_DECREF(pyFrame); return NULL; } return pyFrame; } /*[clinic input] sys._current_frames Return a dict mapping each thread's thread id to its current stack frame. This function should be used for specialized purposes only. [clinic start generated code]*/ static PyObject * sys__current_frames_impl(PyObject *module) /*[clinic end generated code: output=d2a41ac0a0a3809a input=2a9049c5f5033691]*/ { return _PyThread_CurrentFrames(); } /*[clinic input] sys._current_exceptions Return a dict mapping each thread's identifier to its current raised exception. This function should be used for specialized purposes only. [clinic start generated code]*/ static PyObject * sys__current_exceptions_impl(PyObject *module) /*[clinic end generated code: output=2ccfd838c746f0ba input=0e91818fbf2edc1f]*/ { return _PyThread_CurrentExceptions(); } /*[clinic input] sys.call_tracing func: object args as funcargs: object(subclass_of='&PyTuple_Type') / Call func(*args), while tracing is enabled. The tracing state is saved, and restored afterwards. This is intended to be called from a debugger from a checkpoint, to recursively debug some other code. [clinic start generated code]*/ static PyObject * sys_call_tracing_impl(PyObject *module, PyObject *func, PyObject *funcargs) /*[clinic end generated code: output=7e4999853cd4e5a6 input=5102e8b11049f92f]*/ { return _PyEval_CallTracing(func, funcargs); } #ifdef __cplusplus extern "C" { #endif /*[clinic input] sys._debugmallocstats Print summary info to stderr about the state of pymalloc's structures. In Py_DEBUG mode, also perform some expensive internal consistency checks. [clinic start generated code]*/ static PyObject * sys__debugmallocstats_impl(PyObject *module) /*[clinic end generated code: output=ec3565f8c7cee46a input=33c0c9c416f98424]*/ { #ifdef WITH_PYMALLOC if (_PyObject_DebugMallocStats(stderr)) { fputc('\n', stderr); } #endif _PyObject_DebugTypeStats(stderr); Py_RETURN_NONE; } #ifdef Py_TRACE_REFS /* Defined in objects.c because it uses static globals in that file */ extern PyObject *_Py_GetObjects(PyObject *, PyObject *); #endif #ifdef __cplusplus } #endif /*[clinic input] sys._clear_type_cache Clear the internal type lookup cache. [clinic start generated code]*/ static PyObject * sys__clear_type_cache_impl(PyObject *module) /*[clinic end generated code: output=20e48ca54a6f6971 input=127f3e04a8d9b555]*/ { PyType_ClearCache(); Py_RETURN_NONE; } /* Note that, for now, we do not have a per-interpreter equivalent for sys.is_finalizing(). */ /*[clinic input] sys.is_finalizing Return True if Python is exiting. [clinic start generated code]*/ static PyObject * sys_is_finalizing_impl(PyObject *module) /*[clinic end generated code: output=735b5ff7962ab281 input=f0df747a039948a5]*/ { return PyBool_FromLong(_Py_IsFinalizing()); } #ifdef Py_STATS /*[clinic input] sys._stats_on Turns on stats gathering (stats gathering is on by default). [clinic start generated code]*/ static PyObject * sys__stats_on_impl(PyObject *module) /*[clinic end generated code: output=aca53eafcbb4d9fe input=8ddc6df94e484f3a]*/ { _py_stats = &_py_stats_struct; Py_RETURN_NONE; } /*[clinic input] sys._stats_off Turns off stats gathering (stats gathering is on by default). [clinic start generated code]*/ static PyObject * sys__stats_off_impl(PyObject *module) /*[clinic end generated code: output=1534c1ee63812214 input=b3e50e71ecf29f66]*/ { _py_stats = NULL; Py_RETURN_NONE; } /*[clinic input] sys._stats_clear Clears the stats. [clinic start generated code]*/ static PyObject * sys__stats_clear_impl(PyObject *module) /*[clinic end generated code: output=fb65a2525ee50604 input=3e03f2654f44da96]*/ { _Py_StatsClear(); Py_RETURN_NONE; } /*[clinic input] sys._stats_dump Dump stats to file, and clears the stats. [clinic start generated code]*/ static PyObject * sys__stats_dump_impl(PyObject *module) /*[clinic end generated code: output=79f796fb2b4ddf05 input=92346f16d64f6f95]*/ { _Py_PrintSpecializationStats(1); _Py_StatsClear(); Py_RETURN_NONE; } #endif #ifdef ANDROID_API_LEVEL /*[clinic input] sys.getandroidapilevel Return the build time API version of Android as an integer. [clinic start generated code]*/ static PyObject * sys_getandroidapilevel_impl(PyObject *module) /*[clinic end generated code: output=214abf183a1c70c1 input=3e6d6c9fcdd24ac6]*/ { return PyLong_FromLong(ANDROID_API_LEVEL); } #endif /* ANDROID_API_LEVEL */ /*[clinic input] sys.activate_stack_trampoline backend: str / Activate stack profiler trampoline *backend*. [clinic start generated code]*/ static PyObject * sys_activate_stack_trampoline_impl(PyObject *module, const char *backend) /*[clinic end generated code: output=5783cdeb51874b43 input=a12df928758a82b4]*/ { #ifdef PY_HAVE_PERF_TRAMPOLINE if (strcmp(backend, "perf") == 0) { _PyPerf_Callbacks cur_cb; _PyPerfTrampoline_GetCallbacks(&cur_cb); if (cur_cb.write_state != _Py_perfmap_callbacks.write_state) { if (_PyPerfTrampoline_SetCallbacks(&_Py_perfmap_callbacks) < 0 ) { PyErr_SetString(PyExc_ValueError, "can't activate perf trampoline"); return NULL; } } } else { PyErr_Format(PyExc_ValueError, "invalid backend: %s", backend); return NULL; } if (_PyPerfTrampoline_Init(1) < 0) { return NULL; } Py_RETURN_NONE; #else PyErr_SetString(PyExc_ValueError, "perf trampoline not available"); return NULL; #endif } /*[clinic input] sys.deactivate_stack_trampoline Deactivate the current stack profiler trampoline backend. If no stack profiler is activated, this function has no effect. [clinic start generated code]*/ static PyObject * sys_deactivate_stack_trampoline_impl(PyObject *module) /*[clinic end generated code: output=b50da25465df0ef1 input=9f629a6be9fe7fc8]*/ { if (_PyPerfTrampoline_Init(0) < 0) { return NULL; } Py_RETURN_NONE; } /*[clinic input] sys.is_stack_trampoline_active Return *True* if a stack profiler trampoline is active. [clinic start generated code]*/ static PyObject * sys_is_stack_trampoline_active_impl(PyObject *module) /*[clinic end generated code: output=ab2746de0ad9d293 input=29616b7bf6a0b703]*/ { #ifdef PY_HAVE_PERF_TRAMPOLINE if (_PyIsPerfTrampolineActive()) { Py_RETURN_TRUE; } #endif Py_RETURN_FALSE; } /*[clinic input] sys._getframemodulename depth: int = 0 Return the name of the module for a calling frame. The default depth returns the module containing the call to this API. A more typical use in a library will pass a depth of 1 to get the user's module rather than the library module. If no frame, module, or name can be found, returns None. [clinic start generated code]*/ static PyObject * sys__getframemodulename_impl(PyObject *module, int depth) /*[clinic end generated code: output=1d70ef691f09d2db input=d4f1a8ed43b8fb46]*/ { if (PySys_Audit("sys._getframemodulename", "i", depth) < 0) { return NULL; } _PyInterpreterFrame *f = _PyThreadState_GET()->cframe->current_frame; while (f && (_PyFrame_IsIncomplete(f) || depth-- > 0)) { f = f->previous; } if (f == NULL || f->f_funcobj == NULL) { Py_RETURN_NONE; } PyObject *r = PyFunction_GetModule(f->f_funcobj); if (!r) { PyErr_Clear(); r = Py_None; } return Py_NewRef(r); } #ifdef __cplusplus extern "C" { #endif static PerfMapState perf_map_state; PyAPI_FUNC(int) PyUnstable_PerfMapState_Init(void) { #ifndef MS_WINDOWS char filename[100]; pid_t pid = getpid(); // Use nofollow flag to prevent symlink attacks. int flags = O_WRONLY | O_CREAT | O_APPEND | O_NOFOLLOW | O_CLOEXEC; snprintf(filename, sizeof(filename) - 1, "/tmp/perf-%jd.map", (intmax_t)pid); int fd = open(filename, flags, 0600); if (fd == -1) { return -1; } else{ perf_map_state.perf_map = fdopen(fd, "a"); if (perf_map_state.perf_map == NULL) { close(fd); return -1; } } perf_map_state.map_lock = PyThread_allocate_lock(); if (perf_map_state.map_lock == NULL) { fclose(perf_map_state.perf_map); return -2; } #endif return 0; } PyAPI_FUNC(int) PyUnstable_WritePerfMapEntry( const void *code_addr, unsigned int code_size, const char *entry_name ) { #ifndef MS_WINDOWS if (perf_map_state.perf_map == NULL) { int ret = PyUnstable_PerfMapState_Init(); if(ret != 0){ return ret; } } PyThread_acquire_lock(perf_map_state.map_lock, 1); fprintf(perf_map_state.perf_map, "%" PRIxPTR " %x %s\n", (uintptr_t) code_addr, code_size, entry_name); fflush(perf_map_state.perf_map); PyThread_release_lock(perf_map_state.map_lock); #endif return 0; } PyAPI_FUNC(void) PyUnstable_PerfMapState_Fini(void) { #ifndef MS_WINDOWS if (perf_map_state.perf_map != NULL) { // close the file PyThread_acquire_lock(perf_map_state.map_lock, 1); fclose(perf_map_state.perf_map); PyThread_release_lock(perf_map_state.map_lock); // clean up the lock and state PyThread_free_lock(perf_map_state.map_lock); perf_map_state.perf_map = NULL; } #endif } #ifdef __cplusplus } #endif static PyMethodDef sys_methods[] = { /* Might as well keep this in alphabetic order */ SYS_ADDAUDITHOOK_METHODDEF {"audit", _PyCFunction_CAST(sys_audit), METH_FASTCALL, audit_doc }, {"breakpointhook", _PyCFunction_CAST(sys_breakpointhook), METH_FASTCALL | METH_KEYWORDS, breakpointhook_doc}, SYS__CLEAR_TYPE_CACHE_METHODDEF SYS__CURRENT_FRAMES_METHODDEF SYS__CURRENT_EXCEPTIONS_METHODDEF SYS_DISPLAYHOOK_METHODDEF SYS_EXCEPTION_METHODDEF SYS_EXC_INFO_METHODDEF SYS_EXCEPTHOOK_METHODDEF SYS_EXIT_METHODDEF SYS_GETDEFAULTENCODING_METHODDEF SYS_GETDLOPENFLAGS_METHODDEF SYS_GETALLOCATEDBLOCKS_METHODDEF SYS_GETUNICODEINTERNEDSIZE_METHODDEF SYS_GETFILESYSTEMENCODING_METHODDEF SYS_GETFILESYSTEMENCODEERRORS_METHODDEF #ifdef Py_TRACE_REFS {"getobjects", _Py_GetObjects, METH_VARARGS}, #endif SYS_GETTOTALREFCOUNT_METHODDEF SYS_GETREFCOUNT_METHODDEF SYS_GETRECURSIONLIMIT_METHODDEF {"getsizeof", _PyCFunction_CAST(sys_getsizeof), METH_VARARGS | METH_KEYWORDS, getsizeof_doc}, SYS__GETFRAME_METHODDEF SYS__GETFRAMEMODULENAME_METHODDEF SYS_GETWINDOWSVERSION_METHODDEF SYS__ENABLELEGACYWINDOWSFSENCODING_METHODDEF SYS_INTERN_METHODDEF SYS_IS_FINALIZING_METHODDEF SYS_MDEBUG_METHODDEF SYS_SETSWITCHINTERVAL_METHODDEF SYS_GETSWITCHINTERVAL_METHODDEF SYS_SETDLOPENFLAGS_METHODDEF {"setprofile", sys_setprofile, METH_O, setprofile_doc}, SYS__SETPROFILEALLTHREADS_METHODDEF SYS_GETPROFILE_METHODDEF SYS_SETRECURSIONLIMIT_METHODDEF {"settrace", sys_settrace, METH_O, settrace_doc}, SYS__SETTRACEALLTHREADS_METHODDEF SYS_GETTRACE_METHODDEF SYS_CALL_TRACING_METHODDEF SYS__DEBUGMALLOCSTATS_METHODDEF SYS_SET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF SYS_GET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF {"set_asyncgen_hooks", _PyCFunction_CAST(sys_set_asyncgen_hooks), METH_VARARGS | METH_KEYWORDS, set_asyncgen_hooks_doc}, SYS_GET_ASYNCGEN_HOOKS_METHODDEF SYS_GETANDROIDAPILEVEL_METHODDEF SYS_ACTIVATE_STACK_TRAMPOLINE_METHODDEF SYS_DEACTIVATE_STACK_TRAMPOLINE_METHODDEF SYS_IS_STACK_TRAMPOLINE_ACTIVE_METHODDEF SYS_UNRAISABLEHOOK_METHODDEF SYS_GET_INT_MAX_STR_DIGITS_METHODDEF SYS_SET_INT_MAX_STR_DIGITS_METHODDEF #ifdef Py_STATS SYS__STATS_ON_METHODDEF SYS__STATS_OFF_METHODDEF SYS__STATS_CLEAR_METHODDEF SYS__STATS_DUMP_METHODDEF #endif {NULL, NULL} // sentinel }; static PyObject * list_builtin_module_names(void) { PyObject *list = _PyImport_GetBuiltinModuleNames(); if (list == NULL) { return NULL; } if (PyList_Sort(list) != 0) { goto error; } PyObject *tuple = PyList_AsTuple(list); Py_DECREF(list); return tuple; error: Py_DECREF(list); return NULL; } static PyObject * list_stdlib_module_names(void) { Py_ssize_t len = Py_ARRAY_LENGTH(_Py_stdlib_module_names); PyObject *names = PyTuple_New(len); if (names == NULL) { return NULL; } for (Py_ssize_t i = 0; i < len; i++) { PyObject *name = PyUnicode_FromString(_Py_stdlib_module_names[i]); if (name == NULL) { Py_DECREF(names); return NULL; } PyTuple_SET_ITEM(names, i, name); } PyObject *set = PyObject_CallFunction((PyObject *)&PyFrozenSet_Type, "(O)", names); Py_DECREF(names); return set; } /* Pre-initialization support for sys.warnoptions and sys._xoptions * * Modern internal code paths: * These APIs get called after _Py_InitializeCore and get to use the * regular CPython list, dict, and unicode APIs. * * Legacy embedding code paths: * The multi-phase initialization API isn't public yet, so embedding * apps still need to be able configure sys.warnoptions and sys._xoptions * before they call Py_Initialize. To support this, we stash copies of * the supplied wchar * sequences in linked lists, and then migrate the * contents of those lists to the sys module in _PyInitializeCore. * */ struct _preinit_entry { wchar_t *value; struct _preinit_entry *next; }; typedef struct _preinit_entry *_Py_PreInitEntry; static _Py_PreInitEntry _preinit_warnoptions = NULL; static _Py_PreInitEntry _preinit_xoptions = NULL; static _Py_PreInitEntry _alloc_preinit_entry(const wchar_t *value) { /* To get this to work, we have to initialize the runtime implicitly */ _PyRuntime_Initialize(); /* Force default allocator, so we can ensure that it also gets used to * destroy the linked list in _clear_preinit_entries. */ PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); _Py_PreInitEntry node = PyMem_RawCalloc(1, sizeof(*node)); if (node != NULL) { node->value = _PyMem_RawWcsdup(value); if (node->value == NULL) { PyMem_RawFree(node); node = NULL; }; }; PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); return node; } static int _append_preinit_entry(_Py_PreInitEntry *optionlist, const wchar_t *value) { _Py_PreInitEntry new_entry = _alloc_preinit_entry(value); if (new_entry == NULL) { return -1; } /* We maintain the linked list in this order so it's easy to play back * the add commands in the same order later on in _Py_InitializeCore */ _Py_PreInitEntry last_entry = *optionlist; if (last_entry == NULL) { *optionlist = new_entry; } else { while (last_entry->next != NULL) { last_entry = last_entry->next; } last_entry->next = new_entry; } return 0; } static void _clear_preinit_entries(_Py_PreInitEntry *optionlist) { _Py_PreInitEntry current = *optionlist; *optionlist = NULL; /* Deallocate the nodes and their contents using the default allocator */ PyMemAllocatorEx old_alloc; _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); while (current != NULL) { _Py_PreInitEntry next = current->next; PyMem_RawFree(current->value); PyMem_RawFree(current); current = next; } PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); } PyStatus _PySys_ReadPreinitWarnOptions(PyWideStringList *options) { PyStatus status; _Py_PreInitEntry entry; for (entry = _preinit_warnoptions; entry != NULL; entry = entry->next) { status = PyWideStringList_Append(options, entry->value); if (_PyStatus_EXCEPTION(status)) { return status; } } _clear_preinit_entries(&_preinit_warnoptions); return _PyStatus_OK(); } PyStatus _PySys_ReadPreinitXOptions(PyConfig *config) { PyStatus status; _Py_PreInitEntry entry; for (entry = _preinit_xoptions; entry != NULL; entry = entry->next) { status = PyWideStringList_Append(&config->xoptions, entry->value); if (_PyStatus_EXCEPTION(status)) { return status; } } _clear_preinit_entries(&_preinit_xoptions); return _PyStatus_OK(); } static PyObject * get_warnoptions(PyThreadState *tstate) { PyObject *warnoptions = _PySys_GetAttr(tstate, &_Py_ID(warnoptions)); if (warnoptions == NULL || !PyList_Check(warnoptions)) { /* PEP432 TODO: we can reach this if warnoptions is NULL in the main * interpreter config. When that happens, we need to properly set * the `warnoptions` reference in the main interpreter config as well. * * For Python 3.7, we shouldn't be able to get here due to the * combination of how _PyMainInterpreter_ReadConfig and _PySys_EndInit * work, but we expect 3.8+ to make the _PyMainInterpreter_ReadConfig * call optional for embedding applications, thus making this * reachable again. */ warnoptions = PyList_New(0); if (warnoptions == NULL) { return NULL; } if (sys_set_object(tstate->interp, &_Py_ID(warnoptions), warnoptions)) { Py_DECREF(warnoptions); return NULL; } Py_DECREF(warnoptions); } return warnoptions; } void PySys_ResetWarnOptions(void) { PyThreadState *tstate = _PyThreadState_GET(); if (tstate == NULL) { _clear_preinit_entries(&_preinit_warnoptions); return; } PyObject *warnoptions = _PySys_GetAttr(tstate, &_Py_ID(warnoptions)); if (warnoptions == NULL || !PyList_Check(warnoptions)) return; PyList_SetSlice(warnoptions, 0, PyList_GET_SIZE(warnoptions), NULL); } static int _PySys_AddWarnOptionWithError(PyThreadState *tstate, PyObject *option) { PyObject *warnoptions = get_warnoptions(tstate); if (warnoptions == NULL) { return -1; } if (PyList_Append(warnoptions, option)) { return -1; } return 0; } void PySys_AddWarnOptionUnicode(PyObject *option) { PyThreadState *tstate = _PyThreadState_GET(); if (_PySys_AddWarnOptionWithError(tstate, option) < 0) { /* No return value, therefore clear error state if possible */ if (tstate) { _PyErr_Clear(tstate); } } } void PySys_AddWarnOption(const wchar_t *s) { PyThreadState *tstate = _PyThreadState_GET(); if (tstate == NULL) { _append_preinit_entry(&_preinit_warnoptions, s); return; } PyObject *unicode; unicode = PyUnicode_FromWideChar(s, -1); if (unicode == NULL) return; _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS PySys_AddWarnOptionUnicode(unicode); _Py_COMP_DIAG_POP Py_DECREF(unicode); } int PySys_HasWarnOptions(void) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *warnoptions = _PySys_GetAttr(tstate, &_Py_ID(warnoptions)); return (warnoptions != NULL && PyList_Check(warnoptions) && PyList_GET_SIZE(warnoptions) > 0); } static PyObject * get_xoptions(PyThreadState *tstate) { PyObject *xoptions = _PySys_GetAttr(tstate, &_Py_ID(_xoptions)); if (xoptions == NULL || !PyDict_Check(xoptions)) { /* PEP432 TODO: we can reach this if xoptions is NULL in the main * interpreter config. When that happens, we need to properly set * the `xoptions` reference in the main interpreter config as well. * * For Python 3.7, we shouldn't be able to get here due to the * combination of how _PyMainInterpreter_ReadConfig and _PySys_EndInit * work, but we expect 3.8+ to make the _PyMainInterpreter_ReadConfig * call optional for embedding applications, thus making this * reachable again. */ xoptions = PyDict_New(); if (xoptions == NULL) { return NULL; } if (sys_set_object(tstate->interp, &_Py_ID(_xoptions), xoptions)) { Py_DECREF(xoptions); return NULL; } Py_DECREF(xoptions); } return xoptions; } static int _PySys_AddXOptionWithError(const wchar_t *s) { PyObject *name = NULL, *value = NULL; PyThreadState *tstate = _PyThreadState_GET(); PyObject *opts = get_xoptions(tstate); if (opts == NULL) { goto error; } const wchar_t *name_end = wcschr(s, L'='); if (!name_end) { name = PyUnicode_FromWideChar(s, -1); value = Py_NewRef(Py_True); } else { name = PyUnicode_FromWideChar(s, name_end - s); value = PyUnicode_FromWideChar(name_end + 1, -1); } if (name == NULL || value == NULL) { goto error; } if (PyDict_SetItem(opts, name, value) < 0) { goto error; } Py_DECREF(name); Py_DECREF(value); return 0; error: Py_XDECREF(name); Py_XDECREF(value); return -1; } void PySys_AddXOption(const wchar_t *s) { PyThreadState *tstate = _PyThreadState_GET(); if (tstate == NULL) { _append_preinit_entry(&_preinit_xoptions, s); return; } if (_PySys_AddXOptionWithError(s) < 0) { /* No return value, therefore clear error state if possible */ _PyErr_Clear(tstate); } } PyObject * PySys_GetXOptions(void) { PyThreadState *tstate = _PyThreadState_GET(); return get_xoptions(tstate); } /* XXX This doc string is too long to be a single string literal in VC++ 5.0. Two literals concatenated works just fine. If you have a K&R compiler or other abomination that however *does* understand longer strings, get rid of the !!! comment in the middle and the quotes that surround it. */ PyDoc_VAR(sys_doc) = PyDoc_STR( "This module provides access to some objects used or maintained by the\n\ interpreter and to functions that interact strongly with the interpreter.\n\ \n\ Dynamic objects:\n\ \n\ argv -- command line arguments; argv[0] is the script pathname if known\n\ path -- module search path; path[0] is the script directory, else ''\n\ modules -- dictionary of loaded modules\n\ \n\ displayhook -- called to show results in an interactive session\n\ excepthook -- called to handle any uncaught exception other than SystemExit\n\ To customize printing in an interactive session or to install a custom\n\ top-level exception handler, assign other functions to replace these.\n\ \n\ stdin -- standard input file object; used by input()\n\ stdout -- standard output file object; used by print()\n\ stderr -- standard error object; used for error messages\n\ By assigning other file objects (or objects that behave like files)\n\ to these, it is possible to redirect all of the interpreter's I/O.\n\ \n\ last_exc - the last uncaught exception\n\ Only available in an interactive session after a\n\ traceback has been printed.\n\ last_type -- type of last uncaught exception\n\ last_value -- value of last uncaught exception\n\ last_traceback -- traceback of last uncaught exception\n\ These three are the (deprecated) legacy representation of last_exc.\n\ " ) /* concatenating string here */ PyDoc_STR( "\n\ Static objects:\n\ \n\ builtin_module_names -- tuple of module names built into this interpreter\n\ copyright -- copyright notice pertaining to this interpreter\n\ exec_prefix -- prefix used to find the machine-specific Python library\n\ executable -- absolute path of the executable binary of the Python interpreter\n\ float_info -- a named tuple with information about the float implementation.\n\ float_repr_style -- string indicating the style of repr() output for floats\n\ hash_info -- a named tuple with information about the hash algorithm.\n\ hexversion -- version information encoded as a single integer\n\ implementation -- Python implementation information.\n\ int_info -- a named tuple with information about the int implementation.\n\ maxsize -- the largest supported length of containers.\n\ maxunicode -- the value of the largest Unicode code point\n\ platform -- platform identifier\n\ prefix -- prefix used to find the Python library\n\ thread_info -- a named tuple with information about the thread implementation.\n\ version -- the version of this interpreter as a string\n\ version_info -- version information as a named tuple\n\ " ) #ifdef MS_COREDLL /* concatenating string here */ PyDoc_STR( "dllhandle -- [Windows only] integer handle of the Python DLL\n\ winver -- [Windows only] version number of the Python DLL\n\ " ) #endif /* MS_COREDLL */ #ifdef MS_WINDOWS /* concatenating string here */ PyDoc_STR( "_enablelegacywindowsfsencoding -- [Windows only]\n\ " ) #endif PyDoc_STR( "__stdin__ -- the original stdin; don't touch!\n\ __stdout__ -- the original stdout; don't touch!\n\ __stderr__ -- the original stderr; don't touch!\n\ __displayhook__ -- the original displayhook; don't touch!\n\ __excepthook__ -- the original excepthook; don't touch!\n\ \n\ Functions:\n\ \n\ displayhook() -- print an object to the screen, and save it in builtins._\n\ excepthook() -- print an exception and its traceback to sys.stderr\n\ exception() -- return the current thread's active exception\n\ exc_info() -- return information about the current thread's active exception\n\ exit() -- exit the interpreter by raising SystemExit\n\ getdlopenflags() -- returns flags to be used for dlopen() calls\n\ getprofile() -- get the global profiling function\n\ getrefcount() -- return the reference count for an object (plus one :-)\n\ getrecursionlimit() -- return the max recursion depth for the interpreter\n\ getsizeof() -- return the size of an object in bytes\n\ gettrace() -- get the global debug tracing function\n\ setdlopenflags() -- set the flags to be used for dlopen() calls\n\ setprofile() -- set the global profiling function\n\ setrecursionlimit() -- set the max recursion depth for the interpreter\n\ settrace() -- set the global debug tracing function\n\ " ) /* end of sys_doc */ ; PyDoc_STRVAR(flags__doc__, "sys.flags\n\ \n\ Flags provided through command line arguments or environment vars."); static PyTypeObject FlagsType; static PyStructSequence_Field flags_fields[] = { {"debug", "-d"}, {"inspect", "-i"}, {"interactive", "-i"}, {"optimize", "-O or -OO"}, {"dont_write_bytecode", "-B"}, {"no_user_site", "-s"}, {"no_site", "-S"}, {"ignore_environment", "-E"}, {"verbose", "-v"}, {"bytes_warning", "-b"}, {"quiet", "-q"}, {"hash_randomization", "-R"}, {"isolated", "-I"}, {"dev_mode", "-X dev"}, {"utf8_mode", "-X utf8"}, {"warn_default_encoding", "-X warn_default_encoding"}, {"safe_path", "-P"}, {"int_max_str_digits", "-X int_max_str_digits"}, {0} }; static PyStructSequence_Desc flags_desc = { "sys.flags", /* name */ flags__doc__, /* doc */ flags_fields, /* fields */ 18 }; static int set_flags_from_config(PyInterpreterState *interp, PyObject *flags) { const PyPreConfig *preconfig = &interp->runtime->preconfig; const PyConfig *config = _PyInterpreterState_GetConfig(interp); // _PySys_UpdateConfig() modifies sys.flags in-place: // Py_XDECREF() is needed in this case. Py_ssize_t pos = 0; #define SetFlagObj(expr) \ do { \ PyObject *value = (expr); \ if (value == NULL) { \ return -1; \ } \ Py_XDECREF(PyStructSequence_GET_ITEM(flags, pos)); \ PyStructSequence_SET_ITEM(flags, pos, value); \ pos++; \ } while (0) #define SetFlag(expr) SetFlagObj(PyLong_FromLong(expr)) SetFlag(config->parser_debug); SetFlag(config->inspect); SetFlag(config->interactive); SetFlag(config->optimization_level); SetFlag(!config->write_bytecode); SetFlag(!config->user_site_directory); SetFlag(!config->site_import); SetFlag(!config->use_environment); SetFlag(config->verbose); SetFlag(config->bytes_warning); SetFlag(config->quiet); SetFlag(config->use_hash_seed == 0 || config->hash_seed != 0); SetFlag(config->isolated); SetFlagObj(PyBool_FromLong(config->dev_mode)); SetFlag(preconfig->utf8_mode); SetFlag(config->warn_default_encoding); SetFlagObj(PyBool_FromLong(config->safe_path)); SetFlag(config->int_max_str_digits); #undef SetFlagObj #undef SetFlag return 0; } static PyObject* make_flags(PyInterpreterState *interp) { PyObject *flags = PyStructSequence_New(&FlagsType); if (flags == NULL) { return NULL; } if (set_flags_from_config(interp, flags) < 0) { Py_DECREF(flags); return NULL; } return flags; } PyDoc_STRVAR(version_info__doc__, "sys.version_info\n\ \n\ Version information as a named tuple."); static PyTypeObject VersionInfoType; static PyStructSequence_Field version_info_fields[] = { {"major", "Major release number"}, {"minor", "Minor release number"}, {"micro", "Patch release number"}, {"releaselevel", "'alpha', 'beta', 'candidate', or 'final'"}, {"serial", "Serial release number"}, {0} }; static PyStructSequence_Desc version_info_desc = { "sys.version_info", /* name */ version_info__doc__, /* doc */ version_info_fields, /* fields */ 5 }; static PyObject * make_version_info(PyThreadState *tstate) { PyObject *version_info; char *s; int pos = 0; version_info = PyStructSequence_New(&VersionInfoType); if (version_info == NULL) { return NULL; } /* * These release level checks are mutually exclusive and cover * the field, so don't get too fancy with the pre-processor! */ #if PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_ALPHA s = "alpha"; #elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_BETA s = "beta"; #elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_GAMMA s = "candidate"; #elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_FINAL s = "final"; #endif #define SetIntItem(flag) \ PyStructSequence_SET_ITEM(version_info, pos++, PyLong_FromLong(flag)) #define SetStrItem(flag) \ PyStructSequence_SET_ITEM(version_info, pos++, PyUnicode_FromString(flag)) SetIntItem(PY_MAJOR_VERSION); SetIntItem(PY_MINOR_VERSION); SetIntItem(PY_MICRO_VERSION); SetStrItem(s); SetIntItem(PY_RELEASE_SERIAL); #undef SetIntItem #undef SetStrItem if (_PyErr_Occurred(tstate)) { Py_CLEAR(version_info); return NULL; } return version_info; } /* sys.implementation values */ #define NAME "cpython" const char *_PySys_ImplName = NAME; #define MAJOR Py_STRINGIFY(PY_MAJOR_VERSION) #define MINOR Py_STRINGIFY(PY_MINOR_VERSION) #define TAG NAME "-" MAJOR MINOR const char *_PySys_ImplCacheTag = TAG; #undef NAME #undef MAJOR #undef MINOR #undef TAG static PyObject * make_impl_info(PyObject *version_info) { int res; PyObject *impl_info, *value, *ns; impl_info = PyDict_New(); if (impl_info == NULL) return NULL; /* populate the dict */ value = PyUnicode_FromString(_PySys_ImplName); if (value == NULL) goto error; res = PyDict_SetItemString(impl_info, "name", value); Py_DECREF(value); if (res < 0) goto error; value = PyUnicode_FromString(_PySys_ImplCacheTag); if (value == NULL) goto error; res = PyDict_SetItemString(impl_info, "cache_tag", value); Py_DECREF(value); if (res < 0) goto error; res = PyDict_SetItemString(impl_info, "version", version_info); if (res < 0) goto error; value = PyLong_FromLong(PY_VERSION_HEX); if (value == NULL) goto error; res = PyDict_SetItemString(impl_info, "hexversion", value); Py_DECREF(value); if (res < 0) goto error; #ifdef MULTIARCH value = PyUnicode_FromString(MULTIARCH); if (value == NULL) goto error; res = PyDict_SetItemString(impl_info, "_multiarch", value); Py_DECREF(value); if (res < 0) goto error; #endif /* dict ready */ ns = _PyNamespace_New(impl_info); Py_DECREF(impl_info); return ns; error: Py_CLEAR(impl_info); return NULL; } #ifdef __EMSCRIPTEN__ PyDoc_STRVAR(emscripten_info__doc__, "sys._emscripten_info\n\ \n\ WebAssembly Emscripten platform information."); static PyTypeObject *EmscriptenInfoType; static PyStructSequence_Field emscripten_info_fields[] = { {"emscripten_version", "Emscripten version (major, minor, micro)"}, {"runtime", "Runtime (Node.JS version, browser user agent)"}, {"pthreads", "pthread support"}, {"shared_memory", "shared memory support"}, {0} }; static PyStructSequence_Desc emscripten_info_desc = { "sys._emscripten_info", /* name */ emscripten_info__doc__ , /* doc */ emscripten_info_fields, /* fields */ 4 }; EM_JS(char *, _Py_emscripten_runtime, (void), { var info; if (typeof navigator == 'object') { info = navigator.userAgent; } else if (typeof process == 'object') { info = "Node.js ".concat(process.version); } else { info = "UNKNOWN"; } var len = lengthBytesUTF8(info) + 1; var res = _malloc(len); if (res) stringToUTF8(info, res, len); #if __wasm64__ return BigInt(res); #else return res; #endif }); static PyObject * make_emscripten_info(void) { PyObject *emscripten_info = NULL; PyObject *version = NULL; char *ua; int pos = 0; emscripten_info = PyStructSequence_New(EmscriptenInfoType); if (emscripten_info == NULL) { return NULL; } version = Py_BuildValue("(iii)", __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__); if (version == NULL) { goto error; } PyStructSequence_SET_ITEM(emscripten_info, pos++, version); ua = _Py_emscripten_runtime(); if (ua != NULL) { PyObject *oua = PyUnicode_DecodeUTF8(ua, strlen(ua), "strict"); free(ua); if (oua == NULL) { goto error; } PyStructSequence_SET_ITEM(emscripten_info, pos++, oua); } else { PyStructSequence_SET_ITEM(emscripten_info, pos++, Py_NewRef(Py_None)); } #define SetBoolItem(flag) \ PyStructSequence_SET_ITEM(emscripten_info, pos++, PyBool_FromLong(flag)) #ifdef __EMSCRIPTEN_PTHREADS__ SetBoolItem(1); #else SetBoolItem(0); #endif #ifdef __EMSCRIPTEN_SHARED_MEMORY__ SetBoolItem(1); #else SetBoolItem(0); #endif #undef SetBoolItem if (PyErr_Occurred()) { goto error; } return emscripten_info; error: Py_CLEAR(emscripten_info); return NULL; } #endif // __EMSCRIPTEN__ static struct PyModuleDef sysmodule = { PyModuleDef_HEAD_INIT, "sys", sys_doc, -1, /* multiple "initialization" just copies the module dict. */ sys_methods, NULL, NULL, NULL, NULL }; /* Updating the sys namespace, returning NULL pointer on error */ #define SET_SYS(key, value) \ do { \ PyObject *v = (value); \ if (v == NULL) { \ goto err_occurred; \ } \ res = PyDict_SetItemString(sysdict, key, v); \ Py_DECREF(v); \ if (res < 0) { \ goto err_occurred; \ } \ } while (0) #define SET_SYS_FROM_STRING(key, value) \ SET_SYS(key, PyUnicode_FromString(value)) static PyStatus _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) { PyObject *version_info; int res; PyInterpreterState *interp = tstate->interp; /* stdin/stdout/stderr are set in pylifecycle.c */ #define COPY_SYS_ATTR(tokey, fromkey) \ SET_SYS(tokey, PyMapping_GetItemString(sysdict, fromkey)) COPY_SYS_ATTR("__displayhook__", "displayhook"); COPY_SYS_ATTR("__excepthook__", "excepthook"); COPY_SYS_ATTR("__breakpointhook__", "breakpointhook"); COPY_SYS_ATTR("__unraisablehook__", "unraisablehook"); #undef COPY_SYS_ATTR SET_SYS_FROM_STRING("version", Py_GetVersion()); SET_SYS("hexversion", PyLong_FromLong(PY_VERSION_HEX)); SET_SYS("_git", Py_BuildValue("(szz)", "CPython", _Py_gitidentifier(), _Py_gitversion())); SET_SYS_FROM_STRING("_framework", _PYTHONFRAMEWORK); SET_SYS("api_version", PyLong_FromLong(PYTHON_API_VERSION)); SET_SYS_FROM_STRING("copyright", Py_GetCopyright()); SET_SYS_FROM_STRING("platform", Py_GetPlatform()); SET_SYS("maxsize", PyLong_FromSsize_t(PY_SSIZE_T_MAX)); SET_SYS("float_info", PyFloat_GetInfo()); SET_SYS("int_info", PyLong_GetInfo()); /* initialize hash_info */ if (_PyStructSequence_InitBuiltin(interp, &Hash_InfoType, &hash_info_desc) < 0) { goto type_init_failed; } SET_SYS("hash_info", get_hash_info(tstate)); SET_SYS("maxunicode", PyLong_FromLong(0x10FFFF)); SET_SYS("builtin_module_names", list_builtin_module_names()); SET_SYS("stdlib_module_names", list_stdlib_module_names()); #if PY_BIG_ENDIAN SET_SYS_FROM_STRING("byteorder", "big"); #else SET_SYS_FROM_STRING("byteorder", "little"); #endif #ifdef MS_COREDLL SET_SYS("dllhandle", PyLong_FromVoidPtr(PyWin_DLLhModule)); SET_SYS_FROM_STRING("winver", PyWin_DLLVersionString); #endif #ifdef ABIFLAGS SET_SYS_FROM_STRING("abiflags", ABIFLAGS); #endif #define ENSURE_INFO_TYPE(TYPE, DESC) \ do { \ if (_PyStructSequence_InitBuiltinWithFlags( \ interp, &TYPE, &DESC, Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) { \ goto type_init_failed; \ } \ } while (0) /* version_info */ ENSURE_INFO_TYPE(VersionInfoType, version_info_desc); version_info = make_version_info(tstate); SET_SYS("version_info", version_info); /* implementation */ SET_SYS("implementation", make_impl_info(version_info)); // sys.flags: updated in-place later by _PySys_UpdateConfig() ENSURE_INFO_TYPE(FlagsType, flags_desc); SET_SYS("flags", make_flags(tstate->interp)); #if defined(MS_WINDOWS) /* getwindowsversion */ ENSURE_INFO_TYPE(WindowsVersionType, windows_version_desc); SET_SYS_FROM_STRING("_vpath", VPATH); #endif #undef ENSURE_INFO_TYPE /* float repr style: 0.03 (short) vs 0.029999999999999999 (legacy) */ #if _PY_SHORT_FLOAT_REPR == 1 SET_SYS_FROM_STRING("float_repr_style", "short"); #else SET_SYS_FROM_STRING("float_repr_style", "legacy"); #endif SET_SYS("thread_info", PyThread_GetInfo()); /* initialize asyncgen_hooks */ if (_PyStructSequence_InitBuiltin(interp, &AsyncGenHooksType, &asyncgen_hooks_desc) < 0) { goto type_init_failed; } #ifdef __EMSCRIPTEN__ if (EmscriptenInfoType == NULL) { EmscriptenInfoType = PyStructSequence_NewType(&emscripten_info_desc); if (EmscriptenInfoType == NULL) { goto type_init_failed; } } SET_SYS("_emscripten_info", make_emscripten_info()); #endif /* adding sys.path_hooks and sys.path_importer_cache */ SET_SYS("meta_path", PyList_New(0)); SET_SYS("path_importer_cache", PyDict_New()); SET_SYS("path_hooks", PyList_New(0)); if (_PyErr_Occurred(tstate)) { goto err_occurred; } return _PyStatus_OK(); type_init_failed: return _PyStatus_ERR("failed to initialize a type"); err_occurred: return _PyStatus_ERR("can't initialize sys module"); } static int sys_add_xoption(PyObject *opts, const wchar_t *s) { PyObject *name, *value; const wchar_t *name_end = wcschr(s, L'='); if (!name_end) { name = PyUnicode_FromWideChar(s, -1); value = Py_NewRef(Py_True); } else { name = PyUnicode_FromWideChar(s, name_end - s); value = PyUnicode_FromWideChar(name_end + 1, -1); } if (name == NULL || value == NULL) { goto error; } if (PyDict_SetItem(opts, name, value) < 0) { goto error; } Py_DECREF(name); Py_DECREF(value); return 0; error: Py_XDECREF(name); Py_XDECREF(value); return -1; } static PyObject* sys_create_xoptions_dict(const PyConfig *config) { Py_ssize_t nxoption = config->xoptions.length; wchar_t * const * xoptions = config->xoptions.items; PyObject *dict = PyDict_New(); if (dict == NULL) { return NULL; } for (Py_ssize_t i=0; i < nxoption; i++) { const wchar_t *option = xoptions[i]; if (sys_add_xoption(dict, option) < 0) { Py_DECREF(dict); return NULL; } } return dict; } // Update sys attributes for a new PyConfig configuration. // This function also adds attributes that _PySys_InitCore() didn't add. int _PySys_UpdateConfig(PyThreadState *tstate) { PyInterpreterState *interp = tstate->interp; PyObject *sysdict = interp->sysdict; const PyConfig *config = _PyInterpreterState_GetConfig(interp); int res; #define COPY_LIST(KEY, VALUE) \ SET_SYS(KEY, _PyWideStringList_AsList(&(VALUE))); #define SET_SYS_FROM_WSTR(KEY, VALUE) \ SET_SYS(KEY, PyUnicode_FromWideChar(VALUE, -1)); #define COPY_WSTR(SYS_ATTR, WSTR) \ if (WSTR != NULL) { \ SET_SYS_FROM_WSTR(SYS_ATTR, WSTR); \ } if (config->module_search_paths_set) { COPY_LIST("path", config->module_search_paths); } COPY_WSTR("executable", config->executable); COPY_WSTR("_base_executable", config->base_executable); COPY_WSTR("prefix", config->prefix); COPY_WSTR("base_prefix", config->base_prefix); COPY_WSTR("exec_prefix", config->exec_prefix); COPY_WSTR("base_exec_prefix", config->base_exec_prefix); COPY_WSTR("platlibdir", config->platlibdir); if (config->pycache_prefix != NULL) { SET_SYS_FROM_WSTR("pycache_prefix", config->pycache_prefix); } else { PyDict_SetItemString(sysdict, "pycache_prefix", Py_None); } COPY_LIST("argv", config->argv); COPY_LIST("orig_argv", config->orig_argv); COPY_LIST("warnoptions", config->warnoptions); SET_SYS("_xoptions", sys_create_xoptions_dict(config)); const wchar_t *stdlibdir = _Py_GetStdlibDir(); if (stdlibdir != NULL) { SET_SYS_FROM_WSTR("_stdlib_dir", stdlibdir); } else { PyDict_SetItemString(sysdict, "_stdlib_dir", Py_None); } #undef SET_SYS_FROM_WSTR #undef COPY_LIST #undef COPY_WSTR // sys.flags PyObject *flags = _PySys_GetObject(interp, "flags"); // borrowed ref if (flags == NULL) { return -1; } if (set_flags_from_config(interp, flags) < 0) { return -1; } SET_SYS("dont_write_bytecode", PyBool_FromLong(!config->write_bytecode)); if (_PyErr_Occurred(tstate)) { goto err_occurred; } return 0; err_occurred: return -1; } #undef SET_SYS #undef SET_SYS_FROM_STRING /* Set up a preliminary stderr printer until we have enough infrastructure for the io module in place. Use UTF-8/backslashreplace and ignore EAGAIN errors. */ static PyStatus _PySys_SetPreliminaryStderr(PyObject *sysdict) { PyObject *pstderr = PyFile_NewStdPrinter(fileno(stderr)); if (pstderr == NULL) { goto error; } if (PyDict_SetItem(sysdict, &_Py_ID(stderr), pstderr) < 0) { goto error; } if (PyDict_SetItemString(sysdict, "__stderr__", pstderr) < 0) { goto error; } Py_DECREF(pstderr); return _PyStatus_OK(); error: Py_XDECREF(pstderr); return _PyStatus_ERR("can't set preliminary stderr"); } PyObject *_Py_CreateMonitoringObject(void); /* Create sys module without all attributes. _PySys_UpdateConfig() should be called later to add remaining attributes. */ PyStatus _PySys_Create(PyThreadState *tstate, PyObject **sysmod_p) { assert(!_PyErr_Occurred(tstate)); PyInterpreterState *interp = tstate->interp; PyObject *modules = _PyImport_InitModules(interp); if (modules == NULL) { goto error; } PyObject *sysmod = _PyModule_CreateInitialized(&sysmodule, PYTHON_API_VERSION); if (sysmod == NULL) { return _PyStatus_ERR("failed to create a module object"); } PyObject *sysdict = PyModule_GetDict(sysmod); if (sysdict == NULL) { goto error; } interp->sysdict = Py_NewRef(sysdict); interp->sysdict_copy = PyDict_Copy(sysdict); if (interp->sysdict_copy == NULL) { goto error; } if (PyDict_SetItemString(sysdict, "modules", modules) < 0) { goto error; } PyStatus status = _PySys_SetPreliminaryStderr(sysdict); if (_PyStatus_EXCEPTION(status)) { return status; } status = _PySys_InitCore(tstate, sysdict); if (_PyStatus_EXCEPTION(status)) { return status; } if (_PyImport_FixupBuiltin(sysmod, "sys", modules) < 0) { goto error; } PyObject *monitoring = _Py_CreateMonitoringObject(); if (monitoring == NULL) { goto error; } int err = PyDict_SetItemString(sysdict, "monitoring", monitoring); Py_DECREF(monitoring); if (err < 0) { goto error; } assert(!_PyErr_Occurred(tstate)); *sysmod_p = sysmod; return _PyStatus_OK(); error: return _PyStatus_ERR("can't initialize sys module"); } void _PySys_FiniTypes(PyInterpreterState *interp) { _PyStructSequence_FiniBuiltin(interp, &VersionInfoType); _PyStructSequence_FiniBuiltin(interp, &FlagsType); #if defined(MS_WINDOWS) _PyStructSequence_FiniBuiltin(interp, &WindowsVersionType); #endif _PyStructSequence_FiniBuiltin(interp, &Hash_InfoType); _PyStructSequence_FiniBuiltin(interp, &AsyncGenHooksType); #ifdef __EMSCRIPTEN__ if (_Py_IsMainInterpreter(interp)) { Py_CLEAR(EmscriptenInfoType); } #endif } static PyObject * makepathobject(const wchar_t *path, wchar_t delim) { int i, n; const wchar_t *p; PyObject *v, *w; n = 1; p = path; while ((p = wcschr(p, delim)) != NULL) { n++; p++; } v = PyList_New(n); if (v == NULL) return NULL; for (i = 0; ; i++) { p = wcschr(path, delim); if (p == NULL) p = path + wcslen(path); /* End of string */ w = PyUnicode_FromWideChar(path, (Py_ssize_t)(p - path)); if (w == NULL) { Py_DECREF(v); return NULL; } PyList_SET_ITEM(v, i, w); if (*p == '\0') break; path = p+1; } return v; } void PySys_SetPath(const wchar_t *path) { PyObject *v; if ((v = makepathobject(path, DELIM)) == NULL) Py_FatalError("can't create sys.path"); PyInterpreterState *interp = _PyInterpreterState_GET(); if (sys_set_object(interp, &_Py_ID(path), v) != 0) { Py_FatalError("can't assign sys.path"); } Py_DECREF(v); } static PyObject * make_sys_argv(int argc, wchar_t * const * argv) { PyObject *list = PyList_New(argc); if (list == NULL) { return NULL; } for (Py_ssize_t i = 0; i < argc; i++) { PyObject *v = PyUnicode_FromWideChar(argv[i], -1); if (v == NULL) { Py_DECREF(list); return NULL; } PyList_SET_ITEM(list, i, v); } return list; } void PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath) { wchar_t* empty_argv[1] = {L""}; PyThreadState *tstate = _PyThreadState_GET(); if (argc < 1 || argv == NULL) { /* Ensure at least one (empty) argument is seen */ argv = empty_argv; argc = 1; } PyObject *av = make_sys_argv(argc, argv); if (av == NULL) { Py_FatalError("no mem for sys.argv"); } if (sys_set_object_str(tstate->interp, "argv", av) != 0) { Py_DECREF(av); Py_FatalError("can't assign sys.argv"); } Py_DECREF(av); if (updatepath) { /* If argv[0] is not '-c' nor '-m', prepend argv[0] to sys.path. If argv[0] is a symlink, use the real path. */ const PyWideStringList argv_list = {.length = argc, .items = argv}; PyObject *path0 = NULL; if (_PyPathConfig_ComputeSysPath0(&argv_list, &path0)) { if (path0 == NULL) { Py_FatalError("can't compute path0 from argv"); } PyObject *sys_path = _PySys_GetAttr(tstate, &_Py_ID(path)); if (sys_path != NULL) { if (PyList_Insert(sys_path, 0, path0) < 0) { Py_DECREF(path0); Py_FatalError("can't prepend path0 to sys.path"); } } Py_DECREF(path0); } } } void PySys_SetArgv(int argc, wchar_t **argv) { _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS PySys_SetArgvEx(argc, argv, Py_IsolatedFlag == 0); _Py_COMP_DIAG_POP } /* Reimplementation of PyFile_WriteString() no calling indirectly PyErr_CheckSignals(): avoid the call to PyObject_Str(). */ static int sys_pyfile_write_unicode(PyObject *unicode, PyObject *file) { if (file == NULL) return -1; assert(unicode != NULL); PyObject *result = _PyObject_CallMethodOneArg(file, &_Py_ID(write), unicode); if (result == NULL) { return -1; } Py_DECREF(result); return 0; } static int sys_pyfile_write(const char *text, PyObject *file) { PyObject *unicode = NULL; int err; if (file == NULL) return -1; unicode = PyUnicode_FromString(text); if (unicode == NULL) return -1; err = sys_pyfile_write_unicode(unicode, file); Py_DECREF(unicode); return err; } /* APIs to write to sys.stdout or sys.stderr using a printf-like interface. Adapted from code submitted by Just van Rossum. PySys_WriteStdout(format, ...) PySys_WriteStderr(format, ...) The first function writes to sys.stdout; the second to sys.stderr. When there is a problem, they write to the real (C level) stdout or stderr; no exceptions are raised. PyErr_CheckSignals() is not called to avoid the execution of the Python signal handlers: they may raise a new exception whereas sys_write() ignores all exceptions. Both take a printf-style format string as their first argument followed by a variable length argument list determined by the format string. *** WARNING *** The format should limit the total size of the formatted output string to 1000 bytes. In particular, this means that no unrestricted "%s" formats should occur; these should be limited using "%.s where is a decimal number calculated so that plus the maximum size of other formatted text does not exceed 1000 bytes. Also watch out for "%f", which can print hundreds of digits for very large numbers. */ static void sys_write(PyObject *key, FILE *fp, const char *format, va_list va) { PyObject *file; char buffer[1001]; int written; PyThreadState *tstate = _PyThreadState_GET(); PyObject *exc = _PyErr_GetRaisedException(tstate); file = _PySys_GetAttr(tstate, key); written = PyOS_vsnprintf(buffer, sizeof(buffer), format, va); if (sys_pyfile_write(buffer, file) != 0) { _PyErr_Clear(tstate); fputs(buffer, fp); } if (written < 0 || (size_t)written >= sizeof(buffer)) { const char *truncated = "... truncated"; if (sys_pyfile_write(truncated, file) != 0) fputs(truncated, fp); } _PyErr_SetRaisedException(tstate, exc); } void PySys_WriteStdout(const char *format, ...) { va_list va; va_start(va, format); sys_write(&_Py_ID(stdout), stdout, format, va); va_end(va); } void PySys_WriteStderr(const char *format, ...) { va_list va; va_start(va, format); sys_write(&_Py_ID(stderr), stderr, format, va); va_end(va); } static void sys_format(PyObject *key, FILE *fp, const char *format, va_list va) { PyObject *file, *message; const char *utf8; PyThreadState *tstate = _PyThreadState_GET(); PyObject *exc = _PyErr_GetRaisedException(tstate); file = _PySys_GetAttr(tstate, key); message = PyUnicode_FromFormatV(format, va); if (message != NULL) { if (sys_pyfile_write_unicode(message, file) != 0) { _PyErr_Clear(tstate); utf8 = PyUnicode_AsUTF8(message); if (utf8 != NULL) fputs(utf8, fp); } Py_DECREF(message); } _PyErr_SetRaisedException(tstate, exc); } void PySys_FormatStdout(const char *format, ...) { va_list va; va_start(va, format); sys_format(&_Py_ID(stdout), stdout, format, va); va_end(va); } void PySys_FormatStderr(const char *format, ...) { va_list va; va_start(va, format); sys_format(&_Py_ID(stderr), stderr, format, va); va_end(va); } ================================================ FILE: Thread.c ================================================ /* Thread package. This is intended to be usable independently from Python. The implementation for system foobar is in a file thread_foobar.h which is included by this file dependent on config settings. Stuff shared by all thread_*.h files is collected here. */ #include "Python.h" #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() #include "pycore_pythread.h" #ifndef DONT_HAVE_STDIO_H #include #endif #include static void PyThread__init_thread(void); /* Forward */ #define initialized _PyRuntime.threads.initialized void PyThread_init_thread(void) { if (initialized) { return; } initialized = 1; PyThread__init_thread(); } #if defined(HAVE_PTHREAD_STUBS) # define PYTHREAD_NAME "pthread-stubs" # include "thread_pthread_stubs.h" #elif defined(_USE_PTHREADS) /* AKA _PTHREADS */ # if defined(__EMSCRIPTEN__) && !defined(__EMSCRIPTEN_PTHREADS__) # define PYTHREAD_NAME "pthread-stubs" # else # define PYTHREAD_NAME "pthread" # endif # include "thread_pthread.h" #elif defined(NT_THREADS) # define PYTHREAD_NAME "nt" # include "thread_nt.h" #else # error "Require native threads. See https://bugs.python.org/issue31370" #endif /* return the current thread stack size */ size_t PyThread_get_stacksize(void) { return _PyInterpreterState_GET()->threads.stacksize; } /* Only platforms defining a THREAD_SET_STACKSIZE() macro in thread_.h support changing the stack size. Return 0 if stack size is valid, -1 if stack size value is invalid, -2 if setting stack size is not supported. */ int PyThread_set_stacksize(size_t size) { #if defined(THREAD_SET_STACKSIZE) return THREAD_SET_STACKSIZE(size); #else return -2; #endif } /* Thread Specific Storage (TSS) API Cross-platform components of TSS API implementation. */ Py_tss_t * PyThread_tss_alloc(void) { Py_tss_t *new_key = (Py_tss_t *)PyMem_RawMalloc(sizeof(Py_tss_t)); if (new_key == NULL) { return NULL; } new_key->_is_initialized = 0; return new_key; } void PyThread_tss_free(Py_tss_t *key) { if (key != NULL) { PyThread_tss_delete(key); PyMem_RawFree((void *)key); } } int PyThread_tss_is_created(Py_tss_t *key) { assert(key != NULL); return key->_is_initialized; } PyDoc_STRVAR(threadinfo__doc__, "sys.thread_info\n\ \n\ A named tuple holding information about the thread implementation."); static PyStructSequence_Field threadinfo_fields[] = { {"name", "name of the thread implementation"}, {"lock", "name of the lock implementation"}, {"version", "name and version of the thread library"}, {0} }; static PyStructSequence_Desc threadinfo_desc = { "sys.thread_info", /* name */ threadinfo__doc__, /* doc */ threadinfo_fields, /* fields */ 3 }; static PyTypeObject ThreadInfoType; PyObject* PyThread_GetInfo(void) { PyObject *threadinfo, *value; int pos = 0; #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \ && defined(_CS_GNU_LIBPTHREAD_VERSION)) char buffer[255]; int len; #endif PyInterpreterState *interp = _PyInterpreterState_GET(); if (_PyStructSequence_InitBuiltin(interp, &ThreadInfoType, &threadinfo_desc) < 0) { return NULL; } threadinfo = PyStructSequence_New(&ThreadInfoType); if (threadinfo == NULL) return NULL; value = PyUnicode_FromString(PYTHREAD_NAME); if (value == NULL) { Py_DECREF(threadinfo); return NULL; } PyStructSequence_SET_ITEM(threadinfo, pos++, value); #ifdef HAVE_PTHREAD_STUBS value = Py_NewRef(Py_None); #elif defined(_POSIX_THREADS) #ifdef USE_SEMAPHORES value = PyUnicode_FromString("semaphore"); #else value = PyUnicode_FromString("mutex+cond"); #endif if (value == NULL) { Py_DECREF(threadinfo); return NULL; } #else value = Py_NewRef(Py_None); #endif PyStructSequence_SET_ITEM(threadinfo, pos++, value); #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \ && defined(_CS_GNU_LIBPTHREAD_VERSION)) value = NULL; len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer)); if (1 < len && (size_t)len < sizeof(buffer)) { value = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1); if (value == NULL) PyErr_Clear(); } if (value == NULL) #endif { value = Py_NewRef(Py_None); } PyStructSequence_SET_ITEM(threadinfo, pos++, value); return threadinfo; } void _PyThread_FiniType(PyInterpreterState *interp) { _PyStructSequence_FiniBuiltin(interp, &ThreadInfoType); } ================================================ FILE: Thread_NT.h ================================================ #include "pycore_interp.h" // _PyInterpreterState.threads.stacksize /* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */ /* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */ /* Eliminated some memory leaks, gsw@agere.com */ #include #include #ifdef HAVE_PROCESS_H #include #endif /* options */ #ifndef _PY_USE_CV_LOCKS #define _PY_USE_CV_LOCKS 1 /* use locks based on cond vars */ #endif /* Now, define a non-recursive mutex using either condition variables * and critical sections (fast) or using operating system mutexes * (slow) */ #if _PY_USE_CV_LOCKS #include "condvar.h" typedef struct _NRMUTEX { PyMUTEX_T cs; PyCOND_T cv; int locked; } NRMUTEX; typedef NRMUTEX *PNRMUTEX; static PNRMUTEX AllocNonRecursiveMutex(void) { PNRMUTEX m = (PNRMUTEX)PyMem_RawMalloc(sizeof(NRMUTEX)); if (!m) return NULL; if (PyCOND_INIT(&m->cv)) goto fail; if (PyMUTEX_INIT(&m->cs)) { PyCOND_FINI(&m->cv); goto fail; } m->locked = 0; return m; fail: PyMem_RawFree(m); return NULL; } static VOID FreeNonRecursiveMutex(PNRMUTEX mutex) { if (mutex) { PyCOND_FINI(&mutex->cv); PyMUTEX_FINI(&mutex->cs); PyMem_RawFree(mutex); } } static DWORD EnterNonRecursiveMutex(PNRMUTEX mutex, DWORD milliseconds) { DWORD result = WAIT_OBJECT_0; if (PyMUTEX_LOCK(&mutex->cs)) return WAIT_FAILED; if (milliseconds == INFINITE) { while (mutex->locked) { if (PyCOND_WAIT(&mutex->cv, &mutex->cs)) { result = WAIT_FAILED; break; } } } else if (milliseconds != 0) { /* wait at least until the deadline */ _PyTime_t nanoseconds = _PyTime_FromNanoseconds((_PyTime_t)milliseconds * 1000000); _PyTime_t deadline = _PyTime_Add(_PyTime_GetPerfCounter(), nanoseconds); while (mutex->locked) { _PyTime_t microseconds = _PyTime_AsMicroseconds(nanoseconds, _PyTime_ROUND_TIMEOUT); if (PyCOND_TIMEDWAIT(&mutex->cv, &mutex->cs, microseconds) < 0) { result = WAIT_FAILED; break; } nanoseconds = deadline - _PyTime_GetPerfCounter(); if (nanoseconds <= 0) { break; } } } if (!mutex->locked) { mutex->locked = 1; result = WAIT_OBJECT_0; } else if (result == WAIT_OBJECT_0) result = WAIT_TIMEOUT; /* else, it is WAIT_FAILED */ PyMUTEX_UNLOCK(&mutex->cs); /* must ignore result here */ return result; } static BOOL LeaveNonRecursiveMutex(PNRMUTEX mutex) { BOOL result; if (PyMUTEX_LOCK(&mutex->cs)) return FALSE; mutex->locked = 0; /* condvar APIs return 0 on success. We need to return TRUE on success. */ result = !PyCOND_SIGNAL(&mutex->cv); PyMUTEX_UNLOCK(&mutex->cs); return result; } #else /* if ! _PY_USE_CV_LOCKS */ /* NR-locks based on a kernel mutex */ #define PNRMUTEX HANDLE static PNRMUTEX AllocNonRecursiveMutex(void) { return CreateSemaphore(NULL, 1, 1, NULL); } static VOID FreeNonRecursiveMutex(PNRMUTEX mutex) { /* No in-use check */ CloseHandle(mutex); } static DWORD EnterNonRecursiveMutex(PNRMUTEX mutex, DWORD milliseconds) { return WaitForSingleObjectEx(mutex, milliseconds, FALSE); } static BOOL LeaveNonRecursiveMutex(PNRMUTEX mutex) { return ReleaseSemaphore(mutex, 1, NULL); } #endif /* _PY_USE_CV_LOCKS */ unsigned long PyThread_get_thread_ident(void); #ifdef PY_HAVE_THREAD_NATIVE_ID unsigned long PyThread_get_thread_native_id(void); #endif /* * Initialization for the current runtime. */ static void PyThread__init_thread(void) { // Initialization of the C package should not be needed. } /* * Thread support. */ typedef struct { void (*func)(void*); void *arg; } callobj; /* thunker to call adapt between the function type used by the system's thread start function and the internally used one. */ static unsigned __stdcall bootstrap(void *call) { callobj *obj = (callobj*)call; void (*func)(void*) = obj->func; void *arg = obj->arg; HeapFree(GetProcessHeap(), 0, obj); func(arg); return 0; } unsigned long PyThread_start_new_thread(void (*func)(void *), void *arg) { HANDLE hThread; unsigned threadID; callobj *obj; if (!initialized) PyThread_init_thread(); obj = (callobj*)HeapAlloc(GetProcessHeap(), 0, sizeof(*obj)); if (!obj) return PYTHREAD_INVALID_THREAD_ID; obj->func = func; obj->arg = arg; PyThreadState *tstate = _PyThreadState_GET(); size_t stacksize = tstate ? tstate->interp->threads.stacksize : 0; hThread = (HANDLE)_beginthreadex(0, Py_SAFE_DOWNCAST(stacksize, Py_ssize_t, unsigned int), bootstrap, obj, 0, &threadID); if (hThread == 0) { /* I've seen errno == EAGAIN here, which means "there are * too many threads". */ int e = errno; threadID = (unsigned)-1; HeapFree(GetProcessHeap(), 0, obj); } else { CloseHandle(hThread); } return threadID; } /* * Return the thread Id instead of a handle. The Id is said to uniquely identify the * thread in the system */ unsigned long PyThread_get_thread_ident(void) { if (!initialized) PyThread_init_thread(); return GetCurrentThreadId(); } #ifdef PY_HAVE_THREAD_NATIVE_ID /* * Return the native Thread ID (TID) of the calling thread. * The native ID of a thread is valid and guaranteed to be unique system-wide * from the time the thread is created until the thread has been terminated. */ unsigned long PyThread_get_thread_native_id(void) { if (!initialized) { PyThread_init_thread(); } DWORD native_id; native_id = GetCurrentThreadId(); return (unsigned long) native_id; } #endif void _Py_NO_RETURN PyThread_exit_thread(void) { if (!initialized) exit(0); _endthreadex(0); } /* * Lock support. It has to be implemented as semaphores. * I [Dag] tried to implement it with mutex but I could find a way to * tell whether a thread already own the lock or not. */ PyThread_type_lock PyThread_allocate_lock(void) { PNRMUTEX mutex; if (!initialized) PyThread_init_thread(); mutex = AllocNonRecursiveMutex() ; PyThread_type_lock aLock = (PyThread_type_lock) mutex; assert(aLock); return aLock; } void PyThread_free_lock(PyThread_type_lock aLock) { FreeNonRecursiveMutex(aLock) ; } // WaitForSingleObject() accepts timeout in milliseconds in the range // [0; 0xFFFFFFFE] (DWORD type). INFINITE value (0xFFFFFFFF) means no // timeout. 0xFFFFFFFE milliseconds is around 49.7 days. const DWORD TIMEOUT_MS_MAX = 0xFFFFFFFE; /* * Return 1 on success if the lock was acquired * * and 0 if the lock was not acquired. This means a 0 is returned * if the lock has already been acquired by this thread! */ PyLockStatus PyThread_acquire_lock_timed(PyThread_type_lock aLock, PY_TIMEOUT_T microseconds, int intr_flag) { assert(aLock); /* Fow now, intr_flag does nothing on Windows, and lock acquires are * uninterruptible. */ PyLockStatus success; PY_TIMEOUT_T milliseconds; if (microseconds >= 0) { milliseconds = microseconds / 1000; // Round milliseconds away from zero if (microseconds % 1000 > 0) { milliseconds++; } if (milliseconds > (PY_TIMEOUT_T)TIMEOUT_MS_MAX) { // bpo-41710: PyThread_acquire_lock_timed() cannot report timeout // overflow to the caller, so clamp the timeout to // [0, TIMEOUT_MS_MAX] milliseconds. // // _thread.Lock.acquire() and _thread.RLock.acquire() raise an // OverflowError if microseconds is greater than PY_TIMEOUT_MAX. milliseconds = TIMEOUT_MS_MAX; } assert(milliseconds != INFINITE); } else { milliseconds = INFINITE; } if (EnterNonRecursiveMutex((PNRMUTEX)aLock, (DWORD)milliseconds) == WAIT_OBJECT_0) { success = PY_LOCK_ACQUIRED; } else { success = PY_LOCK_FAILURE; } return success; } int PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag) { return PyThread_acquire_lock_timed(aLock, waitflag ? -1 : 0, 0); } void PyThread_release_lock(PyThread_type_lock aLock) { assert(aLock); (void)LeaveNonRecursiveMutex((PNRMUTEX) aLock); } /* minimum/maximum thread stack sizes supported */ #define THREAD_MIN_STACKSIZE 0x8000 /* 32 KiB */ #define THREAD_MAX_STACKSIZE 0x10000000 /* 256 MiB */ /* set the thread stack size. * Return 0 if size is valid, -1 otherwise. */ static int _pythread_nt_set_stacksize(size_t size) { /* set to default */ if (size == 0) { _PyInterpreterState_GET()->threads.stacksize = 0; return 0; } /* valid range? */ if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) { _PyInterpreterState_GET()->threads.stacksize = size; return 0; } return -1; } #define THREAD_SET_STACKSIZE(x) _pythread_nt_set_stacksize(x) /* Thread Local Storage (TLS) API This API is DEPRECATED since Python 3.7. See PEP 539 for details. */ int PyThread_create_key(void) { DWORD result = TlsAlloc(); if (result == TLS_OUT_OF_INDEXES) return -1; return (int)result; } void PyThread_delete_key(int key) { TlsFree(key); } int PyThread_set_key_value(int key, void *value) { BOOL ok = TlsSetValue(key, value); return ok ? 0 : -1; } void * PyThread_get_key_value(int key) { /* because TLS is used in the Py_END_ALLOW_THREAD macro, * it is necessary to preserve the windows error state, because * it is assumed to be preserved across the call to the macro. * Ideally, the macro should be fixed, but it is simpler to * do it here. */ DWORD error = GetLastError(); void *result = TlsGetValue(key); SetLastError(error); return result; } void PyThread_delete_key_value(int key) { /* NULL is used as "key missing", and it is also the default * given by TlsGetValue() if nothing has been set yet. */ TlsSetValue(key, NULL); } /* reinitialization of TLS is not necessary after fork when using * the native TLS functions. And forking isn't supported on Windows either. */ void PyThread_ReInitTLS(void) { } /* Thread Specific Storage (TSS) API Platform-specific components of TSS API implementation. */ int PyThread_tss_create(Py_tss_t *key) { assert(key != NULL); /* If the key has been created, function is silently skipped. */ if (key->_is_initialized) { return 0; } DWORD result = TlsAlloc(); if (result == TLS_OUT_OF_INDEXES) { return -1; } /* In Windows, platform-specific key type is DWORD. */ key->_key = result; key->_is_initialized = 1; return 0; } void PyThread_tss_delete(Py_tss_t *key) { assert(key != NULL); /* If the key has not been created, function is silently skipped. */ if (!key->_is_initialized) { return; } TlsFree(key->_key); key->_key = TLS_OUT_OF_INDEXES; key->_is_initialized = 0; } int PyThread_tss_set(Py_tss_t *key, void *value) { assert(key != NULL); BOOL ok = TlsSetValue(key->_key, value); return ok ? 0 : -1; } void * PyThread_tss_get(Py_tss_t *key) { assert(key != NULL); /* because TSS is used in the Py_END_ALLOW_THREAD macro, * it is necessary to preserve the windows error state, because * it is assumed to be preserved across the call to the macro. * Ideally, the macro should be fixed, but it is simpler to * do it here. */ DWORD error = GetLastError(); void *result = TlsGetValue(key->_key); SetLastError(error); return result; } ================================================ FILE: Thread_Pthread.h ================================================ #include "pycore_interp.h" // _PyInterpreterState.threads.stacksize /* Posix threads interface */ #include #include #if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR) #define destructor xxdestructor #endif #ifndef HAVE_PTHREAD_STUBS # include #endif #if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR) #undef destructor #endif #include #if defined(__linux__) # include /* syscall(SYS_gettid) */ #elif defined(__FreeBSD__) # include /* pthread_getthreadid_np() */ #elif defined(__OpenBSD__) # include /* getthrid() */ #elif defined(_AIX) # include /* thread_self() */ #elif defined(__NetBSD__) # include /* _lwp_self() */ #elif defined(__DragonFly__) # include /* lwp_gettid() */ #endif /* The POSIX spec requires that use of pthread_attr_setstacksize be conditional on _POSIX_THREAD_ATTR_STACKSIZE being defined. */ #ifdef _POSIX_THREAD_ATTR_STACKSIZE #ifndef THREAD_STACK_SIZE #define THREAD_STACK_SIZE 0 /* use default stack size */ #endif /* The default stack size for new threads on BSD is small enough that * we'll get hard crashes instead of 'maximum recursion depth exceeded' * exceptions. * * The default stack size below is the empirically determined minimal stack * sizes where a simple recursive function doesn't cause a hard crash. * * For macOS the value of THREAD_STACK_SIZE is determined in configure.ac * as it also depends on the other configure options like chosen sanitizer * runtimes. */ #if defined(__FreeBSD__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 #undef THREAD_STACK_SIZE #define THREAD_STACK_SIZE 0x400000 #endif #if defined(_AIX) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 #undef THREAD_STACK_SIZE #define THREAD_STACK_SIZE 0x200000 #endif /* bpo-38852: test_threading.test_recursion_limit() checks that 1000 recursive Python calls (default recursion limit) doesn't crash, but raise a regular RecursionError exception. In debug mode, Python function calls allocates more memory on the stack, so use a stack of 8 MiB. */ #if defined(__ANDROID__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 # ifdef Py_DEBUG # undef THREAD_STACK_SIZE # define THREAD_STACK_SIZE 0x800000 # endif #endif #if defined(__VXWORKS__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0 #undef THREAD_STACK_SIZE #define THREAD_STACK_SIZE 0x100000 #endif /* for safety, ensure a viable minimum stacksize */ #define THREAD_STACK_MIN 0x8000 /* 32 KiB */ #else /* !_POSIX_THREAD_ATTR_STACKSIZE */ #ifdef THREAD_STACK_SIZE #error "THREAD_STACK_SIZE defined but _POSIX_THREAD_ATTR_STACKSIZE undefined" #endif #endif /* The POSIX spec says that implementations supporting the sem_* family of functions must indicate this by defining _POSIX_SEMAPHORES. */ #ifdef _POSIX_SEMAPHORES /* On FreeBSD 4.x, _POSIX_SEMAPHORES is defined empty, so we need to add 0 to make it work there as well. */ #if (_POSIX_SEMAPHORES+0) == -1 #define HAVE_BROKEN_POSIX_SEMAPHORES #else #include #include #endif #endif /* Whether or not to use semaphores directly rather than emulating them with * mutexes and condition variables: */ #if (defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES) && \ (defined(HAVE_SEM_TIMEDWAIT) || defined(HAVE_SEM_CLOCKWAIT))) # define USE_SEMAPHORES #else # undef USE_SEMAPHORES #endif /* On platforms that don't use standard POSIX threads pthread_sigmask() * isn't present. DEC threads uses sigprocmask() instead as do most * other UNIX International compliant systems that don't have the full * pthread implementation. */ #if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) # define SET_THREAD_SIGMASK pthread_sigmask #else # define SET_THREAD_SIGMASK sigprocmask #endif /* * pthread_cond support */ #define condattr_monotonic _PyRuntime.threads._condattr_monotonic.ptr static void init_condattr(void) { #ifdef CONDATTR_MONOTONIC # define ca _PyRuntime.threads._condattr_monotonic.val // XXX We need to check the return code? pthread_condattr_init(&ca); // XXX We need to run pthread_condattr_destroy() during runtime fini. if (pthread_condattr_setclock(&ca, CLOCK_MONOTONIC) == 0) { condattr_monotonic = &ca; // Use monotonic clock } # undef ca #endif // CONDATTR_MONOTONIC } int _PyThread_cond_init(PyCOND_T *cond) { return pthread_cond_init(cond, condattr_monotonic); } void _PyThread_cond_after(long long us, struct timespec *abs) { _PyTime_t timeout = _PyTime_FromMicrosecondsClamp(us); _PyTime_t t; #ifdef CONDATTR_MONOTONIC if (condattr_monotonic) { t = _PyTime_GetMonotonicClock(); } else #endif { t = _PyTime_GetSystemClock(); } t = _PyTime_Add(t, timeout); _PyTime_AsTimespec_clamp(t, abs); } /* A pthread mutex isn't sufficient to model the Python lock type * because, according to Draft 5 of the docs (P1003.4a/D5), both of the * following are undefined: * -> a thread tries to lock a mutex it already has locked * -> a thread tries to unlock a mutex locked by a different thread * pthread mutexes are designed for serializing threads over short pieces * of code anyway, so wouldn't be an appropriate implementation of * Python's locks regardless. * * The pthread_lock struct implements a Python lock as a "locked?" bit * and a pair. In general, if the bit can be acquired * instantly, it is, else the pair is used to block the thread until the * bit is cleared. 9 May 1994 tim@ksr.com */ typedef struct { char locked; /* 0=unlocked, 1=locked */ /* a pair to handle an acquire of a locked lock */ pthread_cond_t lock_released; pthread_mutex_t mut; } pthread_lock; #define CHECK_STATUS(name) if (status != 0) { perror(name); error = 1; } #define CHECK_STATUS_PTHREAD(name) if (status != 0) { fprintf(stderr, \ "%s: %s\n", name, strerror(status)); error = 1; } /* * Initialization for the current runtime. */ static void PyThread__init_thread(void) { // The library is only initialized once in the process, // regardless of how many times the Python runtime is initialized. static int lib_initialized = 0; if (!lib_initialized) { lib_initialized = 1; #if defined(_AIX) && defined(__GNUC__) extern void pthread_init(void); pthread_init(); #endif } init_condattr(); } /* * Thread support. */ /* bpo-33015: pythread_callback struct and pythread_wrapper() cast "void func(void *)" to "void* func(void *)": always return NULL. PyThread_start_new_thread() uses "void func(void *)" type, whereas pthread_create() requires a void* return value. */ typedef struct { void (*func) (void *); void *arg; } pythread_callback; static void * pythread_wrapper(void *arg) { /* copy func and func_arg and free the temporary structure */ pythread_callback *callback = arg; void (*func)(void *) = callback->func; void *func_arg = callback->arg; PyMem_RawFree(arg); func(func_arg); return NULL; } unsigned long PyThread_start_new_thread(void (*func)(void *), void *arg) { pthread_t th; int status; #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) pthread_attr_t attrs; #endif #if defined(THREAD_STACK_SIZE) size_t tss; #endif if (!initialized) PyThread_init_thread(); #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) if (pthread_attr_init(&attrs) != 0) return PYTHREAD_INVALID_THREAD_ID; #endif #if defined(THREAD_STACK_SIZE) PyThreadState *tstate = _PyThreadState_GET(); size_t stacksize = tstate ? tstate->interp->threads.stacksize : 0; tss = (stacksize != 0) ? stacksize : THREAD_STACK_SIZE; if (tss != 0) { if (pthread_attr_setstacksize(&attrs, tss) != 0) { pthread_attr_destroy(&attrs); return PYTHREAD_INVALID_THREAD_ID; } } #endif #if defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM); #endif pythread_callback *callback = PyMem_RawMalloc(sizeof(pythread_callback)); if (callback == NULL) { return PYTHREAD_INVALID_THREAD_ID; } callback->func = func; callback->arg = arg; status = pthread_create(&th, #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) &attrs, #else (pthread_attr_t*)NULL, #endif pythread_wrapper, callback); #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) pthread_attr_destroy(&attrs); #endif if (status != 0) { PyMem_RawFree(callback); return PYTHREAD_INVALID_THREAD_ID; } pthread_detach(th); #if SIZEOF_PTHREAD_T <= SIZEOF_LONG return (unsigned long) th; #else return (unsigned long) *(unsigned long *) &th; #endif } /* XXX This implementation is considered (to quote Tim Peters) "inherently hosed" because: - It does not guarantee the promise that a non-zero integer is returned. - The cast to unsigned long is inherently unsafe. - It is not clear that the 'volatile' (for AIX?) are any longer necessary. */ unsigned long PyThread_get_thread_ident(void) { volatile pthread_t threadid; if (!initialized) PyThread_init_thread(); threadid = pthread_self(); return (unsigned long) threadid; } #ifdef PY_HAVE_THREAD_NATIVE_ID unsigned long PyThread_get_thread_native_id(void) { if (!initialized) PyThread_init_thread(); #ifdef __APPLE__ uint64_t native_id; (void) pthread_threadid_np(NULL, &native_id); #elif defined(__linux__) pid_t native_id; native_id = syscall(SYS_gettid); #elif defined(__FreeBSD__) int native_id; native_id = pthread_getthreadid_np(); #elif defined(__OpenBSD__) pid_t native_id; native_id = getthrid(); #elif defined(_AIX) tid_t native_id; native_id = thread_self(); #elif defined(__NetBSD__) lwpid_t native_id; native_id = _lwp_self(); #elif defined(__DragonFly__) lwpid_t native_id; native_id = lwp_gettid(); #endif return (unsigned long) native_id; } #endif void _Py_NO_RETURN PyThread_exit_thread(void) { if (!initialized) exit(0); pthread_exit(0); } #ifdef USE_SEMAPHORES /* * Lock support. */ PyThread_type_lock PyThread_allocate_lock(void) { sem_t *lock; int status, error = 0; if (!initialized) PyThread_init_thread(); lock = (sem_t *)PyMem_RawMalloc(sizeof(sem_t)); if (lock) { status = sem_init(lock,0,1); CHECK_STATUS("sem_init"); if (error) { PyMem_RawFree((void *)lock); lock = NULL; } } return (PyThread_type_lock)lock; } void PyThread_free_lock(PyThread_type_lock lock) { sem_t *thelock = (sem_t *)lock; int status, error = 0; (void) error; /* silence unused-but-set-variable warning */ if (!thelock) return; status = sem_destroy(thelock); CHECK_STATUS("sem_destroy"); PyMem_RawFree((void *)thelock); } /* * As of February 2002, Cygwin thread implementations mistakenly report error * codes in the return value of the sem_ calls (like the pthread_ functions). * Correct implementations return -1 and put the code in errno. This supports * either. */ static int fix_status(int status) { return (status == -1) ? errno : status; } PyLockStatus PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, int intr_flag) { PyLockStatus success; sem_t *thelock = (sem_t *)lock; int status, error = 0; (void) error; /* silence unused-but-set-variable warning */ _PyTime_t timeout; // relative timeout if (microseconds >= 0) { // bpo-41710: PyThread_acquire_lock_timed() cannot report timeout // overflow to the caller, so clamp the timeout to // [_PyTime_MIN, _PyTime_MAX]. // // _PyTime_MAX nanoseconds is around 292.3 years. // // _thread.Lock.acquire() and _thread.RLock.acquire() raise an // OverflowError if microseconds is greater than PY_TIMEOUT_MAX. timeout = _PyTime_FromMicrosecondsClamp(microseconds); } else { timeout = _PyTime_FromNanoseconds(-1); } #ifdef HAVE_SEM_CLOCKWAIT struct timespec abs_timeout; // Local scope for deadline { _PyTime_t deadline = _PyTime_Add(_PyTime_GetMonotonicClock(), timeout); _PyTime_AsTimespec_clamp(deadline, &abs_timeout); } #else _PyTime_t deadline = 0; if (timeout > 0 && !intr_flag) { deadline = _PyDeadline_Init(timeout); } #endif while (1) { if (timeout > 0) { #ifdef HAVE_SEM_CLOCKWAIT status = fix_status(sem_clockwait(thelock, CLOCK_MONOTONIC, &abs_timeout)); #else _PyTime_t abs_time = _PyTime_Add(_PyTime_GetSystemClock(), timeout); struct timespec ts; _PyTime_AsTimespec_clamp(abs_time, &ts); status = fix_status(sem_timedwait(thelock, &ts)); #endif } else if (timeout == 0) { status = fix_status(sem_trywait(thelock)); } else { status = fix_status(sem_wait(thelock)); } /* Retry if interrupted by a signal, unless the caller wants to be notified. */ if (intr_flag || status != EINTR) { break; } // sem_clockwait() uses an absolute timeout, there is no need // to recompute the relative timeout. #ifndef HAVE_SEM_CLOCKWAIT if (timeout > 0) { /* wait interrupted by a signal (EINTR): recompute the timeout */ timeout = _PyDeadline_Get(deadline); if (timeout < 0) { status = ETIMEDOUT; break; } } #endif } /* Don't check the status if we're stopping because of an interrupt. */ if (!(intr_flag && status == EINTR)) { if (timeout > 0) { if (status != ETIMEDOUT) { #ifdef HAVE_SEM_CLOCKWAIT CHECK_STATUS("sem_clockwait"); #else CHECK_STATUS("sem_timedwait"); #endif } } else if (timeout == 0) { if (status != EAGAIN) { CHECK_STATUS("sem_trywait"); } } else { CHECK_STATUS("sem_wait"); } } if (status == 0) { success = PY_LOCK_ACQUIRED; } else if (intr_flag && status == EINTR) { success = PY_LOCK_INTR; } else { success = PY_LOCK_FAILURE; } return success; } void PyThread_release_lock(PyThread_type_lock lock) { sem_t *thelock = (sem_t *)lock; int status, error = 0; (void) error; /* silence unused-but-set-variable warning */ status = sem_post(thelock); CHECK_STATUS("sem_post"); } #else /* USE_SEMAPHORES */ /* * Lock support. */ PyThread_type_lock PyThread_allocate_lock(void) { pthread_lock *lock; int status, error = 0; if (!initialized) PyThread_init_thread(); lock = (pthread_lock *) PyMem_RawCalloc(1, sizeof(pthread_lock)); if (lock) { lock->locked = 0; status = pthread_mutex_init(&lock->mut, NULL); CHECK_STATUS_PTHREAD("pthread_mutex_init"); /* Mark the pthread mutex underlying a Python mutex as pure happens-before. We can't simply mark the Python-level mutex as a mutex because it can be acquired and released in different threads, which will cause errors. */ _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(&lock->mut); status = _PyThread_cond_init(&lock->lock_released); CHECK_STATUS_PTHREAD("pthread_cond_init"); if (error) { PyMem_RawFree((void *)lock); lock = 0; } } return (PyThread_type_lock) lock; } void PyThread_free_lock(PyThread_type_lock lock) { pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; (void) error; /* silence unused-but-set-variable warning */ /* some pthread-like implementations tie the mutex to the cond * and must have the cond destroyed first. */ status = pthread_cond_destroy( &thelock->lock_released ); CHECK_STATUS_PTHREAD("pthread_cond_destroy"); status = pthread_mutex_destroy( &thelock->mut ); CHECK_STATUS_PTHREAD("pthread_mutex_destroy"); PyMem_RawFree((void *)thelock); } PyLockStatus PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, int intr_flag) { PyLockStatus success = PY_LOCK_FAILURE; pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; if (microseconds == 0) { status = pthread_mutex_trylock( &thelock->mut ); if (status != EBUSY) { CHECK_STATUS_PTHREAD("pthread_mutex_trylock[1]"); } } else { status = pthread_mutex_lock( &thelock->mut ); CHECK_STATUS_PTHREAD("pthread_mutex_lock[1]"); } if (status != 0) { goto done; } if (thelock->locked == 0) { success = PY_LOCK_ACQUIRED; goto unlock; } if (microseconds == 0) { goto unlock; } struct timespec abs_timeout; if (microseconds > 0) { _PyThread_cond_after(microseconds, &abs_timeout); } // Continue trying until we get the lock // mut must be locked by me -- part of the condition protocol while (1) { if (microseconds > 0) { status = pthread_cond_timedwait(&thelock->lock_released, &thelock->mut, &abs_timeout); if (status == 1) { break; } if (status == ETIMEDOUT) { break; } CHECK_STATUS_PTHREAD("pthread_cond_timedwait"); } else { status = pthread_cond_wait( &thelock->lock_released, &thelock->mut); CHECK_STATUS_PTHREAD("pthread_cond_wait"); } if (intr_flag && status == 0 && thelock->locked) { // We were woken up, but didn't get the lock. We probably received // a signal. Return PY_LOCK_INTR to allow the caller to handle // it and retry. success = PY_LOCK_INTR; break; } if (status == 0 && !thelock->locked) { success = PY_LOCK_ACQUIRED; break; } // Wait got interrupted by a signal: retry } unlock: if (success == PY_LOCK_ACQUIRED) { thelock->locked = 1; } status = pthread_mutex_unlock( &thelock->mut ); CHECK_STATUS_PTHREAD("pthread_mutex_unlock[1]"); done: if (error) { success = PY_LOCK_FAILURE; } return success; } void PyThread_release_lock(PyThread_type_lock lock) { pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; (void) error; /* silence unused-but-set-variable warning */ status = pthread_mutex_lock( &thelock->mut ); CHECK_STATUS_PTHREAD("pthread_mutex_lock[3]"); thelock->locked = 0; /* wake up someone (anyone, if any) waiting on the lock */ status = pthread_cond_signal( &thelock->lock_released ); CHECK_STATUS_PTHREAD("pthread_cond_signal"); status = pthread_mutex_unlock( &thelock->mut ); CHECK_STATUS_PTHREAD("pthread_mutex_unlock[3]"); } #endif /* USE_SEMAPHORES */ int _PyThread_at_fork_reinit(PyThread_type_lock *lock) { PyThread_type_lock new_lock = PyThread_allocate_lock(); if (new_lock == NULL) { return -1; } /* bpo-6721, bpo-40089: The old lock can be in an inconsistent state. fork() can be called in the middle of an operation on the lock done by another thread. So don't call PyThread_free_lock(*lock). Leak memory on purpose. Don't release the memory either since the address of a mutex is relevant. Putting two mutexes at the same address can lead to problems. */ *lock = new_lock; return 0; } int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) { return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0, /*intr_flag=*/0); } /* set the thread stack size. * Return 0 if size is valid, -1 if size is invalid, * -2 if setting stack size is not supported. */ static int _pythread_pthread_set_stacksize(size_t size) { #if defined(THREAD_STACK_SIZE) pthread_attr_t attrs; size_t tss_min; int rc = 0; #endif /* set to default */ if (size == 0) { _PyInterpreterState_GET()->threads.stacksize = 0; return 0; } #if defined(THREAD_STACK_SIZE) #if defined(PTHREAD_STACK_MIN) tss_min = PTHREAD_STACK_MIN > THREAD_STACK_MIN ? PTHREAD_STACK_MIN : THREAD_STACK_MIN; #else tss_min = THREAD_STACK_MIN; #endif if (size >= tss_min) { /* validate stack size by setting thread attribute */ if (pthread_attr_init(&attrs) == 0) { rc = pthread_attr_setstacksize(&attrs, size); pthread_attr_destroy(&attrs); if (rc == 0) { _PyInterpreterState_GET()->threads.stacksize = size; return 0; } } } return -1; #else return -2; #endif } #define THREAD_SET_STACKSIZE(x) _pythread_pthread_set_stacksize(x) /* Thread Local Storage (TLS) API This API is DEPRECATED since Python 3.7. See PEP 539 for details. */ /* Issue #25658: On platforms where native TLS key is defined in a way that cannot be safely cast to int, PyThread_create_key returns immediately a failure status and other TLS functions all are no-ops. This indicates clearly that the old API is not supported on platforms where it cannot be used reliably, and that no effort will be made to add such support. Note: PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT will be unnecessary after removing this API. */ int PyThread_create_key(void) { #ifdef PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT pthread_key_t key; int fail = pthread_key_create(&key, NULL); if (fail) return -1; if (key > INT_MAX) { /* Issue #22206: handle integer overflow */ pthread_key_delete(key); errno = ENOMEM; return -1; } return (int)key; #else return -1; /* never return valid key value. */ #endif } void PyThread_delete_key(int key) { #ifdef PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT pthread_key_delete(key); #endif } void PyThread_delete_key_value(int key) { #ifdef PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT pthread_setspecific(key, NULL); #endif } int PyThread_set_key_value(int key, void *value) { #ifdef PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT int fail = pthread_setspecific(key, value); return fail ? -1 : 0; #else return -1; #endif } void * PyThread_get_key_value(int key) { #ifdef PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT return pthread_getspecific(key); #else return NULL; #endif } void PyThread_ReInitTLS(void) { } /* Thread Specific Storage (TSS) API Platform-specific components of TSS API implementation. */ int PyThread_tss_create(Py_tss_t *key) { assert(key != NULL); /* If the key has been created, function is silently skipped. */ if (key->_is_initialized) { return 0; } int fail = pthread_key_create(&(key->_key), NULL); if (fail) { return -1; } key->_is_initialized = 1; return 0; } void PyThread_tss_delete(Py_tss_t *key) { assert(key != NULL); /* If the key has not been created, function is silently skipped. */ if (!key->_is_initialized) { return; } pthread_key_delete(key->_key); /* pthread has not provided the defined invalid value for the key. */ key->_is_initialized = 0; } int PyThread_tss_set(Py_tss_t *key, void *value) { assert(key != NULL); int fail = pthread_setspecific(key->_key, value); return fail ? -1 : 0; } void * PyThread_tss_get(Py_tss_t *key) { assert(key != NULL); return pthread_getspecific(key->_key); } ================================================ FILE: Thread_Pthread_Dtubs.h ================================================ #include "cpython/pthread_stubs.h" // mutex int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr) { return 0; } int pthread_mutex_destroy(pthread_mutex_t *mutex) { return 0; } int pthread_mutex_trylock(pthread_mutex_t *mutex) { return 0; } int pthread_mutex_lock(pthread_mutex_t *mutex) { return 0; } int pthread_mutex_unlock(pthread_mutex_t *mutex) { return 0; } // condition int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr) { return 0; } PyAPI_FUNC(int)pthread_cond_destroy(pthread_cond_t *cond) { return 0; } int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex) { return 0; } int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime) { return 0; } int pthread_cond_signal(pthread_cond_t *cond) { return 0; } int pthread_condattr_init(pthread_condattr_t *attr) { return 0; } int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id) { return 0; } // pthread int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void *), void *restrict arg) { return EAGAIN; } int pthread_detach(pthread_t thread) { return 0; } PyAPI_FUNC(pthread_t) pthread_self(void) { return 0; } int pthread_exit(void *retval) { exit(0); } int pthread_attr_init(pthread_attr_t *attr) { return 0; } int pthread_attr_setstacksize( pthread_attr_t *attr, size_t stacksize) { return 0; } int pthread_attr_destroy(pthread_attr_t *attr) { return 0; } typedef struct py_stub_tls_entry py_tls_entry; #define py_tls_entries (_PyRuntime.threads.stubs.tls_entries) int pthread_key_create(pthread_key_t *key, void (*destr_function)(void *)) { if (!key) { return EINVAL; } if (destr_function != NULL) { Py_FatalError("pthread_key_create destructor is not supported"); } for (pthread_key_t idx = 0; idx < PTHREAD_KEYS_MAX; idx++) { if (!py_tls_entries[idx].in_use) { py_tls_entries[idx].in_use = true; *key = idx; return 0; } } return EAGAIN; } int pthread_key_delete(pthread_key_t key) { if (key < 0 || key >= PTHREAD_KEYS_MAX || !py_tls_entries[key].in_use) { return EINVAL; } py_tls_entries[key].in_use = false; py_tls_entries[key].value = NULL; return 0; } void * pthread_getspecific(pthread_key_t key) { if (key < 0 || key >= PTHREAD_KEYS_MAX || !py_tls_entries[key].in_use) { return NULL; } return py_tls_entries[key].value; } int pthread_setspecific(pthread_key_t key, const void *value) { if (key < 0 || key >= PTHREAD_KEYS_MAX || !py_tls_entries[key].in_use) { return EINVAL; } py_tls_entries[key].value = (void *)value; return 0; } // let thread_pthread define the Python API #include "thread_pthread.h" ================================================ FILE: TraceBack.c ================================================ /* Traceback implementation */ #include "Python.h" #include "pycore_ast.h" // asdl_seq_* #include "pycore_call.h" // _PyObject_CallMethodFormat() #include "pycore_compile.h" // _PyAST_Optimize #include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH #include "pycore_frame.h" // _PyFrame_GetCode() #include "pycore_interp.h" // PyInterpreterState.gc #include "pycore_parser.h" // _PyParser_ASTFromString #include "pycore_pyarena.h" // _PyArena_Free() #include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_traceback.h" // EXCEPTION_TB_HEADER #include "../Parser/pegen.h" // _PyPegen_byte_offset_to_character_offset() #include "frameobject.h" // PyFrame_New() #include "structmember.h" // PyMemberDef #include "osdefs.h" // SEP #ifdef HAVE_FCNTL_H # include #endif #define OFF(x) offsetof(PyTracebackObject, x) #define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str)) #define MAX_STRING_LENGTH 500 #define MAX_FRAME_DEPTH 100 #define MAX_NTHREADS 100 /* Function from Parser/tokenizer.c */ extern char* _PyTokenizer_FindEncodingFilename(int, PyObject *); /*[clinic input] class TracebackType "PyTracebackObject *" "&PyTraceback_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=928fa06c10151120]*/ #include "clinic/traceback.c.h" static PyObject * tb_create_raw(PyTracebackObject *next, PyFrameObject *frame, int lasti, int lineno) { PyTracebackObject *tb; if ((next != NULL && !PyTraceBack_Check(next)) || frame == NULL || !PyFrame_Check(frame)) { PyErr_BadInternalCall(); return NULL; } tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type); if (tb != NULL) { tb->tb_next = (PyTracebackObject*)Py_XNewRef(next); tb->tb_frame = (PyFrameObject*)Py_XNewRef(frame); tb->tb_lasti = lasti; tb->tb_lineno = lineno; PyObject_GC_Track(tb); } return (PyObject *)tb; } /*[clinic input] @classmethod TracebackType.__new__ as tb_new tb_next: object tb_frame: object(type='PyFrameObject *', subclass_of='&PyFrame_Type') tb_lasti: int tb_lineno: int Create a new traceback object. [clinic start generated code]*/ static PyObject * tb_new_impl(PyTypeObject *type, PyObject *tb_next, PyFrameObject *tb_frame, int tb_lasti, int tb_lineno) /*[clinic end generated code: output=fa077debd72d861a input=01cbe8ec8783fca7]*/ { if (tb_next == Py_None) { tb_next = NULL; } else if (!PyTraceBack_Check(tb_next)) { return PyErr_Format(PyExc_TypeError, "expected traceback object or None, got '%s'", Py_TYPE(tb_next)->tp_name); } return tb_create_raw((PyTracebackObject *)tb_next, tb_frame, tb_lasti, tb_lineno); } static PyObject * tb_dir(PyTracebackObject *self, PyObject *Py_UNUSED(ignored)) { return Py_BuildValue("[ssss]", "tb_frame", "tb_next", "tb_lasti", "tb_lineno"); } static PyObject * tb_next_get(PyTracebackObject *self, void *Py_UNUSED(_)) { PyObject* ret = (PyObject*)self->tb_next; if (!ret) { ret = Py_None; } return Py_NewRef(ret); } static int tb_next_set(PyTracebackObject *self, PyObject *new_next, void *Py_UNUSED(_)) { if (!new_next) { PyErr_Format(PyExc_TypeError, "can't delete tb_next attribute"); return -1; } /* We accept None or a traceback object, and map None -> NULL (inverse of tb_next_get) */ if (new_next == Py_None) { new_next = NULL; } else if (!PyTraceBack_Check(new_next)) { PyErr_Format(PyExc_TypeError, "expected traceback object, got '%s'", Py_TYPE(new_next)->tp_name); return -1; } /* Check for loops */ PyTracebackObject *cursor = (PyTracebackObject *)new_next; while (cursor) { if (cursor == self) { PyErr_Format(PyExc_ValueError, "traceback loop detected"); return -1; } cursor = cursor->tb_next; } Py_XSETREF(self->tb_next, (PyTracebackObject *)Py_XNewRef(new_next)); return 0; } static PyMethodDef tb_methods[] = { {"__dir__", _PyCFunction_CAST(tb_dir), METH_NOARGS}, {NULL, NULL, 0, NULL}, }; static PyMemberDef tb_memberlist[] = { {"tb_frame", T_OBJECT, OFF(tb_frame), READONLY|PY_AUDIT_READ}, {"tb_lasti", T_INT, OFF(tb_lasti), READONLY}, {"tb_lineno", T_INT, OFF(tb_lineno), READONLY}, {NULL} /* Sentinel */ }; static PyGetSetDef tb_getsetters[] = { {"tb_next", (getter)tb_next_get, (setter)tb_next_set, NULL, NULL}, {NULL} /* Sentinel */ }; static void tb_dealloc(PyTracebackObject *tb) { PyObject_GC_UnTrack(tb); Py_TRASHCAN_BEGIN(tb, tb_dealloc) Py_XDECREF(tb->tb_next); Py_XDECREF(tb->tb_frame); PyObject_GC_Del(tb); Py_TRASHCAN_END } static int tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg) { Py_VISIT(tb->tb_next); Py_VISIT(tb->tb_frame); return 0; } static int tb_clear(PyTracebackObject *tb) { Py_CLEAR(tb->tb_next); Py_CLEAR(tb->tb_frame); return 0; } PyTypeObject PyTraceBack_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "traceback", sizeof(PyTracebackObject), 0, (destructor)tb_dealloc, /*tp_dealloc*/ 0, /*tp_vectorcall_offset*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_as_async*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ tb_new__doc__, /* tp_doc */ (traverseproc)tb_traverse, /* tp_traverse */ (inquiry)tb_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ tb_methods, /* tp_methods */ tb_memberlist, /* tp_members */ tb_getsetters, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ tb_new, /* tp_new */ }; PyObject* _PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame) { assert(tb_next == NULL || PyTraceBack_Check(tb_next)); assert(frame != NULL); int addr = _PyInterpreterFrame_LASTI(frame->f_frame) * sizeof(_Py_CODEUNIT); return tb_create_raw((PyTracebackObject *)tb_next, frame, addr, PyFrame_GetLineNumber(frame)); } int PyTraceBack_Here(PyFrameObject *frame) { PyObject *exc = PyErr_GetRaisedException(); assert(PyExceptionInstance_Check(exc)); PyObject *tb = PyException_GetTraceback(exc); PyObject *newtb = _PyTraceBack_FromFrame(tb, frame); Py_XDECREF(tb); if (newtb == NULL) { _PyErr_ChainExceptions1(exc); return -1; } PyException_SetTraceback(exc, newtb); Py_XDECREF(newtb); PyErr_SetRaisedException(exc); return 0; } /* Insert a frame into the traceback for (funcname, filename, lineno). */ void _PyTraceback_Add(const char *funcname, const char *filename, int lineno) { PyObject *globals; PyCodeObject *code; PyFrameObject *frame; PyThreadState *tstate = _PyThreadState_GET(); /* Save and clear the current exception. Python functions must not be called with an exception set. Calling Python functions happens when the codec of the filesystem encoding is implemented in pure Python. */ PyObject *exc = _PyErr_GetRaisedException(tstate); globals = PyDict_New(); if (!globals) goto error; code = PyCode_NewEmpty(filename, funcname, lineno); if (!code) { Py_DECREF(globals); goto error; } frame = PyFrame_New(tstate, code, globals, NULL); Py_DECREF(globals); Py_DECREF(code); if (!frame) goto error; frame->f_lineno = lineno; _PyErr_SetRaisedException(tstate, exc); PyTraceBack_Here(frame); Py_DECREF(frame); return; error: _PyErr_ChainExceptions1(exc); } static PyObject * _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject *io) { Py_ssize_t i; PyObject *binary; PyObject *v; Py_ssize_t npath; size_t taillen; PyObject *syspath; PyObject *path; const char* tail; PyObject *filebytes; const char* filepath; Py_ssize_t len; PyObject* result; PyObject *open = NULL; filebytes = PyUnicode_EncodeFSDefault(filename); if (filebytes == NULL) { PyErr_Clear(); return NULL; } filepath = PyBytes_AS_STRING(filebytes); /* Search tail of filename in sys.path before giving up */ tail = strrchr(filepath, SEP); if (tail == NULL) tail = filepath; else tail++; taillen = strlen(tail); PyThreadState *tstate = _PyThreadState_GET(); syspath = _PySys_GetAttr(tstate, &_Py_ID(path)); if (syspath == NULL || !PyList_Check(syspath)) goto error; npath = PyList_Size(syspath); open = PyObject_GetAttr(io, &_Py_ID(open)); for (i = 0; i < npath; i++) { v = PyList_GetItem(syspath, i); if (v == NULL) { PyErr_Clear(); break; } if (!PyUnicode_Check(v)) continue; path = PyUnicode_EncodeFSDefault(v); if (path == NULL) { PyErr_Clear(); continue; } len = PyBytes_GET_SIZE(path); if (len + 1 + (Py_ssize_t)taillen >= (Py_ssize_t)namelen - 1) { Py_DECREF(path); continue; /* Too long */ } strcpy(namebuf, PyBytes_AS_STRING(path)); Py_DECREF(path); if (strlen(namebuf) != (size_t)len) continue; /* v contains '\0' */ if (len > 0 && namebuf[len-1] != SEP) namebuf[len++] = SEP; strcpy(namebuf+len, tail); binary = _PyObject_CallMethodFormat(tstate, open, "ss", namebuf, "rb"); if (binary != NULL) { result = binary; goto finally; } PyErr_Clear(); } goto error; error: result = NULL; finally: Py_XDECREF(open); Py_DECREF(filebytes); return result; } /* Writes indent spaces. Returns 0 on success and non-zero on failure. */ int _Py_WriteIndent(int indent, PyObject *f) { char buf[11] = " "; assert(strlen(buf) == 10); while (indent > 0) { if (indent < 10) { buf[indent] = '\0'; } if (PyFile_WriteString(buf, f) < 0) { return -1; } indent -= 10; } return 0; } /* Writes indent spaces, followed by the margin if it is not `\0`. Returns 0 on success and non-zero on failure. */ int _Py_WriteIndentedMargin(int indent, const char *margin, PyObject *f) { if (_Py_WriteIndent(indent, f) < 0) { return -1; } if (margin) { if (PyFile_WriteString(margin, f) < 0) { return -1; } } return 0; } static int display_source_line_with_margin(PyObject *f, PyObject *filename, int lineno, int indent, int margin_indent, const char *margin, int *truncation, PyObject **line) { int fd; int i; char *found_encoding; const char *encoding; PyObject *io; PyObject *binary; PyObject *fob = NULL; PyObject *lineobj = NULL; PyObject *res; char buf[MAXPATHLEN+1]; int kind; const void *data; /* open the file */ if (filename == NULL) return 0; /* Do not attempt to open things like or */ assert(PyUnicode_Check(filename)); if (PyUnicode_READ_CHAR(filename, 0) == '<') { Py_ssize_t len = PyUnicode_GET_LENGTH(filename); if (len > 0 && PyUnicode_READ_CHAR(filename, len - 1) == '>') { return 0; } } io = PyImport_ImportModule("io"); if (io == NULL) { return -1; } binary = _PyObject_CallMethod(io, &_Py_ID(open), "Os", filename, "rb"); if (binary == NULL) { PyErr_Clear(); binary = _Py_FindSourceFile(filename, buf, sizeof(buf), io); if (binary == NULL) { Py_DECREF(io); return -1; } } /* use the right encoding to decode the file as unicode */ fd = PyObject_AsFileDescriptor(binary); if (fd < 0) { Py_DECREF(io); Py_DECREF(binary); return 0; } found_encoding = _PyTokenizer_FindEncodingFilename(fd, filename); if (found_encoding == NULL) PyErr_Clear(); encoding = (found_encoding != NULL) ? found_encoding : "utf-8"; /* Reset position */ if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { Py_DECREF(io); Py_DECREF(binary); PyMem_Free(found_encoding); return 0; } fob = _PyObject_CallMethod(io, &_Py_ID(TextIOWrapper), "Os", binary, encoding); Py_DECREF(io); PyMem_Free(found_encoding); if (fob == NULL) { PyErr_Clear(); res = PyObject_CallMethodNoArgs(binary, &_Py_ID(close)); Py_DECREF(binary); if (res) Py_DECREF(res); else PyErr_Clear(); return 0; } Py_DECREF(binary); /* get the line number lineno */ for (i = 0; i < lineno; i++) { Py_XDECREF(lineobj); lineobj = PyFile_GetLine(fob, -1); if (!lineobj) { PyErr_Clear(); break; } } res = PyObject_CallMethodNoArgs(fob, &_Py_ID(close)); if (res) { Py_DECREF(res); } else { PyErr_Clear(); } Py_DECREF(fob); if (!lineobj || !PyUnicode_Check(lineobj)) { Py_XDECREF(lineobj); return -1; } if (line) { *line = Py_NewRef(lineobj); } /* remove the indentation of the line */ kind = PyUnicode_KIND(lineobj); data = PyUnicode_DATA(lineobj); for (i=0; i < PyUnicode_GET_LENGTH(lineobj); i++) { Py_UCS4 ch = PyUnicode_READ(kind, data, i); if (ch != ' ' && ch != '\t' && ch != '\014') break; } if (i) { PyObject *truncated; truncated = PyUnicode_Substring(lineobj, i, PyUnicode_GET_LENGTH(lineobj)); if (truncated) { Py_SETREF(lineobj, truncated); } else { PyErr_Clear(); } } if (truncation != NULL) { *truncation = i - indent; } if (_Py_WriteIndentedMargin(margin_indent, margin, f) < 0) { goto error; } /* Write some spaces before the line */ if (_Py_WriteIndent(indent, f) < 0) { goto error; } /* finally display the line */ if (PyFile_WriteObject(lineobj, f, Py_PRINT_RAW) < 0) { goto error; } if (PyFile_WriteString("\n", f) < 0) { goto error; } Py_DECREF(lineobj); return 0; error: Py_DECREF(lineobj); return -1; } int _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent, int *truncation, PyObject **line) { return display_source_line_with_margin(f, filename, lineno, indent, 0, NULL, truncation, line); } /* AST based Traceback Specialization * * When displaying a new traceback line, for certain syntactical constructs * (e.g a subscript, an arithmetic operation) we try to create a representation * that separates the primary source of error from the rest. * * Example specialization of BinOp nodes: * Traceback (most recent call last): * File "/home/isidentical/cpython/cpython/t.py", line 10, in * add_values(1, 2, 'x', 3, 4) * File "/home/isidentical/cpython/cpython/t.py", line 2, in add_values * return a + b + c + d + e * ~~~~~~^~~ * TypeError: 'NoneType' object is not subscriptable */ #define IS_WHITESPACE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\f')) static int extract_anchors_from_expr(const char *segment_str, expr_ty expr, Py_ssize_t *left_anchor, Py_ssize_t *right_anchor, char** primary_error_char, char** secondary_error_char) { switch (expr->kind) { case BinOp_kind: { expr_ty left = expr->v.BinOp.left; expr_ty right = expr->v.BinOp.right; for (int i = left->end_col_offset; i < right->col_offset; i++) { if (IS_WHITESPACE(segment_str[i])) { continue; } *left_anchor = i; *right_anchor = i + 1; // Check whether if this a two-character operator (e.g //) if (i + 1 < right->col_offset && !IS_WHITESPACE(segment_str[i + 1])) { ++*right_anchor; } // Set the error characters *primary_error_char = "~"; *secondary_error_char = "^"; break; } return 1; } case Subscript_kind: { *left_anchor = expr->v.Subscript.value->end_col_offset; *right_anchor = expr->v.Subscript.slice->end_col_offset + 1; // Set the error characters *primary_error_char = "~"; *secondary_error_char = "^"; return 1; } default: return 0; } } static int extract_anchors_from_stmt(const char *segment_str, stmt_ty statement, Py_ssize_t *left_anchor, Py_ssize_t *right_anchor, char** primary_error_char, char** secondary_error_char) { switch (statement->kind) { case Expr_kind: { return extract_anchors_from_expr(segment_str, statement->v.Expr.value, left_anchor, right_anchor, primary_error_char, secondary_error_char); } default: return 0; } } static int extract_anchors_from_line(PyObject *filename, PyObject *line, Py_ssize_t start_offset, Py_ssize_t end_offset, Py_ssize_t *left_anchor, Py_ssize_t *right_anchor, char** primary_error_char, char** secondary_error_char) { int res = -1; PyArena *arena = NULL; PyObject *segment = PyUnicode_Substring(line, start_offset, end_offset); if (!segment) { goto done; } const char *segment_str = PyUnicode_AsUTF8(segment); if (!segment_str) { goto done; } arena = _PyArena_New(); if (!arena) { goto done; } PyCompilerFlags flags = _PyCompilerFlags_INIT; _PyASTOptimizeState state; state.optimize = _Py_GetConfig()->optimization_level; state.ff_features = 0; mod_ty module = _PyParser_ASTFromString(segment_str, filename, Py_file_input, &flags, arena); if (!module) { goto done; } if (!_PyAST_Optimize(module, arena, &state)) { goto done; } assert(module->kind == Module_kind); if (asdl_seq_LEN(module->v.Module.body) == 1) { stmt_ty statement = asdl_seq_GET(module->v.Module.body, 0); res = extract_anchors_from_stmt(segment_str, statement, left_anchor, right_anchor, primary_error_char, secondary_error_char); } else { res = 0; } done: if (res > 0) { // Normalize the AST offsets to byte offsets and adjust them with the // start of the actual line (instead of the source code segment). assert(segment != NULL); assert(*left_anchor >= 0); assert(*right_anchor >= 0); *left_anchor = _PyPegen_byte_offset_to_character_offset(segment, *left_anchor) + start_offset; *right_anchor = _PyPegen_byte_offset_to_character_offset(segment, *right_anchor) + start_offset; } Py_XDECREF(segment); if (arena) { _PyArena_Free(arena); } return res; } #define _TRACEBACK_SOURCE_LINE_INDENT 4 static inline int ignore_source_errors(void) { if (PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) { return -1; } PyErr_Clear(); } return 0; } static inline int print_error_location_carets(PyObject *f, int offset, Py_ssize_t start_offset, Py_ssize_t end_offset, Py_ssize_t right_start_offset, Py_ssize_t left_end_offset, const char *primary, const char *secondary) { int special_chars = (left_end_offset != -1 || right_start_offset != -1); const char *str; while (++offset <= end_offset) { if (offset <= start_offset) { str = " "; } else if (special_chars && left_end_offset < offset && offset <= right_start_offset) { str = secondary; } else { str = primary; } if (PyFile_WriteString(str, f) < 0) { return -1; } } if (PyFile_WriteString("\n", f) < 0) { return -1; } return 0; } static int tb_displayline(PyTracebackObject* tb, PyObject *f, PyObject *filename, int lineno, PyFrameObject *frame, PyObject *name, int margin_indent, const char *margin) { if (filename == NULL || name == NULL) { return -1; } if (_Py_WriteIndentedMargin(margin_indent, margin, f) < 0) { return -1; } PyObject *line = PyUnicode_FromFormat(" File \"%U\", line %d, in %U\n", filename, lineno, name); if (line == NULL) { return -1; } int res = PyFile_WriteObject(line, f, Py_PRINT_RAW); Py_DECREF(line); if (res < 0) { return -1; } int err = 0; int truncation = _TRACEBACK_SOURCE_LINE_INDENT; PyObject* source_line = NULL; int rc = display_source_line_with_margin( f, filename, lineno, _TRACEBACK_SOURCE_LINE_INDENT, margin_indent, margin, &truncation, &source_line); if (rc != 0 || !source_line) { /* ignore errors since we can't report them, can we? */ err = ignore_source_errors(); goto done; } int code_offset = tb->tb_lasti; PyCodeObject* code = frame->f_frame->f_code; const Py_ssize_t source_line_len = PyUnicode_GET_LENGTH(source_line); int start_line; int end_line; int start_col_byte_offset; int end_col_byte_offset; if (!PyCode_Addr2Location(code, code_offset, &start_line, &start_col_byte_offset, &end_line, &end_col_byte_offset)) { goto done; } if (start_line < 0 || end_line < 0 || start_col_byte_offset < 0 || end_col_byte_offset < 0) { goto done; } // When displaying errors, we will use the following generic structure: // // ERROR LINE ERROR LINE ERROR LINE ERROR LINE ERROR LINE ERROR LINE ERROR LINE // ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~ // | |-> left_end_offset | |-> end_offset // |-> start_offset |-> right_start_offset // // In general we will only have (start_offset, end_offset) but we can gather more information // by analyzing the AST of the text between *start_offset* and *end_offset*. If this succeeds // we could get *left_end_offset* and *right_start_offset* and some selection of characters for // the different ranges (primary_error_char and secondary_error_char). If we cannot obtain the // AST information or we cannot identify special ranges within it, then left_end_offset and // right_end_offset will be set to -1. // // To keep the column indicators pertinent, they are not shown when the primary character // spans the whole line. // Convert the utf-8 byte offset to the actual character offset so we print the right number of carets. assert(source_line); Py_ssize_t start_offset = _PyPegen_byte_offset_to_character_offset(source_line, start_col_byte_offset); if (start_offset < 0) { err = ignore_source_errors() < 0; goto done; } Py_ssize_t end_offset = _PyPegen_byte_offset_to_character_offset(source_line, end_col_byte_offset); if (end_offset < 0) { err = ignore_source_errors() < 0; goto done; } Py_ssize_t left_end_offset = -1; Py_ssize_t right_start_offset = -1; char *primary_error_char = "^"; char *secondary_error_char = primary_error_char; if (start_line == end_line) { int res = extract_anchors_from_line(filename, source_line, start_offset, end_offset, &left_end_offset, &right_start_offset, &primary_error_char, &secondary_error_char); if (res < 0 && ignore_source_errors() < 0) { goto done; } } else { // If this is a multi-line expression, then we will highlight until // the last non-whitespace character. const char *source_line_str = PyUnicode_AsUTF8(source_line); if (!source_line_str) { goto done; } Py_ssize_t i = source_line_len; while (--i >= 0) { if (!IS_WHITESPACE(source_line_str[i])) { break; } } end_offset = i + 1; } // Elide indicators if primary char spans the frame line Py_ssize_t stripped_line_len = source_line_len - truncation - _TRACEBACK_SOURCE_LINE_INDENT; bool has_secondary_ranges = (left_end_offset != -1 || right_start_offset != -1); if (end_offset - start_offset == stripped_line_len && !has_secondary_ranges) { goto done; } if (_Py_WriteIndentedMargin(margin_indent, margin, f) < 0) { err = -1; goto done; } if (print_error_location_carets(f, truncation, start_offset, end_offset, right_start_offset, left_end_offset, primary_error_char, secondary_error_char) < 0) { err = -1; goto done; } done: Py_XDECREF(source_line); return err; } static const int TB_RECURSIVE_CUTOFF = 3; // Also hardcoded in traceback.py. static int tb_print_line_repeated(PyObject *f, long cnt) { cnt -= TB_RECURSIVE_CUTOFF; PyObject *line = PyUnicode_FromFormat( (cnt > 1) ? " [Previous line repeated %ld more times]\n" : " [Previous line repeated %ld more time]\n", cnt); if (line == NULL) { return -1; } int err = PyFile_WriteObject(line, f, Py_PRINT_RAW); Py_DECREF(line); return err; } static int tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit, int indent, const char *margin) { PyCodeObject *code = NULL; Py_ssize_t depth = 0; PyObject *last_file = NULL; int last_line = -1; PyObject *last_name = NULL; long cnt = 0; PyTracebackObject *tb1 = tb; while (tb1 != NULL) { depth++; tb1 = tb1->tb_next; } while (tb != NULL && depth > limit) { depth--; tb = tb->tb_next; } while (tb != NULL) { code = PyFrame_GetCode(tb->tb_frame); if (last_file == NULL || code->co_filename != last_file || last_line == -1 || tb->tb_lineno != last_line || last_name == NULL || code->co_name != last_name) { if (cnt > TB_RECURSIVE_CUTOFF) { if (tb_print_line_repeated(f, cnt) < 0) { goto error; } } last_file = code->co_filename; last_line = tb->tb_lineno; last_name = code->co_name; cnt = 0; } cnt++; if (cnt <= TB_RECURSIVE_CUTOFF) { if (tb_displayline(tb, f, code->co_filename, tb->tb_lineno, tb->tb_frame, code->co_name, indent, margin) < 0) { goto error; } if (PyErr_CheckSignals() < 0) { goto error; } } Py_CLEAR(code); tb = tb->tb_next; } if (cnt > TB_RECURSIVE_CUTOFF) { if (tb_print_line_repeated(f, cnt) < 0) { goto error; } } return 0; error: Py_XDECREF(code); return -1; } #define PyTraceBack_LIMIT 1000 int _PyTraceBack_Print_Indented(PyObject *v, int indent, const char *margin, const char *header_margin, const char *header, PyObject *f) { PyObject *limitv; long limit = PyTraceBack_LIMIT; if (v == NULL) { return 0; } if (!PyTraceBack_Check(v)) { PyErr_BadInternalCall(); return -1; } limitv = PySys_GetObject("tracebacklimit"); if (limitv && PyLong_Check(limitv)) { int overflow; limit = PyLong_AsLongAndOverflow(limitv, &overflow); if (overflow > 0) { limit = LONG_MAX; } else if (limit <= 0) { return 0; } } if (_Py_WriteIndentedMargin(indent, header_margin, f) < 0) { return -1; } if (PyFile_WriteString(header, f) < 0) { return -1; } if (tb_printinternal((PyTracebackObject *)v, f, limit, indent, margin) < 0) { return -1; } return 0; } int PyTraceBack_Print(PyObject *v, PyObject *f) { int indent = 0; const char *margin = NULL; const char *header_margin = NULL; const char *header = EXCEPTION_TB_HEADER; return _PyTraceBack_Print_Indented(v, indent, margin, header_margin, header, f); } /* Format an integer in range [0; 0xffffffff] to decimal and write it into the file fd. This function is signal safe. */ void _Py_DumpDecimal(int fd, size_t value) { /* maximum number of characters required for output of %lld or %p. We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits, plus 1 for the null byte. 53/22 is an upper bound for log10(256). */ char buffer[1 + (sizeof(size_t)*53-1) / 22 + 1]; char *ptr, *end; end = &buffer[Py_ARRAY_LENGTH(buffer) - 1]; ptr = end; *ptr = '\0'; do { --ptr; assert(ptr >= buffer); *ptr = '0' + (value % 10); value /= 10; } while (value); _Py_write_noraise(fd, ptr, end - ptr); } /* Format an integer as hexadecimal with width digits into fd file descriptor. The function is signal safe. */ void _Py_DumpHexadecimal(int fd, uintptr_t value, Py_ssize_t width) { char buffer[sizeof(uintptr_t) * 2 + 1], *ptr, *end; const Py_ssize_t size = Py_ARRAY_LENGTH(buffer) - 1; if (width > size) width = size; /* it's ok if width is negative */ end = &buffer[size]; ptr = end; *ptr = '\0'; do { --ptr; assert(ptr >= buffer); *ptr = Py_hexdigits[value & 15]; value >>= 4; } while ((end - ptr) < width || value); _Py_write_noraise(fd, ptr, end - ptr); } void _Py_DumpASCII(int fd, PyObject *text) { PyASCIIObject *ascii = _PyASCIIObject_CAST(text); Py_ssize_t i, size; int truncated; int kind; void *data = NULL; Py_UCS4 ch; if (!PyUnicode_Check(text)) return; size = ascii->length; kind = ascii->state.kind; if (ascii->state.compact) { if (ascii->state.ascii) data = ascii + 1; else data = _PyCompactUnicodeObject_CAST(text) + 1; } else { data = _PyUnicodeObject_CAST(text)->data.any; if (data == NULL) return; } if (MAX_STRING_LENGTH < size) { size = MAX_STRING_LENGTH; truncated = 1; } else { truncated = 0; } // Is an ASCII string? if (ascii->state.ascii) { assert(kind == PyUnicode_1BYTE_KIND); char *str = data; int need_escape = 0; for (i=0; i < size; i++) { ch = str[i]; if (!(' ' <= ch && ch <= 126)) { need_escape = 1; break; } } if (!need_escape) { // The string can be written with a single write() syscall _Py_write_noraise(fd, str, size); goto done; } } for (i=0; i < size; i++) { ch = PyUnicode_READ(kind, data, i); if (' ' <= ch && ch <= 126) { /* printable ASCII character */ char c = (char)ch; _Py_write_noraise(fd, &c, 1); } else if (ch <= 0xff) { PUTS(fd, "\\x"); _Py_DumpHexadecimal(fd, ch, 2); } else if (ch <= 0xffff) { PUTS(fd, "\\u"); _Py_DumpHexadecimal(fd, ch, 4); } else { PUTS(fd, "\\U"); _Py_DumpHexadecimal(fd, ch, 8); } } done: if (truncated) { PUTS(fd, "..."); } } /* Write a frame into the file fd: "File "xxx", line xxx in xxx". This function is signal safe. */ static void dump_frame(int fd, _PyInterpreterFrame *frame) { PyCodeObject *code = frame->f_code; PUTS(fd, " File "); if (code->co_filename != NULL && PyUnicode_Check(code->co_filename)) { PUTS(fd, "\""); _Py_DumpASCII(fd, code->co_filename); PUTS(fd, "\""); } else { PUTS(fd, "???"); } int lineno = PyUnstable_InterpreterFrame_GetLine(frame); PUTS(fd, ", line "); if (lineno >= 0) { _Py_DumpDecimal(fd, (size_t)lineno); } else { PUTS(fd, "???"); } PUTS(fd, " in "); if (code->co_name != NULL && PyUnicode_Check(code->co_name)) { _Py_DumpASCII(fd, code->co_name); } else { PUTS(fd, "???"); } PUTS(fd, "\n"); } static void dump_traceback(int fd, PyThreadState *tstate, int write_header) { _PyInterpreterFrame *frame; unsigned int depth; if (write_header) { PUTS(fd, "Stack (most recent call first):\n"); } frame = tstate->cframe->current_frame; if (frame == NULL) { PUTS(fd, " \n"); return; } depth = 0; while (1) { if (MAX_FRAME_DEPTH <= depth) { PUTS(fd, " ...\n"); break; } dump_frame(fd, frame); frame = frame->previous; if (frame == NULL) { break; } if (frame->owner == FRAME_OWNED_BY_CSTACK) { /* Trampoline frame */ frame = frame->previous; } if (frame == NULL) { break; } /* Can't have more than one shim frame in a row */ assert(frame->owner != FRAME_OWNED_BY_CSTACK); depth++; } } /* Dump the traceback of a Python thread into fd. Use write() to write the traceback and retry if write() is interrupted by a signal (failed with EINTR), but don't call the Python signal handler. The caller is responsible to call PyErr_CheckSignals() to call Python signal handlers if signals were received. */ void _Py_DumpTraceback(int fd, PyThreadState *tstate) { dump_traceback(fd, tstate, 1); } /* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if is_current is true, "Thread 0xHHHH:\n" otherwise. This function is signal safe. */ static void write_thread_id(int fd, PyThreadState *tstate, int is_current) { if (is_current) PUTS(fd, "Current thread 0x"); else PUTS(fd, "Thread 0x"); _Py_DumpHexadecimal(fd, tstate->thread_id, sizeof(unsigned long) * 2); PUTS(fd, " (most recent call first):\n"); } /* Dump the traceback of all Python threads into fd. Use write() to write the traceback and retry if write() is interrupted by a signal (failed with EINTR), but don't call the Python signal handler. The caller is responsible to call PyErr_CheckSignals() to call Python signal handlers if signals were received. */ const char* _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, PyThreadState *current_tstate) { PyThreadState *tstate; unsigned int nthreads; if (current_tstate == NULL) { /* _Py_DumpTracebackThreads() is called from signal handlers by faulthandler. SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals and are thus delivered to the thread that caused the fault. Get the Python thread state of the current thread. PyThreadState_Get() doesn't give the state of the thread that caused the fault if the thread released the GIL, and so _PyThreadState_GET() cannot be used. Read the thread specific storage (TSS) instead: call PyGILState_GetThisThreadState(). */ current_tstate = PyGILState_GetThisThreadState(); } if (interp == NULL) { if (current_tstate == NULL) { interp = _PyGILState_GetInterpreterStateUnsafe(); if (interp == NULL) { /* We need the interpreter state to get Python threads */ return "unable to get the interpreter state"; } } else { interp = current_tstate->interp; } } assert(interp != NULL); /* Get the current interpreter from the current thread */ tstate = PyInterpreterState_ThreadHead(interp); if (tstate == NULL) return "unable to get the thread head state"; /* Dump the traceback of each thread */ tstate = PyInterpreterState_ThreadHead(interp); nthreads = 0; _Py_BEGIN_SUPPRESS_IPH do { if (nthreads != 0) PUTS(fd, "\n"); if (nthreads >= MAX_NTHREADS) { PUTS(fd, "...\n"); break; } write_thread_id(fd, tstate, tstate == current_tstate); if (tstate == current_tstate && tstate->interp->gc.collecting) { PUTS(fd, " Garbage-collecting\n"); } dump_traceback(fd, tstate, 0); tstate = PyThreadState_Next(tstate); nthreads++; } while (tstate != NULL); _Py_END_SUPPRESS_IPH return NULL; } ================================================ FILE: TraceMalloc.c ================================================ #include "Python.h" #include "pycore_fileutils.h" // _Py_write_noraise() #include "pycore_gc.h" // PyGC_Head #include "pycore_hashtable.h" // _Py_hashtable_t #include "pycore_object.h" // _PyType_PreHeaderSize #include "pycore_pymem.h" // _Py_tracemalloc_config #include "pycore_runtime.h" // _Py_ID() #include "pycore_traceback.h" #include #include "frameobject.h" // _PyInterpreterFrame_GetLine #include // malloc() #define tracemalloc_config _PyRuntime.tracemalloc.config _Py_DECLARE_STR(anon_unknown, ""); /* Forward declaration */ static void* raw_malloc(size_t size); static void raw_free(void *ptr); #ifdef Py_DEBUG # define TRACE_DEBUG #endif #define TO_PTR(key) ((const void *)(uintptr_t)(key)) #define FROM_PTR(key) ((uintptr_t)(key)) #define allocators _PyRuntime.tracemalloc.allocators #if defined(TRACE_RAW_MALLOC) /* This lock is needed because tracemalloc_free() is called without the GIL held from PyMem_RawFree(). It cannot acquire the lock because it would introduce a deadlock in _PyThreadState_DeleteCurrent(). */ # define tables_lock _PyRuntime.tracemalloc.tables_lock # define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1) # define TABLES_UNLOCK() PyThread_release_lock(tables_lock) #else /* variables are protected by the GIL */ # define TABLES_LOCK() # define TABLES_UNLOCK() #endif #define DEFAULT_DOMAIN 0 typedef struct tracemalloc_frame frame_t; typedef struct tracemalloc_traceback traceback_t; #define TRACEBACK_SIZE(NFRAME) \ (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1)) /* The maximum number of frames is either: - The maximum number of frames we can store in `traceback_t.nframe` - The maximum memory size_t we can allocate */ static const unsigned long MAX_NFRAME = Py_MIN(UINT16_MAX, ((SIZE_MAX - sizeof(traceback_t)) / sizeof(frame_t) + 1)); #define tracemalloc_empty_traceback _PyRuntime.tracemalloc.empty_traceback /* Trace of a memory block */ typedef struct { /* Size of the memory block in bytes */ size_t size; /* Traceback where the memory block was allocated */ traceback_t *traceback; } trace_t; #define tracemalloc_traced_memory _PyRuntime.tracemalloc.traced_memory #define tracemalloc_peak_traced_memory _PyRuntime.tracemalloc.peak_traced_memory #define tracemalloc_filenames _PyRuntime.tracemalloc.filenames #define tracemalloc_traceback _PyRuntime.tracemalloc.traceback #define tracemalloc_tracebacks _PyRuntime.tracemalloc.tracebacks #define tracemalloc_traces _PyRuntime.tracemalloc.traces #define tracemalloc_domains _PyRuntime.tracemalloc.domains #ifdef TRACE_DEBUG static void tracemalloc_error(const char *format, ...) { va_list ap; fprintf(stderr, "tracemalloc: "); va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); fprintf(stderr, "\n"); fflush(stderr); } #endif #if defined(TRACE_RAW_MALLOC) #define REENTRANT_THREADLOCAL #define tracemalloc_reentrant_key _PyRuntime.tracemalloc.reentrant_key /* Any non-NULL pointer can be used */ #define REENTRANT Py_True static int get_reentrant(void) { void *ptr; assert(PyThread_tss_is_created(&tracemalloc_reentrant_key)); ptr = PyThread_tss_get(&tracemalloc_reentrant_key); if (ptr != NULL) { assert(ptr == REENTRANT); return 1; } else return 0; } static void set_reentrant(int reentrant) { assert(reentrant == 0 || reentrant == 1); assert(PyThread_tss_is_created(&tracemalloc_reentrant_key)); if (reentrant) { assert(!get_reentrant()); PyThread_tss_set(&tracemalloc_reentrant_key, REENTRANT); } else { assert(get_reentrant()); PyThread_tss_set(&tracemalloc_reentrant_key, NULL); } } #else /* TRACE_RAW_MALLOC not defined: variable protected by the GIL */ static int tracemalloc_reentrant = 0; static int get_reentrant(void) { return tracemalloc_reentrant; } static void set_reentrant(int reentrant) { assert(reentrant != tracemalloc_reentrant); tracemalloc_reentrant = reentrant; } #endif static Py_uhash_t hashtable_hash_pyobject(const void *key) { PyObject *obj = (PyObject *)key; return PyObject_Hash(obj); } static int hashtable_compare_unicode(const void *key1, const void *key2) { PyObject *obj1 = (PyObject *)key1; PyObject *obj2 = (PyObject *)key2; if (obj1 != NULL && obj2 != NULL) { return (PyUnicode_Compare(obj1, obj2) == 0); } else { return obj1 == obj2; } } static Py_uhash_t hashtable_hash_uint(const void *key_raw) { unsigned int key = (unsigned int)FROM_PTR(key_raw); return (Py_uhash_t)key; } static _Py_hashtable_t * hashtable_new(_Py_hashtable_hash_func hash_func, _Py_hashtable_compare_func compare_func, _Py_hashtable_destroy_func key_destroy_func, _Py_hashtable_destroy_func value_destroy_func) { _Py_hashtable_allocator_t hashtable_alloc = {malloc, free}; return _Py_hashtable_new_full(hash_func, compare_func, key_destroy_func, value_destroy_func, &hashtable_alloc); } static void* raw_malloc(size_t size) { return allocators.raw.malloc(allocators.raw.ctx, size); } static void raw_free(void *ptr) { allocators.raw.free(allocators.raw.ctx, ptr); } static Py_uhash_t hashtable_hash_traceback(const void *key) { const traceback_t *traceback = (const traceback_t *)key; return traceback->hash; } static int hashtable_compare_traceback(const void *key1, const void *key2) { const traceback_t *traceback1 = (const traceback_t *)key1; const traceback_t *traceback2 = (const traceback_t *)key2; if (traceback1->nframe != traceback2->nframe) { return 0; } if (traceback1->total_nframe != traceback2->total_nframe) { return 0; } for (int i=0; i < traceback1->nframe; i++) { const frame_t *frame1 = &traceback1->frames[i]; const frame_t *frame2 = &traceback2->frames[i]; if (frame1->lineno != frame2->lineno) { return 0; } if (frame1->filename != frame2->filename) { assert(PyUnicode_Compare(frame1->filename, frame2->filename) != 0); return 0; } } return 1; } static void tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame) { frame->filename = &_Py_STR(anon_unknown); int lineno = PyUnstable_InterpreterFrame_GetLine(pyframe); if (lineno < 0) { lineno = 0; } frame->lineno = (unsigned int)lineno; PyObject *filename = pyframe->f_code->co_filename; if (filename == NULL) { #ifdef TRACE_DEBUG tracemalloc_error("failed to get the filename of the code object"); #endif return; } if (!PyUnicode_Check(filename)) { #ifdef TRACE_DEBUG tracemalloc_error("filename is not a unicode string"); #endif return; } if (!PyUnicode_IS_READY(filename)) { /* Don't make a Unicode string ready to avoid reentrant calls to tracemalloc_malloc() or tracemalloc_realloc() */ #ifdef TRACE_DEBUG tracemalloc_error("filename is not a ready unicode string"); #endif return; } /* intern the filename */ _Py_hashtable_entry_t *entry; entry = _Py_hashtable_get_entry(tracemalloc_filenames, filename); if (entry != NULL) { filename = (PyObject *)entry->key; } else { /* tracemalloc_filenames is responsible to keep a reference to the filename */ if (_Py_hashtable_set(tracemalloc_filenames, Py_NewRef(filename), NULL) < 0) { Py_DECREF(filename); #ifdef TRACE_DEBUG tracemalloc_error("failed to intern the filename"); #endif return; } } /* the tracemalloc_filenames table keeps a reference to the filename */ frame->filename = filename; } static Py_uhash_t traceback_hash(traceback_t *traceback) { /* code based on tuplehash() of Objects/tupleobject.c */ Py_uhash_t x, y; /* Unsigned for defined overflow behavior. */ int len = traceback->nframe; Py_uhash_t mult = _PyHASH_MULTIPLIER; frame_t *frame; x = 0x345678UL; frame = traceback->frames; while (--len >= 0) { y = (Py_uhash_t)PyObject_Hash(frame->filename); y ^= (Py_uhash_t)frame->lineno; frame++; x = (x ^ y) * mult; /* the cast might truncate len; that doesn't change hash stability */ mult += (Py_uhash_t)(82520UL + len + len); } x ^= traceback->total_nframe; x += 97531UL; return x; } static void traceback_get_frames(traceback_t *traceback) { PyThreadState *tstate = PyGILState_GetThisThreadState(); if (tstate == NULL) { #ifdef TRACE_DEBUG tracemalloc_error("failed to get the current thread state"); #endif return; } _PyInterpreterFrame *pyframe = _PyThreadState_GetFrame(tstate); while (pyframe) { if (traceback->nframe < tracemalloc_config.max_nframe) { tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]); assert(traceback->frames[traceback->nframe].filename != NULL); traceback->nframe++; } if (traceback->total_nframe < UINT16_MAX) { traceback->total_nframe++; } pyframe = _PyFrame_GetFirstComplete(pyframe->previous); } } static traceback_t * traceback_new(void) { traceback_t *traceback; _Py_hashtable_entry_t *entry; assert(PyGILState_Check()); /* get frames */ traceback = tracemalloc_traceback; traceback->nframe = 0; traceback->total_nframe = 0; traceback_get_frames(traceback); if (traceback->nframe == 0) return &tracemalloc_empty_traceback; traceback->hash = traceback_hash(traceback); /* intern the traceback */ entry = _Py_hashtable_get_entry(tracemalloc_tracebacks, traceback); if (entry != NULL) { traceback = (traceback_t *)entry->key; } else { traceback_t *copy; size_t traceback_size; traceback_size = TRACEBACK_SIZE(traceback->nframe); copy = raw_malloc(traceback_size); if (copy == NULL) { #ifdef TRACE_DEBUG tracemalloc_error("failed to intern the traceback: malloc failed"); #endif return NULL; } memcpy(copy, traceback, traceback_size); if (_Py_hashtable_set(tracemalloc_tracebacks, copy, NULL) < 0) { raw_free(copy); #ifdef TRACE_DEBUG tracemalloc_error("failed to intern the traceback: putdata failed"); #endif return NULL; } traceback = copy; } return traceback; } static _Py_hashtable_t* tracemalloc_create_traces_table(void) { return hashtable_new(_Py_hashtable_hash_ptr, _Py_hashtable_compare_direct, NULL, raw_free); } static _Py_hashtable_t* tracemalloc_create_domains_table(void) { return hashtable_new(hashtable_hash_uint, _Py_hashtable_compare_direct, NULL, (_Py_hashtable_destroy_func)_Py_hashtable_destroy); } static _Py_hashtable_t* tracemalloc_get_traces_table(unsigned int domain) { if (domain == DEFAULT_DOMAIN) { return tracemalloc_traces; } else { return _Py_hashtable_get(tracemalloc_domains, TO_PTR(domain)); } } static void tracemalloc_remove_trace(unsigned int domain, uintptr_t ptr) { assert(tracemalloc_config.tracing); _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain); if (!traces) { return; } trace_t *trace = _Py_hashtable_steal(traces, TO_PTR(ptr)); if (!trace) { return; } assert(tracemalloc_traced_memory >= trace->size); tracemalloc_traced_memory -= trace->size; raw_free(trace); } #define REMOVE_TRACE(ptr) \ tracemalloc_remove_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr)) static int tracemalloc_add_trace(unsigned int domain, uintptr_t ptr, size_t size) { assert(tracemalloc_config.tracing); traceback_t *traceback = traceback_new(); if (traceback == NULL) { return -1; } _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain); if (traces == NULL) { traces = tracemalloc_create_traces_table(); if (traces == NULL) { return -1; } if (_Py_hashtable_set(tracemalloc_domains, TO_PTR(domain), traces) < 0) { _Py_hashtable_destroy(traces); return -1; } } trace_t *trace = _Py_hashtable_get(traces, TO_PTR(ptr)); if (trace != NULL) { /* the memory block is already tracked */ assert(tracemalloc_traced_memory >= trace->size); tracemalloc_traced_memory -= trace->size; trace->size = size; trace->traceback = traceback; } else { trace = raw_malloc(sizeof(trace_t)); if (trace == NULL) { return -1; } trace->size = size; trace->traceback = traceback; int res = _Py_hashtable_set(traces, TO_PTR(ptr), trace); if (res != 0) { raw_free(trace); return res; } } assert(tracemalloc_traced_memory <= SIZE_MAX - size); tracemalloc_traced_memory += size; if (tracemalloc_traced_memory > tracemalloc_peak_traced_memory) { tracemalloc_peak_traced_memory = tracemalloc_traced_memory; } return 0; } #define ADD_TRACE(ptr, size) \ tracemalloc_add_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr), size) static void* tracemalloc_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize) { PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; void *ptr; assert(elsize == 0 || nelem <= SIZE_MAX / elsize); if (use_calloc) ptr = alloc->calloc(alloc->ctx, nelem, elsize); else ptr = alloc->malloc(alloc->ctx, nelem * elsize); if (ptr == NULL) return NULL; TABLES_LOCK(); if (ADD_TRACE(ptr, nelem * elsize) < 0) { /* Failed to allocate a trace for the new memory block */ TABLES_UNLOCK(); alloc->free(alloc->ctx, ptr); return NULL; } TABLES_UNLOCK(); return ptr; } static void* tracemalloc_realloc(void *ctx, void *ptr, size_t new_size) { PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; void *ptr2; ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); if (ptr2 == NULL) return NULL; if (ptr != NULL) { /* an existing memory block has been resized */ TABLES_LOCK(); /* tracemalloc_add_trace() updates the trace if there is already a trace at address ptr2 */ if (ptr2 != ptr) { REMOVE_TRACE(ptr); } if (ADD_TRACE(ptr2, new_size) < 0) { /* Memory allocation failed. The error cannot be reported to the caller, because realloc() may already have shrunk the memory block and so removed bytes. This case is very unlikely: a hash entry has just been released, so the hash table should have at least one free entry. The GIL and the table lock ensures that only one thread is allocating memory. */ Py_FatalError("tracemalloc_realloc() failed to allocate a trace"); } TABLES_UNLOCK(); } else { /* new allocation */ TABLES_LOCK(); if (ADD_TRACE(ptr2, new_size) < 0) { /* Failed to allocate a trace for the new memory block */ TABLES_UNLOCK(); alloc->free(alloc->ctx, ptr2); return NULL; } TABLES_UNLOCK(); } return ptr2; } static void tracemalloc_free(void *ctx, void *ptr) { PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; if (ptr == NULL) return; /* GIL cannot be locked in PyMem_RawFree() because it would introduce a deadlock in _PyThreadState_DeleteCurrent(). */ alloc->free(alloc->ctx, ptr); TABLES_LOCK(); REMOVE_TRACE(ptr); TABLES_UNLOCK(); } static void* tracemalloc_alloc_gil(int use_calloc, void *ctx, size_t nelem, size_t elsize) { void *ptr; if (get_reentrant()) { PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; if (use_calloc) return alloc->calloc(alloc->ctx, nelem, elsize); else return alloc->malloc(alloc->ctx, nelem * elsize); } /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for allocations larger than 512 bytes, don't trace the same memory allocation twice. */ set_reentrant(1); ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize); set_reentrant(0); return ptr; } static void* tracemalloc_malloc_gil(void *ctx, size_t size) { return tracemalloc_alloc_gil(0, ctx, 1, size); } static void* tracemalloc_calloc_gil(void *ctx, size_t nelem, size_t elsize) { return tracemalloc_alloc_gil(1, ctx, nelem, elsize); } static void* tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size) { void *ptr2; if (get_reentrant()) { /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc(). Example: PyMem_RawRealloc() is called internally by pymalloc (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new arena (new_arena()). */ PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); if (ptr2 != NULL && ptr != NULL) { TABLES_LOCK(); REMOVE_TRACE(ptr); TABLES_UNLOCK(); } return ptr2; } /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for allocations larger than 512 bytes. Don't trace the same memory allocation twice. */ set_reentrant(1); ptr2 = tracemalloc_realloc(ctx, ptr, new_size); set_reentrant(0); return ptr2; } #ifdef TRACE_RAW_MALLOC static void* tracemalloc_raw_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize) { PyGILState_STATE gil_state; void *ptr; if (get_reentrant()) { PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; if (use_calloc) return alloc->calloc(alloc->ctx, nelem, elsize); else return alloc->malloc(alloc->ctx, nelem * elsize); } /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() indirectly which would call PyGILState_Ensure() if reentrant are not disabled. */ set_reentrant(1); gil_state = PyGILState_Ensure(); ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize); PyGILState_Release(gil_state); set_reentrant(0); return ptr; } static void* tracemalloc_raw_malloc(void *ctx, size_t size) { return tracemalloc_raw_alloc(0, ctx, 1, size); } static void* tracemalloc_raw_calloc(void *ctx, size_t nelem, size_t elsize) { return tracemalloc_raw_alloc(1, ctx, nelem, elsize); } static void* tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size) { PyGILState_STATE gil_state; void *ptr2; if (get_reentrant()) { /* Reentrant call to PyMem_RawRealloc(). */ PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); if (ptr2 != NULL && ptr != NULL) { TABLES_LOCK(); REMOVE_TRACE(ptr); TABLES_UNLOCK(); } return ptr2; } /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() indirectly which would call PyGILState_Ensure() if reentrant calls are not disabled. */ set_reentrant(1); gil_state = PyGILState_Ensure(); ptr2 = tracemalloc_realloc(ctx, ptr, new_size); PyGILState_Release(gil_state); set_reentrant(0); return ptr2; } #endif /* TRACE_RAW_MALLOC */ static void tracemalloc_clear_filename(void *value) { PyObject *filename = (PyObject *)value; Py_DECREF(filename); } /* reentrant flag must be set to call this function and GIL must be held */ static void tracemalloc_clear_traces(void) { /* The GIL protects variables against concurrent access */ assert(PyGILState_Check()); TABLES_LOCK(); _Py_hashtable_clear(tracemalloc_traces); _Py_hashtable_clear(tracemalloc_domains); tracemalloc_traced_memory = 0; tracemalloc_peak_traced_memory = 0; TABLES_UNLOCK(); _Py_hashtable_clear(tracemalloc_tracebacks); _Py_hashtable_clear(tracemalloc_filenames); } int _PyTraceMalloc_Init(void) { if (tracemalloc_config.initialized == TRACEMALLOC_FINALIZED) { PyErr_SetString(PyExc_RuntimeError, "the tracemalloc module has been unloaded"); return -1; } if (tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED) return 0; PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); #ifdef REENTRANT_THREADLOCAL if (PyThread_tss_create(&tracemalloc_reentrant_key) != 0) { #ifdef MS_WINDOWS PyErr_SetFromWindowsErr(0); #else PyErr_SetFromErrno(PyExc_OSError); #endif return -1; } #endif #if defined(TRACE_RAW_MALLOC) if (tables_lock == NULL) { tables_lock = PyThread_allocate_lock(); if (tables_lock == NULL) { PyErr_SetString(PyExc_RuntimeError, "cannot allocate lock"); return -1; } } #endif tracemalloc_filenames = hashtable_new(hashtable_hash_pyobject, hashtable_compare_unicode, tracemalloc_clear_filename, NULL); tracemalloc_tracebacks = hashtable_new(hashtable_hash_traceback, hashtable_compare_traceback, NULL, raw_free); tracemalloc_traces = tracemalloc_create_traces_table(); tracemalloc_domains = tracemalloc_create_domains_table(); if (tracemalloc_filenames == NULL || tracemalloc_tracebacks == NULL || tracemalloc_traces == NULL || tracemalloc_domains == NULL) { PyErr_NoMemory(); return -1; } tracemalloc_empty_traceback.nframe = 1; tracemalloc_empty_traceback.total_nframe = 1; /* borrowed reference */ tracemalloc_empty_traceback.frames[0].filename = &_Py_STR(anon_unknown); tracemalloc_empty_traceback.frames[0].lineno = 0; tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback); tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED; return 0; } static void tracemalloc_deinit(void) { if (tracemalloc_config.initialized != TRACEMALLOC_INITIALIZED) return; tracemalloc_config.initialized = TRACEMALLOC_FINALIZED; _PyTraceMalloc_Stop(); /* destroy hash tables */ _Py_hashtable_destroy(tracemalloc_domains); _Py_hashtable_destroy(tracemalloc_traces); _Py_hashtable_destroy(tracemalloc_tracebacks); _Py_hashtable_destroy(tracemalloc_filenames); #if defined(TRACE_RAW_MALLOC) if (tables_lock != NULL) { PyThread_free_lock(tables_lock); tables_lock = NULL; } #endif #ifdef REENTRANT_THREADLOCAL PyThread_tss_delete(&tracemalloc_reentrant_key); #endif } int _PyTraceMalloc_Start(int max_nframe) { PyMemAllocatorEx alloc; size_t size; if (max_nframe < 1 || (unsigned long) max_nframe > MAX_NFRAME) { PyErr_Format(PyExc_ValueError, "the number of frames must be in range [1; %lu]", MAX_NFRAME); return -1; } if (_PyTraceMalloc_Init() < 0) { return -1; } if (tracemalloc_config.tracing) { /* hook already installed: do nothing */ return 0; } tracemalloc_config.max_nframe = max_nframe; /* allocate a buffer to store a new traceback */ size = TRACEBACK_SIZE(max_nframe); assert(tracemalloc_traceback == NULL); tracemalloc_traceback = raw_malloc(size); if (tracemalloc_traceback == NULL) { PyErr_NoMemory(); return -1; } #ifdef TRACE_RAW_MALLOC alloc.malloc = tracemalloc_raw_malloc; alloc.calloc = tracemalloc_raw_calloc; alloc.realloc = tracemalloc_raw_realloc; alloc.free = tracemalloc_free; alloc.ctx = &allocators.raw; PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc); #endif alloc.malloc = tracemalloc_malloc_gil; alloc.calloc = tracemalloc_calloc_gil; alloc.realloc = tracemalloc_realloc_gil; alloc.free = tracemalloc_free; alloc.ctx = &allocators.mem; PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem); PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc); alloc.ctx = &allocators.obj; PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj); PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc); /* everything is ready: start tracing Python memory allocations */ tracemalloc_config.tracing = 1; return 0; } void _PyTraceMalloc_Stop(void) { if (!tracemalloc_config.tracing) return; /* stop tracing Python memory allocations */ tracemalloc_config.tracing = 0; /* unregister the hook on memory allocators */ #ifdef TRACE_RAW_MALLOC PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); #endif PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem); PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj); tracemalloc_clear_traces(); /* release memory */ raw_free(tracemalloc_traceback); tracemalloc_traceback = NULL; } static PyObject* frame_to_pyobject(frame_t *frame) { PyObject *frame_obj, *lineno_obj; frame_obj = PyTuple_New(2); if (frame_obj == NULL) return NULL; PyTuple_SET_ITEM(frame_obj, 0, Py_NewRef(frame->filename)); lineno_obj = PyLong_FromUnsignedLong(frame->lineno); if (lineno_obj == NULL) { Py_DECREF(frame_obj); return NULL; } PyTuple_SET_ITEM(frame_obj, 1, lineno_obj); return frame_obj; } static PyObject* traceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table) { PyObject *frames; if (intern_table != NULL) { frames = _Py_hashtable_get(intern_table, (const void *)traceback); if (frames) { return Py_NewRef(frames); } } frames = PyTuple_New(traceback->nframe); if (frames == NULL) return NULL; for (int i=0; i < traceback->nframe; i++) { PyObject *frame = frame_to_pyobject(&traceback->frames[i]); if (frame == NULL) { Py_DECREF(frames); return NULL; } PyTuple_SET_ITEM(frames, i, frame); } if (intern_table != NULL) { if (_Py_hashtable_set(intern_table, traceback, frames) < 0) { Py_DECREF(frames); PyErr_NoMemory(); return NULL; } /* intern_table keeps a new reference to frames */ Py_INCREF(frames); } return frames; } static PyObject* trace_to_pyobject(unsigned int domain, const trace_t *trace, _Py_hashtable_t *intern_tracebacks) { PyObject *trace_obj = NULL; PyObject *obj; trace_obj = PyTuple_New(4); if (trace_obj == NULL) return NULL; obj = PyLong_FromSize_t(domain); if (obj == NULL) { Py_DECREF(trace_obj); return NULL; } PyTuple_SET_ITEM(trace_obj, 0, obj); obj = PyLong_FromSize_t(trace->size); if (obj == NULL) { Py_DECREF(trace_obj); return NULL; } PyTuple_SET_ITEM(trace_obj, 1, obj); obj = traceback_to_pyobject(trace->traceback, intern_tracebacks); if (obj == NULL) { Py_DECREF(trace_obj); return NULL; } PyTuple_SET_ITEM(trace_obj, 2, obj); obj = PyLong_FromUnsignedLong(trace->traceback->total_nframe); if (obj == NULL) { Py_DECREF(trace_obj); return NULL; } PyTuple_SET_ITEM(trace_obj, 3, obj); return trace_obj; } typedef struct { _Py_hashtable_t *traces; _Py_hashtable_t *domains; _Py_hashtable_t *tracebacks; PyObject *list; unsigned int domain; } get_traces_t; static int tracemalloc_copy_trace(_Py_hashtable_t *traces, const void *key, const void *value, void *user_data) { _Py_hashtable_t *traces2 = (_Py_hashtable_t *)user_data; trace_t *trace = (trace_t *)value; trace_t *trace2 = raw_malloc(sizeof(trace_t)); if (trace2 == NULL) { return -1; } *trace2 = *trace; if (_Py_hashtable_set(traces2, key, trace2) < 0) { raw_free(trace2); return -1; } return 0; } static _Py_hashtable_t* tracemalloc_copy_traces(_Py_hashtable_t *traces) { _Py_hashtable_t *traces2 = tracemalloc_create_traces_table(); if (traces2 == NULL) { return NULL; } int err = _Py_hashtable_foreach(traces, tracemalloc_copy_trace, traces2); if (err) { _Py_hashtable_destroy(traces2); return NULL; } return traces2; } static int tracemalloc_copy_domain(_Py_hashtable_t *domains, const void *key, const void *value, void *user_data) { _Py_hashtable_t *domains2 = (_Py_hashtable_t *)user_data; unsigned int domain = (unsigned int)FROM_PTR(key); _Py_hashtable_t *traces = (_Py_hashtable_t *)value; _Py_hashtable_t *traces2 = tracemalloc_copy_traces(traces); if (traces2 == NULL) { return -1; } if (_Py_hashtable_set(domains2, TO_PTR(domain), traces2) < 0) { _Py_hashtable_destroy(traces2); return -1; } return 0; } static _Py_hashtable_t* tracemalloc_copy_domains(_Py_hashtable_t *domains) { _Py_hashtable_t *domains2 = tracemalloc_create_domains_table(); if (domains2 == NULL) { return NULL; } int err = _Py_hashtable_foreach(domains, tracemalloc_copy_domain, domains2); if (err) { _Py_hashtable_destroy(domains2); return NULL; } return domains2; } static int tracemalloc_get_traces_fill(_Py_hashtable_t *traces, const void *key, const void *value, void *user_data) { get_traces_t *get_traces = user_data; const trace_t *trace = (const trace_t *)value; PyObject *tuple = trace_to_pyobject(get_traces->domain, trace, get_traces->tracebacks); if (tuple == NULL) { return 1; } int res = PyList_Append(get_traces->list, tuple); Py_DECREF(tuple); if (res < 0) { return 1; } return 0; } static int tracemalloc_get_traces_domain(_Py_hashtable_t *domains, const void *key, const void *value, void *user_data) { get_traces_t *get_traces = user_data; unsigned int domain = (unsigned int)FROM_PTR(key); _Py_hashtable_t *traces = (_Py_hashtable_t *)value; get_traces->domain = domain; return _Py_hashtable_foreach(traces, tracemalloc_get_traces_fill, get_traces); } static void tracemalloc_pyobject_decref(void *value) { PyObject *obj = (PyObject *)value; Py_DECREF(obj); } static traceback_t* tracemalloc_get_traceback(unsigned int domain, uintptr_t ptr) { if (!tracemalloc_config.tracing) return NULL; trace_t *trace; TABLES_LOCK(); _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain); if (traces) { trace = _Py_hashtable_get(traces, TO_PTR(ptr)); } else { trace = NULL; } TABLES_UNLOCK(); if (!trace) { return NULL; } return trace->traceback; } #define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str)) static void _PyMem_DumpFrame(int fd, frame_t * frame) { PUTS(fd, " File \""); _Py_DumpASCII(fd, frame->filename); PUTS(fd, "\", line "); _Py_DumpDecimal(fd, frame->lineno); PUTS(fd, "\n"); } /* Dump the traceback where a memory block was allocated into file descriptor fd. The function may block on TABLES_LOCK() but it is unlikely. */ void _PyMem_DumpTraceback(int fd, const void *ptr) { traceback_t *traceback; int i; if (!tracemalloc_config.tracing) { PUTS(fd, "Enable tracemalloc to get the memory block " "allocation traceback\n\n"); return; } traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr); if (traceback == NULL) return; PUTS(fd, "Memory block allocated at (most recent call first):\n"); for (i=0; i < traceback->nframe; i++) { _PyMem_DumpFrame(fd, &traceback->frames[i]); } PUTS(fd, "\n"); } #undef PUTS static int tracemalloc_get_tracemalloc_memory_cb(_Py_hashtable_t *domains, const void *key, const void *value, void *user_data) { const _Py_hashtable_t *traces = value; size_t *size = (size_t*)user_data; *size += _Py_hashtable_size(traces); return 0; } int PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr, size_t size) { int res; PyGILState_STATE gil_state; if (!tracemalloc_config.tracing) { /* tracemalloc is not tracing: do nothing */ return -2; } gil_state = PyGILState_Ensure(); TABLES_LOCK(); res = tracemalloc_add_trace(domain, ptr, size); TABLES_UNLOCK(); PyGILState_Release(gil_state); return res; } int PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr) { if (!tracemalloc_config.tracing) { /* tracemalloc is not tracing: do nothing */ return -2; } TABLES_LOCK(); tracemalloc_remove_trace(domain, ptr); TABLES_UNLOCK(); return 0; } void _PyTraceMalloc_Fini(void) { assert(PyGILState_Check()); tracemalloc_deinit(); } /* If the object memory block is already traced, update its trace with the current Python traceback. Do nothing if tracemalloc is not tracing memory allocations or if the object memory block is not already traced. */ int _PyTraceMalloc_NewReference(PyObject *op) { assert(PyGILState_Check()); if (!tracemalloc_config.tracing) { /* tracemalloc is not tracing: do nothing */ return -1; } PyTypeObject *type = Py_TYPE(op); const size_t presize = _PyType_PreHeaderSize(type); uintptr_t ptr = (uintptr_t)((char *)op - presize); int res = -1; TABLES_LOCK(); trace_t *trace = _Py_hashtable_get(tracemalloc_traces, TO_PTR(ptr)); if (trace != NULL) { /* update the traceback of the memory block */ traceback_t *traceback = traceback_new(); if (traceback != NULL) { trace->traceback = traceback; res = 0; } } /* else: cannot track the object, its memory block size is unknown */ TABLES_UNLOCK(); return res; } PyObject* _PyTraceMalloc_GetTraceback(unsigned int domain, uintptr_t ptr) { traceback_t *traceback; traceback = tracemalloc_get_traceback(domain, ptr); if (traceback == NULL) Py_RETURN_NONE; return traceback_to_pyobject(traceback, NULL); } int _PyTraceMalloc_IsTracing(void) { return tracemalloc_config.tracing; } void _PyTraceMalloc_ClearTraces(void) { if (!tracemalloc_config.tracing) { return; } set_reentrant(1); tracemalloc_clear_traces(); set_reentrant(0); } PyObject * _PyTraceMalloc_GetTraces(void) { get_traces_t get_traces; get_traces.domain = DEFAULT_DOMAIN; get_traces.traces = NULL; get_traces.domains = NULL; get_traces.tracebacks = NULL; get_traces.list = PyList_New(0); if (get_traces.list == NULL) goto error; if (!tracemalloc_config.tracing) return get_traces.list; /* the traceback hash table is used temporarily to intern traceback tuple of (filename, lineno) tuples */ get_traces.tracebacks = hashtable_new(_Py_hashtable_hash_ptr, _Py_hashtable_compare_direct, NULL, tracemalloc_pyobject_decref); if (get_traces.tracebacks == NULL) { goto no_memory; } // Copy all traces so tracemalloc_get_traces_fill() doesn't have to disable // temporarily tracemalloc which would impact other threads and so would // miss allocations while get_traces() is called. TABLES_LOCK(); get_traces.traces = tracemalloc_copy_traces(tracemalloc_traces); TABLES_UNLOCK(); if (get_traces.traces == NULL) { goto no_memory; } TABLES_LOCK(); get_traces.domains = tracemalloc_copy_domains(tracemalloc_domains); TABLES_UNLOCK(); if (get_traces.domains == NULL) { goto no_memory; } // Convert traces to a list of tuples set_reentrant(1); int err = _Py_hashtable_foreach(get_traces.traces, tracemalloc_get_traces_fill, &get_traces); if (!err) { err = _Py_hashtable_foreach(get_traces.domains, tracemalloc_get_traces_domain, &get_traces); } set_reentrant(0); if (err) { goto error; } goto finally; no_memory: PyErr_NoMemory(); error: Py_CLEAR(get_traces.list); finally: if (get_traces.tracebacks != NULL) { _Py_hashtable_destroy(get_traces.tracebacks); } if (get_traces.traces != NULL) { _Py_hashtable_destroy(get_traces.traces); } if (get_traces.domains != NULL) { _Py_hashtable_destroy(get_traces.domains); } return get_traces.list; } PyObject * _PyTraceMalloc_GetObjectTraceback(PyObject *obj) /*[clinic end generated code: output=41ee0553a658b0aa input=29495f1b21c53212]*/ { PyTypeObject *type; traceback_t *traceback; type = Py_TYPE(obj); const size_t presize = _PyType_PreHeaderSize(type); uintptr_t ptr = (uintptr_t)((char *)obj - presize); traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, ptr); if (traceback == NULL) { Py_RETURN_NONE; } return traceback_to_pyobject(traceback, NULL); } int _PyTraceMalloc_GetTracebackLimit(void) { return tracemalloc_config.max_nframe; } size_t _PyTraceMalloc_GetMemory(void) { size_t size; size = _Py_hashtable_size(tracemalloc_tracebacks); size += _Py_hashtable_size(tracemalloc_filenames); TABLES_LOCK(); size += _Py_hashtable_size(tracemalloc_traces); _Py_hashtable_foreach(tracemalloc_domains, tracemalloc_get_tracemalloc_memory_cb, &size); TABLES_UNLOCK(); return size; } PyObject * _PyTraceMalloc_GetTracedMemory(void) { Py_ssize_t size, peak_size; if (!tracemalloc_config.tracing) return Py_BuildValue("ii", 0, 0); TABLES_LOCK(); size = tracemalloc_traced_memory; peak_size = tracemalloc_peak_traced_memory; TABLES_UNLOCK(); return Py_BuildValue("nn", size, peak_size); } void _PyTraceMalloc_ResetPeak(void) { if (!tracemalloc_config.tracing) { return; } TABLES_LOCK(); tracemalloc_peak_traced_memory = tracemalloc_traced_memory; TABLES_UNLOCK(); }