56
56
57
57
typedef struct _zend_loop_var {
58
58
zend_uchar opcode ;
59
- uint32_t try_catch_offset ;
60
- uint32_t brk_cont_offset ;
61
- znode var ;
59
+ zend_uchar var_type ;
60
+ uint32_t var_num ;
61
+ union {
62
+ uint32_t try_catch_offset ;
63
+ uint32_t brk_cont_offset ;
64
+ } u ;
62
65
} zend_loop_var ;
63
66
64
67
static inline void zend_alloc_cache_slot (uint32_t literal ) {
@@ -565,7 +568,7 @@ void zend_stop_lexing(void)
565
568
LANG_SCNG (yy_cursor ) = LANG_SCNG (yy_limit );
566
569
}
567
570
568
- static inline void zend_begin_loop (const znode * loop_var ) /* {{{ */
571
+ static inline void zend_begin_loop (zend_uchar free_opcode , const znode * loop_var ) /* {{{ */
569
572
{
570
573
zend_brk_cont_element * brk_cont_element ;
571
574
int parent = CG (context ).current_brk_cont ;
@@ -576,9 +579,10 @@ static inline void zend_begin_loop(const znode *loop_var) /* {{{ */
576
579
brk_cont_element -> parent = parent ;
577
580
578
581
if (loop_var && (loop_var -> op_type & (IS_VAR |IS_TMP_VAR ))) {
579
- info .opcode = loop_var -> flag ? ZEND_FE_FREE : ZEND_FREE ;
580
- info .var = * loop_var ;
581
- info .brk_cont_offset = CG (context ).current_brk_cont ;
582
+ info .opcode = free_opcode ;
583
+ info .var_type = loop_var -> op_type ;
584
+ info .var_num = loop_var -> u .op .var ;
585
+ info .u .brk_cont_offset = CG (context ).current_brk_cont ;
582
586
brk_cont_element -> start = get_next_op_number (CG (active_op_array ));
583
587
} else {
584
588
info .opcode = ZEND_NOP ;
@@ -888,49 +892,6 @@ static void str_dtor(zval *zv) /* {{{ */ {
888
892
889
893
static zend_bool zend_is_call (zend_ast * ast );
890
894
891
- static zend_loop_var * generate_fast_calls (zend_loop_var * var ) /* {{{ */
892
- {
893
- zend_loop_var * base = zend_stack_base (& CG (loop_var_stack ));
894
- for (; var >= base && var -> opcode == ZEND_FAST_CALL ; var -- ) {
895
- zend_op * opline = get_next_op (CG (active_op_array ));
896
- opline -> opcode = ZEND_FAST_CALL ;
897
- SET_NODE (opline -> result , & var -> var );
898
- SET_UNUSED (opline -> op1 );
899
- SET_UNUSED (opline -> op2 );
900
- opline -> op1 .num = var -> try_catch_offset ;
901
- opline -> extended_value = ZEND_FAST_CALL_UNBOUND ;
902
- }
903
- return var ;
904
- }
905
- /* }}} */
906
-
907
- static zend_loop_var * generate_free_loop_var (zend_loop_var * info ) /* {{{ */
908
- {
909
- zend_op * opline ;
910
- zend_loop_var * base = zend_stack_base (& CG (loop_var_stack ));
911
- ZEND_ASSERT (info -> opcode != ZEND_FAST_CALL );
912
-
913
- if (info < base || info -> opcode == ZEND_RETURN ) {
914
- /* Stack separator */
915
- return NULL ;
916
- }
917
-
918
- if (info -> opcode == ZEND_NOP ) {
919
- /* Loop doesn't have freeable variable */
920
- return info - 1 ;
921
- }
922
-
923
- ZEND_ASSERT (info -> var .op_type == IS_VAR || info -> var .op_type == IS_TMP_VAR );
924
- opline = get_next_op (CG (active_op_array ));
925
- opline -> opcode = info -> opcode ;
926
- SET_NODE (opline -> op1 , & info -> var );
927
- SET_UNUSED (opline -> op2 );
928
- opline -> op2 .num = info -> brk_cont_offset ;
929
- opline -> extended_value = ZEND_FREE_ON_RETURN ;
930
- return info - 1 ;
931
- }
932
- /* }}} */
933
-
934
895
static uint32_t zend_add_try_element (uint32_t try_op ) /* {{{ */
935
896
{
936
897
zend_op_array * op_array = CG (active_op_array );
@@ -3497,13 +3458,55 @@ void zend_compile_unset(zend_ast *ast) /* {{{ */
3497
3458
}
3498
3459
/* }}} */
3499
3460
3500
- static void zend_handle_loops_and_finally ( ) /* {{{ */
3461
+ static int zend_handle_loops_and_finally_ex ( zend_long depth ) /* {{{ */
3501
3462
{
3463
+ zend_loop_var * base ;
3502
3464
zend_loop_var * loop_var = zend_stack_top (& CG (loop_var_stack ));
3503
- while ( loop_var ) {
3504
- loop_var = generate_fast_calls ( loop_var );
3505
- loop_var = generate_free_loop_var ( loop_var ) ;
3465
+
3466
+ if (! loop_var ) {
3467
+ return 1 ;
3506
3468
}
3469
+ base = zend_stack_base (& CG (loop_var_stack ));
3470
+ for (; loop_var >= base ; loop_var -- ) {
3471
+ if (loop_var -> opcode == ZEND_FAST_CALL ) {
3472
+ zend_op * opline = get_next_op (CG (active_op_array ));
3473
+
3474
+ opline -> opcode = ZEND_FAST_CALL ;
3475
+ opline -> result_type = IS_TMP_VAR ;
3476
+ opline -> result .var = loop_var -> var_num ;
3477
+ SET_UNUSED (opline -> op1 );
3478
+ SET_UNUSED (opline -> op2 );
3479
+ opline -> op1 .num = loop_var -> u .try_catch_offset ;
3480
+ opline -> extended_value = ZEND_FAST_CALL_UNBOUND ;
3481
+ } else if (loop_var -> opcode == ZEND_RETURN ) {
3482
+ /* Stack separator */
3483
+ break ;
3484
+ } else if (depth <= 1 ) {
3485
+ return 1 ;
3486
+ } else if (loop_var -> opcode == ZEND_NOP ) {
3487
+ /* Loop doesn't have freeable variable */
3488
+ depth -- ;
3489
+ } else {
3490
+ zend_op * opline ;
3491
+
3492
+ ZEND_ASSERT (loop_var -> var_type == IS_VAR || loop_var -> var_type == IS_TMP_VAR );
3493
+ opline = get_next_op (CG (active_op_array ));
3494
+ opline -> opcode = loop_var -> opcode ;
3495
+ opline -> op1_type = loop_var -> var_type ;
3496
+ opline -> op1 .var = loop_var -> var_num ;
3497
+ SET_UNUSED (opline -> op2 );
3498
+ opline -> op2 .num = loop_var -> u .brk_cont_offset ;
3499
+ opline -> extended_value = ZEND_FREE_ON_RETURN ;
3500
+ depth -- ;
3501
+ }
3502
+ }
3503
+ return (depth == 0 );
3504
+ }
3505
+ /* }}} */
3506
+
3507
+ static int zend_handle_loops_and_finally (void ) /* {{{ */
3508
+ {
3509
+ zend_handle_loops_and_finally_ex (zend_stack_count (& CG (loop_var_stack )) + 1 );
3507
3510
}
3508
3511
/* }}} */
3509
3512
@@ -3602,32 +3605,19 @@ void zend_compile_break_continue(zend_ast *ast) /* {{{ */
3602
3605
zend_error_noreturn (E_COMPILE_ERROR , "'%s' not in the 'loop' or 'switch' context" ,
3603
3606
ast -> kind == ZEND_AST_BREAK ? "break" : "continue" );
3604
3607
} else {
3605
- int array_offset = CG (context ).current_brk_cont ;
3606
- zend_long nest_level = depth ;
3607
- zend_loop_var * loop_var = zend_stack_top (& CG (loop_var_stack ));
3608
-
3609
- do {
3610
- if (array_offset == -1 ) {
3611
- zend_error_noreturn (E_COMPILE_ERROR , "Cannot '%s' %d level%s" ,
3612
- ast -> kind == ZEND_AST_BREAK ? "break" : "continue" ,
3613
- depth , depth == 1 ? "" : "s" );
3614
- }
3615
-
3616
- loop_var = generate_fast_calls (loop_var );
3617
- if (nest_level > 1 ) {
3618
- loop_var = generate_free_loop_var (loop_var );
3619
- }
3620
-
3621
- array_offset = CG (active_op_array )-> brk_cont_array [array_offset ].parent ;
3622
- } while (-- nest_level > 0 );
3608
+ if (!zend_handle_loops_and_finally_ex (depth )) {
3609
+ zend_error_noreturn (E_COMPILE_ERROR , "Cannot '%s' %d level%s" ,
3610
+ ast -> kind == ZEND_AST_BREAK ? "break" : "continue" ,
3611
+ depth , depth == 1 ? "" : "s" );
3612
+ }
3623
3613
}
3624
3614
opline = zend_emit_op (NULL , ast -> kind == ZEND_AST_BREAK ? ZEND_BRK : ZEND_CONT , NULL , NULL );
3625
3615
opline -> op1 .num = CG (context ).current_brk_cont ;
3626
3616
opline -> op2 .num = depth ;
3627
3617
}
3628
3618
/* }}} */
3629
3619
3630
- zend_op * zend_resolve_goto_label (zend_op_array * op_array , zend_op * opline ) /* {{{ */
3620
+ void zend_resolve_goto_label (zend_op_array * op_array , zend_op * opline ) /* {{{ */
3631
3621
{
3632
3622
zend_label * dest ;
3633
3623
int current , remove_oplines = opline -> op1 .num ;
@@ -3672,20 +3662,19 @@ zend_op *zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline) /* {{
3672
3662
}
3673
3663
}
3674
3664
3675
- ZEND_ASSERT (remove_oplines >= 0 );
3676
- while (remove_oplines -- ) {
3677
- MAKE_NOP (opline );
3678
- opline -- ;
3679
- }
3680
-
3681
3665
opline -> opcode = ZEND_JMP ;
3682
3666
opline -> op1 .opline_num = dest -> opline_num ;
3683
3667
opline -> extended_value = 0 ;
3684
3668
SET_UNUSED (opline -> op1 );
3685
3669
SET_UNUSED (opline -> op2 );
3686
3670
SET_UNUSED (opline -> result );
3687
3671
3688
- return opline ;
3672
+ ZEND_ASSERT (remove_oplines >= 0 );
3673
+ while (remove_oplines -- ) {
3674
+ opline -- ;
3675
+ MAKE_NOP (opline );
3676
+ ZEND_VM_SET_OPCODE_HANDLER (opline );
3677
+ }
3689
3678
}
3690
3679
/* }}} */
3691
3680
@@ -3734,7 +3723,7 @@ void zend_compile_while(zend_ast *ast) /* {{{ */
3734
3723
3735
3724
opnum_jmp = zend_emit_jump (0 );
3736
3725
3737
- zend_begin_loop (NULL );
3726
+ zend_begin_loop (ZEND_NOP , NULL );
3738
3727
3739
3728
opnum_start = get_next_op_number (CG (active_op_array ));
3740
3729
zend_compile_stmt (stmt_ast );
@@ -3757,7 +3746,7 @@ void zend_compile_do_while(zend_ast *ast) /* {{{ */
3757
3746
znode cond_node ;
3758
3747
uint32_t opnum_start , opnum_cond ;
3759
3748
3760
- zend_begin_loop (NULL );
3749
+ zend_begin_loop (ZEND_NOP , NULL );
3761
3750
3762
3751
opnum_start = get_next_op_number (CG (active_op_array ));
3763
3752
zend_compile_stmt (stmt_ast );
@@ -3808,7 +3797,7 @@ void zend_compile_for(zend_ast *ast) /* {{{ */
3808
3797
3809
3798
opnum_jmp = zend_emit_jump (0 );
3810
3799
3811
- zend_begin_loop (NULL );
3800
+ zend_begin_loop (ZEND_NOP , NULL );
3812
3801
3813
3802
opnum_start = get_next_op_number (CG (active_op_array ));
3814
3803
zend_compile_stmt (stmt_ast );
@@ -3890,8 +3879,7 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
3890
3879
zend_emit_assign_znode (key_ast , & key_node );
3891
3880
}
3892
3881
3893
- reset_node .flag = ZEND_FE_FREE ;
3894
- zend_begin_loop (& reset_node );
3882
+ zend_begin_loop (ZEND_FE_FREE , & reset_node );
3895
3883
3896
3884
zend_compile_stmt (stmt_ast );
3897
3885
@@ -3966,8 +3954,7 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */
3966
3954
3967
3955
zend_compile_expr (& expr_node , expr_ast );
3968
3956
3969
- expr_node .flag = 0 ; /* Generate normal FREE */
3970
- zend_begin_loop (& expr_node );
3957
+ zend_begin_loop (ZEND_FREE , & expr_node );
3971
3958
3972
3959
case_node .op_type = IS_TMP_VAR ;
3973
3960
case_node .u .op .var = get_temporary_variable (CG (active_op_array ));
@@ -4075,9 +4062,9 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
4075
4062
4076
4063
/* Push FAST_CALL on unwind stack */
4077
4064
fast_call .opcode = ZEND_FAST_CALL ;
4078
- fast_call .var . op_type = IS_TMP_VAR ;
4079
- fast_call .var . u . op . var = CG (context ).fast_call_var ;
4080
- fast_call .try_catch_offset = try_catch_offset ;
4065
+ fast_call .var_type = IS_TMP_VAR ;
4066
+ fast_call .var_num = CG (context ).fast_call_var ;
4067
+ fast_call .u . try_catch_offset = try_catch_offset ;
4081
4068
zend_stack_push (& CG (loop_var_stack ), & fast_call );
4082
4069
}
4083
4070
0 commit comments