@@ -362,6 +362,30 @@ eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit)
362
362
}
363
363
}
364
364
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
+
365
389
/* 1 for success, 0 for not ready, cannot error at the moment. */
366
390
static int
367
391
optimize_uops (
@@ -376,6 +400,10 @@ optimize_uops(
376
400
_Py_UOpsContext context ;
377
401
_Py_UOpsContext * ctx = & context ;
378
402
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 ;
379
407
380
408
if (_Py_uop_abstractcontext_init (ctx ) < 0 ) {
381
409
goto out_of_space ;
@@ -416,8 +444,7 @@ optimize_uops(
416
444
ctx -> frame -> stack_pointer = stack_pointer ;
417
445
assert (STACK_LEVEL () >= 0 );
418
446
}
419
- _Py_uop_abstractcontext_fini (ctx );
420
- return trace_len ;
447
+ Py_UNREACHABLE ();
421
448
422
449
out_of_space :
423
450
DPRINTF (3 , "\n" );
@@ -443,9 +470,17 @@ optimize_uops(
443
470
_Py_uop_abstractcontext_fini (ctx );
444
471
return 0 ;
445
472
done :
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 */
448
475
_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
+ }
449
484
return trace_len ;
450
485
}
451
486
@@ -532,124 +567,6 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size)
532
567
Py_UNREACHABLE ();
533
568
}
534
569
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
-
653
570
// 0 - failure, no error raised, just fall back to Tier 1
654
571
// -1 - failure, and raise error
655
572
// > 0 - length of optimized trace
@@ -669,8 +586,6 @@ _Py_uop_analyze_and_optimize(
669
586
return err ;
670
587
}
671
588
672
- peephole_opt (frame , buffer , length );
673
-
674
589
length = optimize_uops (
675
590
_PyFrame_GetCode (frame ), buffer ,
676
591
length , curr_stacklen , dependencies );
0 commit comments