@@ -152,6 +152,16 @@ incorrect_keys(PyObject *obj, uint32_t version)
152152 (INST)->oparg = ARG; \
153153 (INST)->operand0 = OPERAND;
154154
155+ #define ADD_OP (OP , ARG , OPERAND ) ( \
156+ ctx->out_buffer[ctx->out_len].opcode = (OP), \
157+ ctx->out_buffer[ctx->out_len].format = this_instr->format, \
158+ ctx->out_buffer[ctx->out_len].oparg = (ARG), \
159+ ctx->out_buffer[ctx->out_len].target = this_instr->target, \
160+ ctx->out_buffer[ctx->out_len].operand0 = (OPERAND), \
161+ ctx->out_buffer[ctx->out_len].operand1 = this_instr->operand1, \
162+ ctx->out_len++ \
163+ )
164+
155165/* Shortened forms for convenience, used in optimizer_bytecodes.c */
156166#define sym_is_not_null _Py_uop_sym_is_not_null
157167#define sym_is_const _Py_uop_sym_is_const
@@ -219,7 +229,7 @@ optimize_to_bool(
219229 bool insert_mode )
220230{
221231 if (sym_matches_type (value , & PyBool_Type )) {
222- REPLACE_OP ( this_instr , _NOP , 0 , 0 );
232+ ADD_OP ( _NOP , 0 , 0 );
223233 * result_ptr = value ;
224234 return 1 ;
225235 }
@@ -229,17 +239,17 @@ optimize_to_bool(
229239 int opcode = insert_mode ?
230240 _INSERT_1_LOAD_CONST_INLINE_BORROW :
231241 _POP_TOP_LOAD_CONST_INLINE_BORROW ;
232- REPLACE_OP ( this_instr , opcode , 0 , (uintptr_t )load );
242+ ADD_OP ( opcode , 0 , (uintptr_t )load );
233243 * result_ptr = sym_new_const (ctx , load );
234244 return 1 ;
235245 }
236246 return 0 ;
237247}
238248
239249static void
240- eliminate_pop_guard (_PyUOpInstruction * this_instr , bool exit )
250+ eliminate_pop_guard (_PyUOpInstruction * this_instr , JitOptContext * ctx , bool exit )
241251{
242- REPLACE_OP ( this_instr , _POP_TOP , 0 , 0 );
252+ ADD_OP ( _POP_TOP , 0 , 0 );
243253 if (exit ) {
244254 REPLACE_OP ((this_instr + 1 ), _EXIT_TRACE , 0 , 0 );
245255 this_instr [1 ].target = this_instr -> target ;
@@ -256,7 +266,7 @@ lookup_attr(JitOptContext *ctx, _PyBloomFilter *dependencies, _PyUOpInstruction
256266 PyObject * lookup = _PyType_Lookup (type , name );
257267 if (lookup ) {
258268 int opcode = _Py_IsImmortal (lookup ) ? immortal : mortal ;
259- REPLACE_OP ( this_instr , opcode , 0 , (uintptr_t )lookup );
269+ ADD_OP ( opcode , 0 , (uintptr_t )lookup );
260270 PyType_Watch (TYPE_WATCHER_ID , (PyObject * )type );
261271 _Py_BloomFilter_Add (dependencies , type );
262272 return sym_new_const (ctx , lookup );
@@ -364,6 +374,7 @@ optimize_uops(
364374 frame -> func = func ;
365375 ctx -> curr_frame_depth ++ ;
366376 ctx -> frame = frame ;
377+ ctx -> out_len = 0 ;
367378
368379 _PyUOpInstruction * this_instr = NULL ;
369380 JitOptRef * stack_pointer = ctx -> frame -> stack_pointer ;
@@ -387,6 +398,7 @@ optimize_uops(
387398 }
388399#endif
389400
401+ int out_len_before = ctx -> out_len ;
390402 switch (opcode ) {
391403
392404#include "optimizer_cases.c.h"
@@ -395,6 +407,10 @@ optimize_uops(
395407 DPRINTF (1 , "\nUnknown opcode in abstract interpreter\n" );
396408 Py_UNREACHABLE ();
397409 }
410+ // If no ADD_OP was called during this iteration, copy the original instruction
411+ if (ctx -> out_len == out_len_before ) {
412+ ctx -> out_buffer [ctx -> out_len ++ ] = * this_instr ;
413+ }
398414 assert (ctx -> frame != NULL );
399415 if (!CURRENT_FRAME_IS_INIT_SHIM ()) {
400416 DPRINTF (3 , " stack_level %d\n" , STACK_LEVEL ());
@@ -423,7 +439,18 @@ optimize_uops(
423439 /* Either reached the end or cannot optimize further, but there
424440 * would be no benefit in retrying later */
425441 _Py_uop_abstractcontext_fini (ctx );
426- return trace_len ;
442+ // Check that the trace ends with a proper terminator
443+ if (ctx -> out_len > 0 ) {
444+ int last_opcode = ctx -> out_buffer [ctx -> out_len - 1 ].opcode ;
445+ if (last_opcode != _EXIT_TRACE &&
446+ last_opcode != _JUMP_TO_TOP &&
447+ last_opcode != _DYNAMIC_EXIT &&
448+ last_opcode != _DEOPT ) {
449+ return 0 ;
450+ }
451+ }
452+
453+ return ctx -> out_len ;
427454
428455error :
429456 DPRINTF (3 , "\n" );
@@ -584,6 +611,7 @@ _Py_uop_analyze_and_optimize(
584611)
585612{
586613 OPT_STAT_INC (optimizer_attempts );
614+ JitOptContext * ctx = & tstate -> jit_tracer_state -> opt_context ;
587615
588616 length = optimize_uops (
589617 tstate , buffer ,
@@ -595,7 +623,7 @@ _Py_uop_analyze_and_optimize(
595623
596624 assert (length > 0 );
597625
598- length = remove_unneeded_uops (buffer , length );
626+ length = remove_unneeded_uops (ctx -> out_buffer , length );
599627 assert (length > 0 );
600628
601629 OPT_STAT_INC (optimizer_successes );
0 commit comments