@@ -362,6 +362,30 @@ eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit)
362362 }
363363}
364364
365+ /* _PUSH_FRAME/_POP_FRAME's operand can be 0, a PyFunctionObject *, or a
366+ * PyCodeObject *. Retrieve the code object if possible.
367+ */
368+ static PyCodeObject *
369+ get_code (_PyUOpInstruction * op )
370+ {
371+ assert (op -> opcode == _PUSH_FRAME || op -> opcode == _POP_FRAME );
372+ PyCodeObject * co = NULL ;
373+ uint64_t operand = op -> operand ;
374+ if (operand == 0 ) {
375+ return NULL ;
376+ }
377+ if (operand & 1 ) {
378+ co = (PyCodeObject * )(operand & ~1 );
379+ }
380+ else {
381+ PyFunctionObject * func = (PyFunctionObject * )operand ;
382+ assert (PyFunction_Check (func ));
383+ co = (PyCodeObject * )func -> func_code ;
384+ }
385+ assert (PyCode_Check (co ));
386+ return co ;
387+ }
388+
365389/* 1 for success, 0 for not ready, cannot error at the moment. */
366390static int
367391optimize_uops (
@@ -376,6 +400,10 @@ optimize_uops(
376400 _Py_UOpsContext context ;
377401 _Py_UOpsContext * ctx = & context ;
378402 uint32_t opcode = UINT16_MAX ;
403+ int curr_space = 0 ;
404+ int max_space = 0 ;
405+ _PyUOpInstruction * first_valid_check_stack = NULL ;
406+ _PyUOpInstruction * corresponding_check_stack = NULL ;
379407
380408 if (_Py_uop_abstractcontext_init (ctx ) < 0 ) {
381409 goto out_of_space ;
@@ -416,8 +444,7 @@ optimize_uops(
416444 ctx -> frame -> stack_pointer = stack_pointer ;
417445 assert (STACK_LEVEL () >= 0 );
418446 }
419- _Py_uop_abstractcontext_fini (ctx );
420- return trace_len ;
447+ Py_UNREACHABLE ();
421448
422449out_of_space :
423450 DPRINTF (3 , "\n" );
@@ -443,9 +470,17 @@ optimize_uops(
443470 _Py_uop_abstractcontext_fini (ctx );
444471 return 0 ;
445472done :
446- /* Cannot optimize further, but there would be no benefit
447- * in retrying later */
473+ /* Either reached the end or cannot optimize further, but there
474+ * would be no benefit in retrying later */
448475 _Py_uop_abstractcontext_fini (ctx );
476+ if (first_valid_check_stack != NULL ) {
477+ assert (first_valid_check_stack -> opcode == _CHECK_STACK_SPACE );
478+ assert (max_space > 0 );
479+ assert (max_space <= INT_MAX );
480+ assert (max_space <= INT32_MAX );
481+ first_valid_check_stack -> opcode = _CHECK_STACK_SPACE_OPERAND ;
482+ first_valid_check_stack -> operand = max_space ;
483+ }
449484 return trace_len ;
450485}
451486
@@ -532,124 +567,6 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size)
532567 Py_UNREACHABLE ();
533568}
534569
535- /* _PUSH_FRAME/_POP_FRAME's operand can be 0, a PyFunctionObject *, or a
536- * PyCodeObject *. Retrieve the code object if possible.
537- */
538- static PyCodeObject *
539- get_co (_PyUOpInstruction * op )
540- {
541- assert (op -> opcode == _PUSH_FRAME || op -> opcode == _POP_FRAME );
542- PyCodeObject * co = NULL ;
543- uint64_t operand = op -> operand ;
544- if (operand == 0 ) {
545- return NULL ;
546- }
547- if (operand & 1 ) {
548- co = (PyCodeObject * )(operand & ~1 );
549- }
550- else {
551- PyFunctionObject * func = (PyFunctionObject * )operand ;
552- assert (PyFunction_Check (func ));
553- co = (PyCodeObject * )func -> func_code ;
554- }
555- assert (PyCode_Check (co ));
556- return co ;
557- }
558-
559- static void
560- peephole_opt (_PyInterpreterFrame * frame , _PyUOpInstruction * buffer , int buffer_size )
561- {
562- PyCodeObject * co = _PyFrame_GetCode (frame );
563- int curr_space = 0 ;
564- int max_space = 0 ;
565- _PyUOpInstruction * first_valid_check_stack = NULL ;
566- _PyUOpInstruction * corresponding_check_stack = NULL ;
567- for (int pc = 0 ; pc < buffer_size ; pc ++ ) {
568- int opcode = buffer [pc ].opcode ;
569- switch (opcode ) {
570- case _LOAD_CONST : {
571- assert (co != NULL );
572- PyObject * val = PyTuple_GET_ITEM (co -> co_consts , buffer [pc ].oparg );
573- buffer [pc ].opcode = _Py_IsImmortal (val ) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE ;
574- buffer [pc ].operand = (uintptr_t )val ;
575- break ;
576- }
577- case _CHECK_PEP_523 : {
578- /* Setting the eval frame function invalidates
579- * all executors, so no need to check dynamically */
580- if (_PyInterpreterState_GET ()-> eval_frame == NULL ) {
581- buffer [pc ].opcode = _NOP ;
582- }
583- break ;
584- }
585- case _CHECK_STACK_SPACE : {
586- assert (corresponding_check_stack == NULL );
587- corresponding_check_stack = & buffer [pc ];
588- break ;
589- }
590- case _PUSH_FRAME : {
591- assert (corresponding_check_stack != NULL );
592- co = get_co (& buffer [pc ]);
593- if (co == NULL ) {
594- // should be about to _EXIT_TRACE anyway
595- goto finish ;
596- }
597- int framesize = co -> co_framesize ;
598- assert (framesize > 0 );
599- curr_space += framesize ;
600- if (curr_space < 0 || curr_space > INT32_MAX ) {
601- // won't fit in signed 32-bit int
602- goto finish ;
603- }
604- max_space = curr_space > max_space ? curr_space : max_space ;
605- if (first_valid_check_stack == NULL ) {
606- first_valid_check_stack = corresponding_check_stack ;
607- }
608- else {
609- // delete all but the first valid _CHECK_STACK_SPACE
610- corresponding_check_stack -> opcode = _NOP ;
611- }
612- corresponding_check_stack = NULL ;
613- break ;
614- }
615- case _POP_FRAME : {
616- assert (corresponding_check_stack == NULL );
617- assert (co != NULL );
618- int framesize = co -> co_framesize ;
619- assert (framesize > 0 );
620- assert (framesize <= curr_space );
621- curr_space -= framesize ;
622- co = get_co (& buffer [pc ]);
623- if (co == NULL ) {
624- // might be impossible, but bailing is still safe
625- goto finish ;
626- }
627- break ;
628- }
629- case _JUMP_TO_TOP :
630- case _EXIT_TRACE :
631- goto finish ;
632- #ifdef Py_DEBUG
633- case _CHECK_STACK_SPACE_OPERAND : {
634- /* We should never see _CHECK_STACK_SPACE_OPERANDs.
635- * They are only created at the end of this pass. */
636- Py_UNREACHABLE ();
637- }
638- #endif
639- }
640- }
641- Py_UNREACHABLE ();
642- finish :
643- if (first_valid_check_stack != NULL ) {
644- assert (first_valid_check_stack -> opcode == _CHECK_STACK_SPACE );
645- assert (max_space > 0 );
646- assert (max_space <= INT_MAX );
647- assert (max_space <= INT32_MAX );
648- first_valid_check_stack -> opcode = _CHECK_STACK_SPACE_OPERAND ;
649- first_valid_check_stack -> operand = max_space ;
650- }
651- }
652-
653570// 0 - failure, no error raised, just fall back to Tier 1
654571// -1 - failure, and raise error
655572// > 0 - length of optimized trace
@@ -669,8 +586,6 @@ _Py_uop_analyze_and_optimize(
669586 return err ;
670587 }
671588
672- peephole_opt (frame , buffer , length );
673-
674589 length = optimize_uops (
675590 _PyFrame_GetCode (frame ), buffer ,
676591 length , curr_stacklen , dependencies );
0 commit comments