codekingpro/portable-devtools
114k
1#ifndef Py_INTERNAL_OPTIMIZER_H2#define Py_INTERNAL_OPTIMIZER_H3#ifdef __cplusplus4extern "C" {5#endif6 7#ifndef Py_BUILD_CORE8# error "this header requires Py_BUILD_CORE define"9#endif10 11#include "pycore_typedefs.h" // _PyInterpreterFrame12#include "pycore_uop_ids.h"13#include <stdbool.h>14 15 16typedef struct _PyExecutorLinkListNode {17 struct _PyExecutorObject *next;18 struct _PyExecutorObject *previous;19} _PyExecutorLinkListNode;20 21 22/* Bloom filter with m = 25623 * https://en.wikipedia.org/wiki/Bloom_filter */24#define _Py_BLOOM_FILTER_WORDS 825 26typedef struct {27 uint32_t bits[_Py_BLOOM_FILTER_WORDS];28} _PyBloomFilter;29 30typedef struct {31 uint8_t opcode;32 uint8_t oparg;33 uint8_t valid:1;34 uint8_t linked:1;35 uint8_t chain_depth:6; // Must be big enough for MAX_CHAIN_DEPTH - 1.36 bool warm;37 int index; // Index of ENTER_EXECUTOR (if code isn't NULL, below).38 _PyBloomFilter bloom;39 _PyExecutorLinkListNode links;40 PyCodeObject *code; // Weak (NULL if no corresponding ENTER_EXECUTOR).41} _PyVMData;42 43/* Depending on the format,44 * the 32 bits between the oparg and operand are:45 * UOP_FORMAT_TARGET:46 * uint32_t target;47 * UOP_FORMAT_JUMP48 * uint16_t jump_target;49 * uint16_t error_target;50 */51typedef struct {52 uint16_t opcode:15;53 uint16_t format:1;54 uint16_t oparg;55 union {56 uint32_t target;57 struct {58 uint16_t jump_target;59 uint16_t error_target;60 };61 };62 uint64_t operand0; // A cache entry63 uint64_t operand1;64#ifdef Py_STATS65 uint64_t execution_count;66#endif67} _PyUOpInstruction;68 69typedef struct {70 uint32_t target;71 _Py_BackoffCounter temperature;72 struct _PyExecutorObject *executor;73} _PyExitData;74 75typedef struct _PyExecutorObject {76 PyObject_VAR_HEAD77 const _PyUOpInstruction *trace;78 _PyVMData vm_data; /* Used by the VM, but opaque to the optimizer */79 uint32_t exit_count;80 uint32_t code_size;81 size_t jit_size;82 void *jit_code;83 void *jit_side_entry;84 _PyExitData exits[1];85} _PyExecutorObject;86 87/* If pending deletion list gets large enough, then scan,88 * and free any executors that aren't executing89 * i.e. any that aren't a thread's current_executor. */90#define EXECUTOR_DELETE_LIST_MAX 10091 92// Export for '_opcode' shared extension (JIT compiler).93PyAPI_FUNC(_PyExecutorObject*) _Py_GetExecutor(PyCodeObject *code, int offset);94 95void _Py_ExecutorInit(_PyExecutorObject *, const _PyBloomFilter *);96void _Py_ExecutorDetach(_PyExecutorObject *);97void _Py_BloomFilter_Init(_PyBloomFilter *);98void _Py_BloomFilter_Add(_PyBloomFilter *bloom, void *obj);99PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj);100 101#define _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS 3102#define _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS 6103 104#ifdef _Py_TIER2105PyAPI_FUNC(void) _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is_invalidation);106PyAPI_FUNC(void) _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation);107PyAPI_FUNC(void) _Py_Executors_InvalidateCold(PyInterpreterState *interp);108 109#else110# define _Py_Executors_InvalidateDependency(A, B, C) ((void)0)111# define _Py_Executors_InvalidateAll(A, B) ((void)0)112# define _Py_Executors_InvalidateCold(A) ((void)0)113 114#endif115 116// Used as the threshold to trigger executor invalidation when117// trace_run_counter is greater than this value.118#define JIT_CLEANUP_THRESHOLD 100000119 120// This is the length of the trace we project initially.121#define UOP_MAX_TRACE_LENGTH 800122 123#define TRACE_STACK_SIZE 5124 125int _Py_uop_analyze_and_optimize(_PyInterpreterFrame *frame,126 _PyUOpInstruction *trace, int trace_len, int curr_stackentries,127 _PyBloomFilter *dependencies);128 129extern PyTypeObject _PyUOpExecutor_Type;130 131 132#define UOP_FORMAT_TARGET 0133#define UOP_FORMAT_JUMP 1134 135static inline uint32_t uop_get_target(const _PyUOpInstruction *inst)136{137 assert(inst->format == UOP_FORMAT_TARGET);138 return inst->target;139}140 141static inline uint16_t uop_get_jump_target(const _PyUOpInstruction *inst)142{143 assert(inst->format == UOP_FORMAT_JUMP);144 return inst->jump_target;145}146 147static inline uint16_t uop_get_error_target(const _PyUOpInstruction *inst)148{149 assert(inst->format != UOP_FORMAT_TARGET);150 return inst->error_target;151}152 153// Holds locals, stack, locals, stack ... co_consts (in that order)154#define MAX_ABSTRACT_INTERP_SIZE 4096155 156#define TY_ARENA_SIZE (UOP_MAX_TRACE_LENGTH * 5)157 158// Need extras for root frame and for overflow frame (see TRACE_STACK_PUSH())159#define MAX_ABSTRACT_FRAME_DEPTH (TRACE_STACK_SIZE + 2)160 161// The maximum number of side exits that we can take before requiring forward162// progress (and inserting a new ENTER_EXECUTOR instruction). In practice, this163// is the "maximum amount of polymorphism" that an isolated trace tree can164// handle before rejoining the rest of the program.165#define MAX_CHAIN_DEPTH 4166 167/* Symbols */168/* See explanation in optimizer_symbols.c */169 170 171typedef enum _JitSymType {172 JIT_SYM_UNKNOWN_TAG = 1,173 JIT_SYM_NULL_TAG = 2,174 JIT_SYM_NON_NULL_TAG = 3,175 JIT_SYM_BOTTOM_TAG = 4,176 JIT_SYM_TYPE_VERSION_TAG = 5,177 JIT_SYM_KNOWN_CLASS_TAG = 6,178 JIT_SYM_KNOWN_VALUE_TAG = 7,179 JIT_SYM_TUPLE_TAG = 8,180 JIT_SYM_TRUTHINESS_TAG = 9,181} JitSymType;182 183typedef struct _jit_opt_known_class {184 uint8_t tag;185 uint32_t version;186 PyTypeObject *type;187} JitOptKnownClass;188 189typedef struct _jit_opt_known_version {190 uint8_t tag;191 uint32_t version;192} JitOptKnownVersion;193 194typedef struct _jit_opt_known_value {195 uint8_t tag;196 PyObject *value;197} JitOptKnownValue;198 199#define MAX_SYMBOLIC_TUPLE_SIZE 7200 201typedef struct _jit_opt_tuple {202 uint8_t tag;203 uint8_t length;204 uint16_t items[MAX_SYMBOLIC_TUPLE_SIZE];205} JitOptTuple;206 207typedef struct {208 uint8_t tag;209 bool invert;210 uint16_t value;211} JitOptTruthiness;212 213typedef union _jit_opt_symbol {214 uint8_t tag;215 JitOptKnownClass cls;216 JitOptKnownValue value;217 JitOptKnownVersion version;218 JitOptTuple tuple;219 JitOptTruthiness truthiness;220} JitOptSymbol;221 222 223 224struct _Py_UOpsAbstractFrame {225 // Max stacklen226 int stack_len;227 int locals_len;228 229 JitOptSymbol **stack_pointer;230 JitOptSymbol **stack;231 JitOptSymbol **locals;232};233 234typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame;235 236typedef struct ty_arena {237 int ty_curr_number;238 int ty_max_number;239 JitOptSymbol arena[TY_ARENA_SIZE];240} ty_arena;241 242typedef struct _JitOptContext {243 char done;244 char out_of_space;245 bool contradiction;246 // The current "executing" frame.247 _Py_UOpsAbstractFrame *frame;248 _Py_UOpsAbstractFrame frames[MAX_ABSTRACT_FRAME_DEPTH];249 int curr_frame_depth;250 251 // Arena for the symbolic types.252 ty_arena t_arena;253 254 JitOptSymbol **n_consumed;255 JitOptSymbol **limit;256 JitOptSymbol *locals_and_stack[MAX_ABSTRACT_INTERP_SIZE];257} JitOptContext;258 259extern bool _Py_uop_sym_is_null(JitOptSymbol *sym);260extern bool _Py_uop_sym_is_not_null(JitOptSymbol *sym);261extern bool _Py_uop_sym_is_const(JitOptContext *ctx, JitOptSymbol *sym);262extern PyObject *_Py_uop_sym_get_const(JitOptContext *ctx, JitOptSymbol *sym);263extern JitOptSymbol *_Py_uop_sym_new_unknown(JitOptContext *ctx);264extern JitOptSymbol *_Py_uop_sym_new_not_null(JitOptContext *ctx);265extern JitOptSymbol *_Py_uop_sym_new_type(266 JitOptContext *ctx, PyTypeObject *typ);267extern JitOptSymbol *_Py_uop_sym_new_const(JitOptContext *ctx, PyObject *const_val);268extern JitOptSymbol *_Py_uop_sym_new_null(JitOptContext *ctx);269extern bool _Py_uop_sym_has_type(JitOptSymbol *sym);270extern bool _Py_uop_sym_matches_type(JitOptSymbol *sym, PyTypeObject *typ);271extern bool _Py_uop_sym_matches_type_version(JitOptSymbol *sym, unsigned int version);272extern void _Py_uop_sym_set_null(JitOptContext *ctx, JitOptSymbol *sym);273extern void _Py_uop_sym_set_non_null(JitOptContext *ctx, JitOptSymbol *sym);274extern void _Py_uop_sym_set_type(JitOptContext *ctx, JitOptSymbol *sym, PyTypeObject *typ);275extern bool _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptSymbol *sym, unsigned int version);276extern void _Py_uop_sym_set_const(JitOptContext *ctx, JitOptSymbol *sym, PyObject *const_val);277extern bool _Py_uop_sym_is_bottom(JitOptSymbol *sym);278extern int _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptSymbol *sym);279extern PyTypeObject *_Py_uop_sym_get_type(JitOptSymbol *sym);280extern bool _Py_uop_sym_is_immortal(JitOptSymbol *sym);281extern JitOptSymbol *_Py_uop_sym_new_tuple(JitOptContext *ctx, int size, JitOptSymbol **args);282extern JitOptSymbol *_Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptSymbol *sym, int item);283extern int _Py_uop_sym_tuple_length(JitOptSymbol *sym);284extern JitOptSymbol *_Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptSymbol *value, bool truthy);285 286extern void _Py_uop_abstractcontext_init(JitOptContext *ctx);287extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx);288 289extern _Py_UOpsAbstractFrame *_Py_uop_frame_new(290 JitOptContext *ctx,291 PyCodeObject *co,292 int curr_stackentries,293 JitOptSymbol **args,294 int arg_len);295extern int _Py_uop_frame_pop(JitOptContext *ctx);296 297PyAPI_FUNC(PyObject *) _Py_uop_symbols_test(PyObject *self, PyObject *ignored);298 299PyAPI_FUNC(int) _PyOptimizer_Optimize(_PyInterpreterFrame *frame, _Py_CODEUNIT *start, _PyExecutorObject **exec_ptr, int chain_depth);300 301static inline int is_terminator(const _PyUOpInstruction *uop)302{303 int opcode = uop->opcode;304 return (305 opcode == _EXIT_TRACE ||306 opcode == _JUMP_TO_TOP307 );308}309 310PyAPI_FUNC(int) _PyDumpExecutors(FILE *out);311#ifdef _Py_TIER2312extern void _Py_ClearExecutorDeletionList(PyInterpreterState *interp);313#endif314 315#ifdef __cplusplus316}317#endif318#endif /* !Py_INTERNAL_OPTIMIZER_H */319 