Skip to content

Commit d28150d

Browse files
committed
Add function symbol (with version) to optimizer symbols
1 parent 095bc77 commit d28150d

File tree

5 files changed

+166
-22
lines changed

5 files changed

+166
-22
lines changed

Include/internal/pycore_optimizer.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ typedef enum _JitSymType {
181181
JIT_SYM_TUPLE_TAG = 8,
182182
JIT_SYM_TRUTHINESS_TAG = 9,
183183
JIT_SYM_COMPACT_INT = 10,
184+
JIT_SYM_FUNCTION_TAG = 11,
184185
} JitSymType;
185186

186187
typedef struct _jit_opt_known_class {
@@ -217,6 +218,14 @@ typedef struct {
217218
uint8_t tag;
218219
} JitOptCompactInt;
219220

221+
typedef struct {
222+
uint8_t tag;
223+
bool value_is_code;
224+
uint32_t version;
225+
PyObject *function;
226+
} JitOptFunction;
227+
228+
220229
typedef union _jit_opt_symbol {
221230
uint8_t tag;
222231
JitOptKnownClass cls;
@@ -225,6 +234,7 @@ typedef union _jit_opt_symbol {
225234
JitOptTuple tuple;
226235
JitOptTruthiness truthiness;
227236
JitOptCompactInt compact;
237+
JitOptFunction function;
228238
} JitOptSymbol;
229239

230240

@@ -276,6 +286,9 @@ struct _Py_UOpsAbstractFrame {
276286
// Max stacklen
277287
int stack_len;
278288
int locals_len;
289+
bool function_checked;
290+
bool builtins_watched;
291+
bool globals_watched;
279292

280293
JitOptRef *stack_pointer;
281294
JitOptRef *stack;
@@ -298,6 +311,7 @@ typedef struct _JitOptContext {
298311
_Py_UOpsAbstractFrame *frame;
299312
_Py_UOpsAbstractFrame frames[MAX_ABSTRACT_FRAME_DEPTH];
300313
int curr_frame_depth;
314+
uint32_t prechecked_function_version;
301315

302316
// Arena for the symbolic types.
303317
ty_arena t_arena;
@@ -339,6 +353,8 @@ extern JitOptRef _Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptRef value,
339353
extern bool _Py_uop_sym_is_compact_int(JitOptRef sym);
340354
extern JitOptRef _Py_uop_sym_new_compact_int(JitOptContext *ctx);
341355
extern void _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef sym);
356+
extern void _Py_uop_sym_set_function_version(JitOptContext *ctx, JitOptRef ref, uint32_t version);
357+
extern uint32_t _Py_uop_sym_get_function_version(JitOptRef ref);
342358

343359
extern void _Py_uop_abstractcontext_init(JitOptContext *ctx);
344360
extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx);

Python/optimizer_analysis.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,8 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
344344
#define sym_set_type_version(SYM, VERSION) _Py_uop_sym_set_type_version(ctx, SYM, VERSION)
345345
#define sym_set_const(SYM, CNST) _Py_uop_sym_set_const(ctx, SYM, CNST)
346346
#define sym_set_compact_int(SYM) _Py_uop_sym_set_compact_int(ctx, SYM)
347+
#define sym_get_function_version(SYM) _Py_uop_sym_get_function_version(SYM)
348+
#define sym_set_function_version(SYM, VER) _Py_uop_sym_set_function_version(ctx, SYM, VER)
347349
#define sym_is_bottom _Py_uop_sym_is_bottom
348350
#define sym_truthiness _Py_uop_sym_truthiness
349351
#define frame_new _Py_uop_frame_new

Python/optimizer_bytecodes.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame;
2828
#define sym_set_type_version(SYM, VERSION) _Py_uop_sym_set_type_version(ctx, SYM, VERSION)
2929
#define sym_set_const(SYM, CNST) _Py_uop_sym_set_const(ctx, SYM, CNST)
3030
#define sym_set_compact_int(SYM) _Py_uop_sym_set_compact_int(ctx, SYM)
31+
#define sym_get_function_version(SYM) _Py_uop_sym_get_function_version(SYM)
32+
#define sym_set_function_version(SYM, VER) _Py_uop_sym_set_function_version(ctx, SYM, VER)
3133
#define sym_is_bottom _Py_uop_sym_is_bottom
3234
#define frame_new _Py_uop_frame_new
3335
#define frame_pop _Py_uop_frame_pop
@@ -663,12 +665,18 @@ dummy_func(void) {
663665
}
664666

665667
op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) {
666-
if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyFunction_Type)) {
667-
assert(PyFunction_Check(sym_get_const(ctx, callable)));
668-
REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
669-
this_instr->operand1 = (uintptr_t)sym_get_const(ctx, callable);
668+
assert(func_version != 0);
669+
if (sym_get_function_version(callable) == func_version) {
670+
REPLACE_OP(this_instr, NOP, 0, 0);
671+
}
672+
else {
673+
if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyFunction_Type)) {
674+
assert(PyFunction_Check(sym_get_const(ctx, callable)));
675+
REPLACE_OP(this_instr, _CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
676+
this_instr->operand1 = (uintptr_t)sym_get_const(ctx, callable);
677+
}
678+
sym_set_function_version(callable, func_version);
670679
}
671-
sym_set_type(callable, &PyFunction_Type);
672680
}
673681

674682
op(_CHECK_METHOD_VERSION, (func_version/2, callable, null, unused[oparg] -- callable, null, unused[oparg])) {

Python/optimizer_cases.c.h

Lines changed: 11 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/optimizer_symbols.c

Lines changed: 124 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ static void make_const(JitOptSymbol *sym, PyObject *val)
121121
static inline void
122122
sym_set_bottom(JitOptContext *ctx, JitOptSymbol *sym)
123123
{
124+
if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) {
125+
Py_CLEAR(sym->value.value);
126+
}
127+
if (sym->tag == JIT_SYM_FUNCTION_TAG) {
128+
Py_CLEAR(sym->function.function);
129+
}
124130
sym->tag = JIT_SYM_BOTTOM_TAG;
125131
ctx->done = true;
126132
ctx->contradiction = true;
@@ -143,19 +149,24 @@ bool
143149
_Py_uop_sym_is_const(JitOptContext *ctx, JitOptRef ref)
144150
{
145151
JitOptSymbol *sym = PyJitRef_Unwrap(ref);
146-
if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) {
147-
return true;
148-
}
149-
if (sym->tag == JIT_SYM_TRUTHINESS_TAG) {
150-
JitOptSymbol *value = allocation_base(ctx) + sym->truthiness.value;
151-
int truthiness = _Py_uop_sym_truthiness(ctx, PyJitRef_Wrap(value));
152-
if (truthiness < 0) {
153-
return false;
152+
switch(sym->tag) {
153+
case JIT_SYM_KNOWN_VALUE_TAG:
154+
return true;
155+
case JIT_SYM_TRUTHINESS_TAG:
156+
{
157+
JitOptSymbol *value = allocation_base(ctx) + sym->truthiness.value;
158+
int truthiness = _Py_uop_sym_truthiness(ctx, PyJitRef_Wrap(value));
159+
if (truthiness < 0) {
160+
return false;
161+
}
162+
make_const(sym, (truthiness ^ sym->truthiness.invert) ? Py_True : Py_False);
163+
return true;
154164
}
155-
make_const(sym, (truthiness ^ sym->truthiness.invert) ? Py_True : Py_False);
156-
return true;
165+
case JIT_SYM_FUNCTION_TAG:
166+
return sym->function.function != NULL;
167+
default:
168+
return false;
157169
}
158-
return false;
159170
}
160171

161172
bool
@@ -182,6 +193,9 @@ _Py_uop_sym_get_const(JitOptContext *ctx, JitOptRef ref)
182193
make_const(sym, res);
183194
return res;
184195
}
196+
if (sym->tag == JIT_SYM_FUNCTION_TAG) {
197+
return sym->function.function;
198+
}
185199
return NULL;
186200
}
187201

@@ -269,6 +283,11 @@ _Py_uop_sym_set_type(JitOptContext *ctx, JitOptRef ref, PyTypeObject *typ)
269283
sym_set_bottom(ctx, sym);
270284
}
271285
return;
286+
case JIT_SYM_FUNCTION_TAG:
287+
if (typ != &PyFunction_Type) {
288+
sym_set_bottom(ctx, sym);
289+
}
290+
return;
272291
}
273292
}
274293

@@ -307,6 +326,12 @@ _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptRef ref, unsigned int ver
307326
return false;
308327
};
309328
return true;
329+
case JIT_SYM_FUNCTION_TAG:
330+
if (PyFunction_Type.tp_version_tag != version) {
331+
sym_set_bottom(ctx, sym);
332+
return false;
333+
};
334+
return true;
310335
case JIT_SYM_TYPE_VERSION_TAG:
311336
if (sym->version.version != version) {
312337
sym_set_bottom(ctx, sym);
@@ -424,6 +449,14 @@ _Py_uop_sym_set_const(JitOptContext *ctx, JitOptRef ref, PyObject *const_val)
424449
sym_set_bottom(ctx, sym);
425450
}
426451
return;
452+
case JIT_SYM_FUNCTION_TAG:
453+
if (PyFunction_Check(const_val)) {
454+
sym->function.function = Py_NewRef(const_val);
455+
if (((PyFunctionObject *)const_val)->func_version != sym->function.version) {
456+
sym_set_bottom(ctx, sym);
457+
}
458+
}
459+
return;
427460
}
428461
}
429462

@@ -543,7 +576,8 @@ _Py_uop_sym_get_type(JitOptRef ref)
543576
return &PyBool_Type;
544577
case JIT_SYM_COMPACT_INT:
545578
return &PyLong_Type;
546-
579+
case JIT_SYM_FUNCTION_TAG:
580+
return &PyFunction_Type;
547581
}
548582
Py_UNREACHABLE();
549583
}
@@ -571,6 +605,8 @@ _Py_uop_sym_get_type_version(JitOptRef ref)
571605
return PyBool_Type.tp_version_tag;
572606
case JIT_SYM_COMPACT_INT:
573607
return PyLong_Type.tp_version_tag;
608+
case JIT_SYM_FUNCTION_TAG:
609+
return PyFunction_Type.tp_version_tag;
574610
}
575611
Py_UNREACHABLE();
576612
}
@@ -606,6 +642,8 @@ _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptRef ref)
606642
case JIT_SYM_UNKNOWN_TAG:
607643
case JIT_SYM_COMPACT_INT:
608644
return -1;
645+
case JIT_SYM_FUNCTION_TAG:
646+
return 1;
609647
case JIT_SYM_KNOWN_CLASS_TAG:
610648
/* TODO :
611649
* Instances of some classes are always
@@ -761,6 +799,7 @@ _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef ref)
761799
return;
762800
case JIT_SYM_TUPLE_TAG:
763801
case JIT_SYM_TRUTHINESS_TAG:
802+
case JIT_SYM_FUNCTION_TAG:
764803
sym_set_bottom(ctx, sym);
765804
return;
766805
case JIT_SYM_BOTTOM_TAG:
@@ -773,6 +812,72 @@ _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef ref)
773812
}
774813
}
775814

815+
void
816+
_Py_uop_sym_set_function_version(JitOptContext *ctx, JitOptRef ref, uint32_t version)
817+
{
818+
JitOptSymbol *sym = PyJitRef_Unwrap(ref);
819+
JitSymType tag = sym->tag;
820+
switch(tag) {
821+
case JIT_SYM_TUPLE_TAG:
822+
case JIT_SYM_TRUTHINESS_TAG:
823+
case JIT_SYM_BOTTOM_TAG:
824+
case JIT_SYM_COMPACT_INT:
825+
case JIT_SYM_NULL_TAG:
826+
sym_set_bottom(ctx, sym);
827+
return;
828+
case JIT_SYM_KNOWN_CLASS_TAG:
829+
if (sym->cls.type == &PyFunction_Type) {
830+
sym->tag = JIT_SYM_FUNCTION_TAG;
831+
sym->function.function = NULL;
832+
sym->function.version = version;
833+
} else {
834+
sym_set_bottom(ctx, sym);
835+
}
836+
return;
837+
case JIT_SYM_TYPE_VERSION_TAG:
838+
if (sym->version.version == PyLong_Type.tp_version_tag) {
839+
sym->tag = JIT_SYM_COMPACT_INT;
840+
}
841+
else {
842+
sym_set_bottom(ctx, sym);
843+
}
844+
return;
845+
case JIT_SYM_KNOWN_VALUE_TAG:
846+
if (PyFunction_Check(sym->value.value)) {
847+
sym->tag = JIT_SYM_FUNCTION_TAG;
848+
sym->function.function = sym->value.value;
849+
sym->function.version = version;
850+
}
851+
else {
852+
Py_CLEAR(sym->value.value);
853+
sym_set_bottom(ctx, sym);
854+
}
855+
return;
856+
case JIT_SYM_NON_NULL_TAG:
857+
case JIT_SYM_UNKNOWN_TAG:
858+
sym->tag = JIT_SYM_FUNCTION_TAG;
859+
sym->function.function = NULL;
860+
sym->function.version = version;
861+
return;
862+
case JIT_SYM_FUNCTION_TAG:
863+
if (sym->function.version != version) {
864+
Py_CLEAR(sym->function.function);
865+
sym_set_bottom(ctx, sym);
866+
}
867+
return;
868+
}
869+
}
870+
871+
uint32_t
872+
_Py_uop_sym_get_function_version(JitOptRef ref)
873+
{
874+
JitOptSymbol *sym = PyJitRef_Unwrap(ref);
875+
if (sym->tag == JIT_SYM_FUNCTION_TAG) {
876+
return sym->function.function;
877+
}
878+
return 0;
879+
}
880+
776881
JitOptRef
777882
_Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptRef ref, bool truthy)
778883
{
@@ -827,6 +932,9 @@ _Py_uop_frame_new(
827932
frame->locals = ctx->n_consumed;
828933
frame->stack = frame->locals + co->co_nlocalsplus;
829934
frame->stack_pointer = frame->stack + curr_stackentries;
935+
frame->function_checked = false;
936+
frame->builtins_watched = false;
937+
frame->globals_watched = false;
830938
ctx->n_consumed = ctx->n_consumed + (co->co_nlocalsplus + co->co_stacksize);
831939
if (ctx->n_consumed >= ctx->limit) {
832940
ctx->done = true;
@@ -860,13 +968,17 @@ _Py_uop_abstractcontext_fini(JitOptContext *ctx)
860968
if (ctx == NULL) {
861969
return;
862970
}
971+
ctx->prechecked_function_version = 0;
863972
ctx->curr_frame_depth = 0;
864973
int tys = ctx->t_arena.ty_curr_number;
865974
for (int i = 0; i < tys; i++) {
866975
JitOptSymbol *sym = &ctx->t_arena.arena[i];
867976
if (sym->tag == JIT_SYM_KNOWN_VALUE_TAG) {
868977
Py_CLEAR(sym->value.value);
869978
}
979+
if (sym->tag == JIT_SYM_FUNCTION_TAG) {
980+
Py_CLEAR(sym->function.function);
981+
}
870982
}
871983
}
872984

0 commit comments

Comments
 (0)