@@ -499,31 +499,178 @@ static void zend_extension_op_array_handler(zend_extension *extension, zend_op_a
499
499
}
500
500
}
501
501
502
- static void zend_check_finally_breakout (zend_op_array * op_array , zend_op * opline , zend_uint dst_num TSRMLS_DC ) {
503
- zend_uint i , op_num = opline - op_array -> opcodes ;
504
- for (i = 0 ; i < op_array -> last_try_catch ; i ++ ) {
502
+ static void zend_check_finally_breakout (zend_op_array * op_array , zend_uint op_num , zend_uint dst_num TSRMLS_DC )
503
+ {
504
+ zend_uint i ;
505
+
506
+ for (i = 0 ; i < op_array -> last_try_catch ; i ++ ) {
505
507
if (op_array -> try_catch_array [i ].try_op > op_num ) {
506
508
break ;
507
509
}
508
510
if ((op_num >= op_array -> try_catch_array [i ].finally_op
509
- && op_num < op_array -> try_catch_array [i ].finally_end )
510
- && (dst_num >= op_array -> try_catch_array [i ].finally_end
511
+ && op_num <= op_array -> try_catch_array [i ].finally_end )
512
+ && (dst_num > op_array -> try_catch_array [i ].finally_end
511
513
|| dst_num < op_array -> try_catch_array [i ].finally_op )) {
512
514
CG (in_compilation ) = 1 ;
513
515
CG (active_op_array ) = op_array ;
514
- CG (zend_lineno ) = opline -> lineno ;
516
+ CG (zend_lineno ) = op_array -> opcodes [ op_num ]. lineno ;
515
517
zend_error (E_COMPILE_ERROR , "jump out of a finally block is disallowed" );
516
518
}
517
519
}
518
520
}
519
521
522
+ static void zend_resolve_finally_call (zend_op_array * op_array , zend_uint op_num , zend_uint dst_num TSRMLS_DC )
523
+ {
524
+ zend_uint start_op ;
525
+ zend_op * opline ;
526
+ zend_uint i = op_array -> last_try_catch ;
527
+
528
+ if (dst_num != (zend_uint )- 1 ) {
529
+ zend_check_finally_breakout (op_array , op_num , dst_num TSRMLS_CC );
530
+ }
531
+
532
+ /* the backward order is mater */
533
+ while (i > 0 ) {
534
+ i -- ;
535
+ if (op_array -> try_catch_array [i ].finally_op &&
536
+ op_num >= op_array -> try_catch_array [i ].try_op &&
537
+ op_num < op_array -> try_catch_array [i ].finally_op - 1 &&
538
+ (dst_num < op_array -> try_catch_array [i ].try_op ||
539
+ dst_num > op_array -> try_catch_array [i ].finally_end )) {
540
+ /* we have a jump out of try block that needs executing finally */
541
+
542
+ /* generate a FAST_CALL to finaly block */
543
+ start_op = get_next_op_number (op_array );
544
+ opline = get_next_op (op_array TSRMLS_CC );
545
+ opline -> opcode = ZEND_FAST_CALL ;
546
+ SET_UNUSED (opline -> op1 );
547
+ SET_UNUSED (opline -> op2 );
548
+ opline -> op1 .opline_num = op_array -> try_catch_array [i ].finally_op ;
549
+ if (op_array -> try_catch_array [i ].catch_op ) {
550
+ opline -> extended_value = 1 ;
551
+ opline -> op2 .opline_num = op_array -> try_catch_array [i ].catch_op ;
552
+ }
553
+
554
+ /* generate a sequence of FAST_CALL to upward finaly block */
555
+ while (i > 0 ) {
556
+ i -- ;
557
+ if (op_array -> try_catch_array [i ].finally_op &&
558
+ op_num >= op_array -> try_catch_array [i ].try_op &&
559
+ op_num < op_array -> try_catch_array [i ].finally_op - 1 &&
560
+ (dst_num < op_array -> try_catch_array [i ].try_op ||
561
+ dst_num > op_array -> try_catch_array [i ].finally_end )) {
562
+
563
+ opline = get_next_op (op_array TSRMLS_CC );
564
+ opline -> opcode = ZEND_FAST_CALL ;
565
+ SET_UNUSED (opline -> op1 );
566
+ SET_UNUSED (opline -> op2 );
567
+ opline -> op1 .opline_num = op_array -> try_catch_array [i ].finally_op ;
568
+ }
569
+ }
570
+
571
+ /* Finish the sequence with original opcode */
572
+ opline = get_next_op (op_array TSRMLS_CC );
573
+ * opline = op_array -> opcodes [op_num ];
574
+
575
+ /* Replace original opcode with jump to this sequence */
576
+ opline = op_array -> opcodes + op_num ;
577
+ opline -> opcode = ZEND_JMP ;
578
+ SET_UNUSED (opline -> op1 );
579
+ SET_UNUSED (opline -> op2 );
580
+ opline -> op1 .opline_num = start_op ;
581
+
582
+ break ;
583
+ }
584
+ }
585
+ }
586
+
587
+ static void zend_resolve_finally_ret (zend_op_array * op_array , zend_uint op_num TSRMLS_DC )
588
+ {
589
+ int i ;
590
+ zend_uint catch_op_num = 0 , finally_op_num = 0 ;
591
+
592
+ for (i = 0 ; i < op_array -> last_try_catch ; i ++ ) {
593
+ if (op_array -> try_catch_array [i ].try_op > op_num ) {
594
+ break ;
595
+ }
596
+ if (op_num < op_array -> try_catch_array [i ].finally_op ) {
597
+ finally_op_num = op_array -> try_catch_array [i ].finally_op ;
598
+ }
599
+ if (op_num < op_array -> try_catch_array [i ].catch_op ) {
600
+ catch_op_num = op_array -> try_catch_array [i ].catch_op ;
601
+ }
602
+ }
603
+
604
+ if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num )) {
605
+ /* in case of unhandled exception return to upward finally block */
606
+ op_array -> opcodes [op_num ].extended_value = ZEND_FAST_RET_TO_FINALLY ;
607
+ op_array -> opcodes [op_num ].op2 .opline_num = finally_op_num ;
608
+ } else if (catch_op_num ) {
609
+ /* in case of unhandled exception return to upward catch block */
610
+ op_array -> opcodes [op_num ].extended_value = ZEND_FAST_RET_TO_CATCH ;
611
+ op_array -> opcodes [op_num ].op2 .opline_num = catch_op_num ;
612
+ }
613
+ }
614
+
615
+ static void zend_resolve_finally_calls (zend_op_array * op_array TSRMLS_DC )
616
+ {
617
+ zend_uint i ;
618
+ zend_op * opline ;
619
+
620
+ for (i = 0 ; i < op_array -> last ; i ++ ) {
621
+ opline = op_array -> opcodes + i ;
622
+ switch (opline -> opcode ) {
623
+ case ZEND_RETURN :
624
+ case ZEND_RETURN_BY_REF :
625
+ zend_resolve_finally_call (op_array , i , (zend_uint )- 1 TSRMLS_CC );
626
+ break ;
627
+ case ZEND_BRK :
628
+ case ZEND_CONT :
629
+ {
630
+ int nest_levels , array_offset ;
631
+ zend_brk_cont_element * jmp_to ;
632
+
633
+ nest_levels = Z_LVAL (op_array -> literals [opline -> op2 .constant ].constant );
634
+ array_offset = opline -> op1 .opline_num ;
635
+ do {
636
+ jmp_to = & op_array -> brk_cont_array [array_offset ];
637
+ if (nest_levels > 1 ) {
638
+ array_offset = jmp_to -> parent ;
639
+ }
640
+ } while (-- nest_levels > 0 );
641
+ zend_resolve_finally_call (op_array , i , opline -> opcode == ZEND_BRK ? jmp_to -> brk : jmp_to -> cont TSRMLS_CC );
642
+ break ;
643
+ }
644
+ case ZEND_GOTO :
645
+ if (Z_TYPE (op_array -> literals [opline -> op2 .constant ].constant ) != IS_LONG ) {
646
+ zend_uint num = opline -> op2 .constant ;
647
+ opline -> op2 .zv = & op_array -> literals [opline -> op2 .constant ].constant ;
648
+ zend_resolve_goto_label (op_array , opline , 1 TSRMLS_CC );
649
+ opline -> op2 .constant = num ;
650
+ }
651
+ /* break omitted intentionally */
652
+ case ZEND_JMP :
653
+ zend_resolve_finally_call (op_array , i , opline -> op1 .opline_num TSRMLS_CC );
654
+ break ;
655
+ case ZEND_FAST_RET :
656
+ zend_resolve_finally_ret (op_array , i TSRMLS_CC );
657
+ break ;
658
+ default :
659
+ break ;
660
+ }
661
+ }
662
+ }
663
+
520
664
ZEND_API int pass_two (zend_op_array * op_array TSRMLS_DC )
521
665
{
522
666
zend_op * opline , * end ;
523
667
524
668
if (op_array -> type != ZEND_USER_FUNCTION && op_array -> type != ZEND_EVAL_CODE ) {
525
669
return 0 ;
526
670
}
671
+ if (op_array -> has_finally_block ) {
672
+ zend_resolve_finally_calls (op_array TSRMLS_CC );
673
+ }
527
674
if (CG (compiler_options ) & ZEND_COMPILE_EXTENDED_INFO ) {
528
675
zend_update_extended_info (op_array TSRMLS_CC );
529
676
}
@@ -560,30 +707,9 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
560
707
}
561
708
/* break omitted intentionally */
562
709
case ZEND_JMP :
563
- if (op_array -> last_try_catch ) {
564
- zend_check_finally_breakout (op_array , opline , opline -> op1 .opline_num TSRMLS_CC );
565
- }
710
+ case ZEND_FAST_CALL :
566
711
opline -> op1 .jmp_addr = & op_array -> opcodes [opline -> op1 .opline_num ];
567
712
break ;
568
- case ZEND_BRK :
569
- case ZEND_CONT :
570
- if (op_array -> last_try_catch ) {
571
- int nest_levels , array_offset ;
572
- zend_brk_cont_element * jmp_to ;
573
-
574
- nest_levels = Z_LVAL_P (opline -> op2 .zv );
575
- array_offset = opline -> op1 .opline_num ;
576
- do {
577
- jmp_to = & op_array -> brk_cont_array [array_offset ];
578
- if (nest_levels > 1 ) {
579
- array_offset = jmp_to -> parent ;
580
- }
581
- } while (-- nest_levels > 0 );
582
- if (op_array -> last_try_catch ) {
583
- zend_check_finally_breakout (op_array , opline , jmp_to -> brk TSRMLS_CC );
584
- }
585
- }
586
- break ;
587
713
case ZEND_JMPZ :
588
714
case ZEND_JMPNZ :
589
715
case ZEND_JMPZ_EX :
0 commit comments