1- #ifdef _Py_TIER2
1+ // #ifdef _Py_TIER2
22
33/*
44 * This file contains the support code for CPython's uops optimizer.
@@ -124,36 +124,122 @@ convert_global_to_const(_PyUOpInstruction *inst, PyObject *obj, bool pop)
124124}
125125
126126static int
127- incorrect_keys (_PyUOpInstruction * inst , PyObject * obj )
127+ incorrect_keys (uint32_t version , PyObject * obj )
128128{
129129 if (!PyDict_CheckExact (obj )) {
130130 return 1 ;
131131 }
132132 PyDictObject * dict = (PyDictObject * )obj ;
133- if (dict -> ma_keys -> dk_version != inst -> operand0 ) {
133+ if (dict -> ma_keys -> dk_version != version ) {
134134 return 1 ;
135135 }
136136 return 0 ;
137137}
138138
139- static int
140- check_next_uop (_PyUOpInstruction * buffer , int size , int pc , uint16_t expected )
139+ int
140+ optimize_guard_globals_version (
141+ _PyUOpInstruction * instr ,
142+ uint32_t version ,
143+ JitOptContext * ctx
144+ )
141145{
142- if (pc + 1 >= size ) {
143- DPRINTF (1 , "Cannot rewrite %s at pc %d: buffer too small\n" ,
144- _PyOpcode_uop_name [buffer [pc ].opcode ], pc );
145- return 0 ;
146+ if (ctx -> frame -> function == NULL ) {
147+ return -1 ;
146148 }
147- uint16_t next_opcode = buffer [pc + 1 ].opcode ;
148- if (next_opcode != expected ) {
149- DPRINTF (1 ,
150- "Cannot rewrite %s at pc %d: unexpected next opcode %s, "
151- "expected %s\n" ,
152- _PyOpcode_uop_name [buffer [pc ].opcode ], pc ,
153- _PyOpcode_uop_name [next_opcode ], _PyOpcode_uop_name [expected ]);
154- return 0 ;
149+ PyDictObject * globals = (PyDictObject * )ctx -> frame -> function -> func_globals ;
150+ if (!PyDict_CheckExact (globals )) {
151+ ctx -> done = true;
152+ return -1 ;
153+ }
154+ if (globals -> ma_keys -> dk_version != version ) {
155+ OPT_STAT_INC (remove_globals_incorrect_keys );
156+ ctx -> done = true;
157+ return -1 ;
158+ }
159+ uint64_t watched_mutations = get_mutations (globals );
160+ if (watched_mutations >= _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS ) {
161+ return -1 ;
162+ }
163+ if (!ctx -> frame -> globals_watched ) {
164+ PyDict_Watch (GLOBALS_WATCHER_ID , (PyObject * )globals );
165+ ctx -> frame -> globals_watched = true;
166+ }
167+ instr -> opcode = _NOP ;
168+ instr -> oparg = 0 ;
169+ return 0 ;
170+ }
171+
172+ JitOptSymbol *
173+ optimize_load_global_module (
174+ _PyUOpInstruction * instr ,
175+ uint32_t version ,
176+ JitOptContext * ctx
177+ )
178+ {
179+ if (ctx -> frame -> function == NULL ) {
180+ goto no_opt ;
155181 }
156- return 1 ;
182+ PyObject * globals = ctx -> frame -> function -> func_globals ;
183+ if (incorrect_keys (version , globals )) {
184+ OPT_STAT_INC (remove_globals_incorrect_keys );
185+ ctx -> done = true;
186+ goto no_opt ;
187+ }
188+ if (get_mutations (globals ) >= _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS ) {
189+ goto no_opt ;
190+ }
191+ if (!ctx -> frame -> globals_watched ) {
192+ PyDict_Watch (GLOBALS_WATCHER_ID , globals );
193+ _Py_BloomFilter_Add (ctx -> dependencies , globals );
194+ ctx -> frame -> globals_watched = true;
195+ }
196+ if (!ctx -> frame -> function_checked && instr [-1 ].opcode == _NOP ) {
197+ instr [-1 ].opcode = _CHECK_FUNCTION ;
198+ instr [-1 ].operand0 = func_version ;
199+ ctx -> frame -> function_checked = true;
200+ }
201+ if (ctx -> frame -> function_checked ) {
202+ PyObject * cnst = convert_global_to_const (instr , globals , false);
203+ if (cnst != NULL ) {
204+ return _Py_uop_sym_new_const (ctx , cnst );
205+ }
206+ }
207+ no_opt :
208+ return _Py_uop_sym_new_not_null (ctx );
209+ }
210+
211+
212+ JitOptSymbol *
213+ optimize_load_global_builtins (
214+ _PyUOpInstruction * instr ,
215+ uint32_t version ,
216+ JitOptContext * ctx
217+ )
218+ {
219+ if (ctx -> frame -> function == NULL ) {
220+ goto no_opt ;
221+ }
222+ PyObject * builtins = ctx -> frame -> function -> func_builtins ;
223+ if (incorrect_keys (version , builtins )) {
224+ OPT_STAT_INC (remove_globals_incorrect_keys );
225+ ctx -> done = true;
226+ goto no_opt ;
227+ }
228+ if (ctx -> interp -> rare_events .builtin_dict >= _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS ) {
229+ goto no_opt ;
230+ }
231+ if (!ctx -> frame -> builtins_watched ) {
232+ PyDict_Watch (BUILTINS_WATCHER_ID , builtins );
233+ ctx -> frame -> builtins_watched = true;
234+ }
235+ if (ctx -> frame -> function_checked ) {
236+ PyObject * cnst = convert_global_to_const (instr , builtins , false);
237+ if (cnst != NULL ) {
238+ return _Py_uop_sym_new_const (ctx , cnst );
239+ }
240+ }
241+ no_opt :
242+ return _Py_uop_sym_new_not_null (ctx );
157243}
158244
159245/* Returns 1 if successfully optimized
@@ -200,7 +286,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
200286 int opcode = inst -> opcode ;
201287 switch (opcode ) {
202288 case _GUARD_GLOBALS_VERSION :
203- if (incorrect_keys (inst , globals )) {
289+ if (incorrect_keys (inst -> operand0 , globals )) {
204290 OPT_STAT_INC (remove_globals_incorrect_keys );
205291 return 0 ;
206292 }
@@ -222,7 +308,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
222308 }
223309 break ;
224310 case _LOAD_GLOBAL_BUILTINS :
225- if (incorrect_keys (inst , builtins )) {
311+ if (incorrect_keys (inst -> operand0 , builtins )) {
226312 OPT_STAT_INC (remove_globals_incorrect_keys );
227313 return 0 ;
228314 }
@@ -238,7 +324,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
238324 }
239325 break ;
240326 case _LOAD_GLOBAL_MODULE :
241- if (incorrect_keys (inst , globals )) {
327+ if (incorrect_keys (inst -> operand0 , globals )) {
242328 OPT_STAT_INC (remove_globals_incorrect_keys );
243329 return 0 ;
244330 }
@@ -350,6 +436,8 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
350436#define sym_get_type _Py_uop_sym_get_type
351437#define sym_matches_type _Py_uop_sym_matches_type
352438#define sym_matches_type_version _Py_uop_sym_matches_type_version
439+ #define sym_get_function_version _Py_uop_sym_get_function_version
440+ #define sym_set_function_version _Py_uop_sym_set_function_version
353441#define sym_set_null (SYM ) _Py_uop_sym_set_null(ctx, SYM)
354442#define sym_set_non_null (SYM ) _Py_uop_sym_set_non_null(ctx, SYM)
355443#define sym_set_type (SYM , TYPE ) _Py_uop_sym_set_type(ctx, SYM, TYPE)
@@ -447,14 +535,16 @@ get_code_with_logging(_PyUOpInstruction *op)
447535/* 1 for success, 0 for not ready, cannot error at the moment. */
448536static int
449537optimize_uops (
450- PyCodeObject * co ,
538+ _PyInterpreterFrame * real_frame ,
451539 _PyUOpInstruction * trace ,
452540 int trace_len ,
453541 int curr_stacklen ,
454542 _PyBloomFilter * dependencies
455543)
456544{
457-
545+ PyFunctionObject * func = (PyFunctionObject * )PyStackRef_AsPyObjectBorrow (real_frame -> f_funcobj );
546+ PyCodeObject * co = _PyFrame_GetCode (real_frame );
547+ assert (PyFunction_Check (func ));
458548 JitOptContext context ;
459549 JitOptContext * ctx = & context ;
460550 uint32_t opcode = UINT16_MAX ;
@@ -468,11 +558,14 @@ optimize_uops(
468558 if (frame == NULL ) {
469559 return -1 ;
470560 }
561+ frame -> function = (PyFunctionObject * )func ;
471562 ctx -> curr_frame_depth ++ ;
472563 ctx -> frame = frame ;
473564 ctx -> done = false;
474565 ctx -> out_of_space = false;
475566 ctx -> contradiction = false;
567+ ctx -> dependencies = dependencies ;
568+ ctx -> interp = _PyInterpreterState_GET ();
476569
477570 _PyUOpInstruction * this_instr = NULL ;
478571 for (int i = 0 ; !ctx -> done ; i ++ ) {
@@ -649,7 +742,7 @@ _Py_uop_analyze_and_optimize(
649742 }
650743
651744 length = optimize_uops (
652- _PyFrame_GetCode ( frame ) , buffer ,
745+ frame , buffer ,
653746 length , curr_stacklen , dependencies );
654747
655748 if (length <= 0 ) {
0 commit comments