@@ -60,11 +60,6 @@ typedef struct _zend_loop_var {
60
60
uint32_t try_catch_offset ;
61
61
} zend_loop_var ;
62
62
63
- typedef struct _zend_short_circuiting_chain {
64
- zend_stack jmp_null_opnums ;
65
- uint32_t flags ;
66
- } zend_short_circuiting_chain ;
67
-
68
63
static inline uint32_t zend_alloc_cache_slots (unsigned count ) {
69
64
if (count == 0 ) {
70
65
return (uint32_t ) -1 ;
@@ -373,15 +368,14 @@ void zend_init_compiler_data_structures(void) /* {{{ */
373
368
{
374
369
zend_stack_init (& CG (loop_var_stack ), sizeof (zend_loop_var ));
375
370
zend_stack_init (& CG (delayed_oplines_stack ), sizeof (zend_op ));
376
- zend_stack_init (& CG (short_circuiting_chains ), sizeof (zend_short_circuiting_chain ));
371
+ zend_stack_init (& CG (short_circuiting_opnums ), sizeof (uint32_t ));
377
372
CG (active_class_entry ) = NULL ;
378
373
CG (in_compilation ) = 0 ;
379
374
CG (skip_shebang ) = 0 ;
380
375
381
376
CG (encoding_declared ) = 0 ;
382
377
CG (memoized_exprs ) = NULL ;
383
378
CG (memoize_mode ) = 0 ;
384
- CG (in_short_circuiting_chain ) = 0 ;
385
379
}
386
380
/* }}} */
387
381
@@ -428,7 +422,7 @@ void shutdown_compiler(void) /* {{{ */
428
422
{
429
423
zend_stack_destroy (& CG (loop_var_stack ));
430
424
zend_stack_destroy (& CG (delayed_oplines_stack ));
431
- zend_stack_destroy (& CG (short_circuiting_chains ));
425
+ zend_stack_destroy (& CG (short_circuiting_opnums ));
432
426
zend_hash_destroy (& CG (filenames_table ));
433
427
zend_arena_destroy (CG (arena ));
434
428
@@ -2233,15 +2227,7 @@ static zend_op *zend_delayed_compile_end(uint32_t offset) /* {{{ */
2233
2227
}
2234
2228
/* }}} */
2235
2229
2236
- #define ZEND_WAS_IN_SHORT_CIRCUITING_CHAIN (1 << 0)
2237
- #define ZEND_SHORT_CIRCUITING_CHAIN_WAS_CREATED (1 << 1)
2238
-
2239
- static zend_short_circuiting_chain * zend_current_short_circuiting_chain ()
2240
- {
2241
- return zend_stack_top (& CG (short_circuiting_chains ));
2242
- }
2243
-
2244
- static zend_bool zend_ast_kind_is_short_circuited (uint32_t ast_kind )
2230
+ static zend_bool zend_ast_kind_is_short_circuited (zend_ast_kind ast_kind )
2245
2231
{
2246
2232
switch (ast_kind ) {
2247
2233
case ZEND_AST_DIM :
@@ -2276,67 +2262,56 @@ static zend_bool zend_ast_is_short_circuited(const zend_ast *ast)
2276
2262
return 0 ;
2277
2263
}
2278
2264
2279
- static uint32_t zend_begin_short_circuiting_chain (uint32_t ast_kind , zend_bool force )
2280
- {
2281
- zend_bool was_in_short_circuiting_chain = CG (in_short_circuiting_chain );
2282
- zend_bool ast_kind_is_short_circuited = zend_ast_kind_is_short_circuited (ast_kind );
2283
-
2284
- uint32_t flags = 0 ;
2285
- if (was_in_short_circuiting_chain ) {
2286
- flags |= ZEND_WAS_IN_SHORT_CIRCUITING_CHAIN ;
2287
- }
2265
+ /* Mark nodes that are an inner part of a short-circuiting chain.
2266
+ * We should not perform a "commit" on them, as it will be performed by the outer-most node.
2267
+ * We do this to avoid passing down an argument in various compile functions. */
2288
2268
2289
- if (force || (!was_in_short_circuiting_chain && ast_kind_is_short_circuited )) {
2290
- flags |= ZEND_SHORT_CIRCUITING_CHAIN_WAS_CREATED ;
2269
+ #define ZEND_SHORT_CIRCUITING_INNER 0x8000
2291
2270
2292
- CG (in_short_circuiting_chain ) = 1 ;
2293
-
2294
- zend_short_circuiting_chain chain ;
2295
- zend_stack_init (& chain .jmp_null_opnums , sizeof (uint32_t ));
2296
- chain .flags = 0 ;
2297
- zend_stack_push (& CG (short_circuiting_chains ), & chain );
2298
- }
2299
-
2300
- if (!force && !ast_kind_is_short_circuited ) {
2301
- CG (in_short_circuiting_chain ) = 0 ;
2271
+ static void zend_short_circuiting_mark_inner (zend_ast * ast ) {
2272
+ if (zend_ast_kind_is_short_circuited (ast -> kind )) {
2273
+ ast -> attr |= ZEND_SHORT_CIRCUITING_INNER ;
2302
2274
}
2303
-
2304
- return flags ;
2305
2275
}
2306
2276
2307
- static void zend_end_short_circuiting_chain ( uint32_t flags , znode * result )
2277
+ static uint32_t zend_short_circuiting_checkpoint ( )
2308
2278
{
2309
- zend_bool was_in_short_circuiting_chain = (flags & ZEND_WAS_IN_SHORT_CIRCUITING_CHAIN ) != 0 ;
2310
- zend_bool short_circuiting_chain_was_created = (flags & ZEND_SHORT_CIRCUITING_CHAIN_WAS_CREATED ) != 0 ;
2311
-
2312
- if (short_circuiting_chain_was_created ) {
2313
- zend_short_circuiting_chain * chain = zend_current_short_circuiting_chain ();
2314
- zend_stack * jmp_null_opnums = & chain -> jmp_null_opnums ;
2279
+ return zend_stack_count (& CG (short_circuiting_opnums ));
2280
+ }
2315
2281
2316
- while (!zend_stack_is_empty (jmp_null_opnums )) {
2317
- uint32_t jmp_null_opnum = * (uint32_t * )zend_stack_top (jmp_null_opnums );
2318
- zend_op * jmp_null_opline = & CG (active_op_array )-> opcodes [jmp_null_opnum ];
2319
- jmp_null_opline -> op2 .opline_num = get_next_op_number ();
2320
- SET_NODE (jmp_null_opline -> result , result );
2321
- jmp_null_opline -> extended_value = chain -> flags ;
2322
- zend_stack_del_top (jmp_null_opnums );
2323
- }
2282
+ static void zend_short_circuiting_commit (uint32_t checkpoint , znode * result , zend_ast * ast )
2283
+ {
2284
+ zend_bool is_short_circuited = zend_ast_kind_is_short_circuited (ast -> kind )
2285
+ || ast -> kind == ZEND_AST_ISSET || ast -> kind == ZEND_AST_EMPTY ;
2286
+ if (!is_short_circuited ) {
2287
+ ZEND_ASSERT (zend_stack_count (& CG (short_circuiting_opnums )) == checkpoint
2288
+ && "Short circuiting stack should be empty" );
2289
+ return ;
2290
+ }
2324
2291
2325
- zend_stack_destroy (jmp_null_opnums );
2326
- zend_stack_del_top (& CG (short_circuiting_chains ));
2292
+ if (ast -> attr & ZEND_SHORT_CIRCUITING_INNER ) {
2293
+ /* Outer-most node will commit. */
2294
+ return ;
2327
2295
}
2328
2296
2329
- CG (in_short_circuiting_chain ) = was_in_short_circuiting_chain ;
2297
+ while (zend_stack_count (& CG (short_circuiting_opnums )) != checkpoint ) {
2298
+ uint32_t opnum = * (uint32_t * ) zend_stack_top (& CG (short_circuiting_opnums ));
2299
+ zend_op * opline = & CG (active_op_array )-> opcodes [opnum ];
2300
+ opline -> op2 .opline_num = get_next_op_number ();
2301
+ SET_NODE (opline -> result , result );
2302
+ opline -> extended_value =
2303
+ ast -> kind == ZEND_AST_ISSET ? ZEND_SHORT_CIRCUITING_CHAIN_ISSET :
2304
+ ast -> kind == ZEND_AST_EMPTY ? ZEND_SHORT_CIRCUITING_CHAIN_EMPTY :
2305
+ ZEND_SHORT_CIRCUITING_CHAIN_EXPR ;
2306
+ zend_stack_del_top (& CG (short_circuiting_opnums ));
2307
+ }
2330
2308
}
2331
2309
2332
2310
static void zend_emit_jmp_null (znode * obj_node )
2333
2311
{
2334
2312
uint32_t jmp_null_opnum = get_next_op_number ();
2335
2313
zend_emit_op (NULL , ZEND_JMP_NULL , obj_node , NULL );
2336
-
2337
- zend_short_circuiting_chain * short_circuiting_chain = zend_current_short_circuiting_chain ();
2338
- zend_stack * jmp_null_opnums = & short_circuiting_chain -> jmp_null_opnums ;
2339
- zend_stack_push (jmp_null_opnums , & jmp_null_opnum );
2314
+ zend_stack_push (& CG (short_circuiting_opnums ), & jmp_null_opnum );
2340
2315
}
2341
2316
2342
2317
#define ZEND_MEMOIZE_NONE 0
@@ -2658,10 +2633,7 @@ static zend_op *zend_compile_simple_var_no_cv(znode *result, zend_ast *ast, uint
2658
2633
znode name_node ;
2659
2634
zend_op * opline ;
2660
2635
2661
- zend_bool was_in_short_circuiting_chain = CG (in_short_circuiting_chain );
2662
- CG (in_short_circuiting_chain ) = 0 ;
2663
2636
zend_compile_expr (& name_node , name_ast );
2664
- CG (in_short_circuiting_chain ) = was_in_short_circuiting_chain ;
2665
2637
if (name_node .op_type == IS_CONST ) {
2666
2638
convert_to_string (& name_node .u .constant );
2667
2639
}
@@ -2761,6 +2733,7 @@ static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t
2761
2733
2762
2734
znode var_node , dim_node ;
2763
2735
2736
+ zend_short_circuiting_mark_inner (var_ast );
2764
2737
opline = zend_delayed_compile_var (& var_node , var_ast , type , 0 );
2765
2738
if (opline && type == BP_VAR_W && (opline -> opcode == ZEND_FETCH_STATIC_PROP_W || opline -> opcode == ZEND_FETCH_OBJ_W )) {
2766
2739
opline -> extended_value |= ZEND_FETCH_DIM_WRITE ;
@@ -2777,10 +2750,7 @@ static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t
2777
2750
}
2778
2751
dim_node .op_type = IS_UNUSED ;
2779
2752
} else {
2780
- zend_bool was_in_short_circuiting_chain = CG (in_short_circuiting_chain );
2781
- CG (in_short_circuiting_chain ) = 0 ;
2782
2753
zend_compile_expr (& dim_node , dim_ast );
2783
- CG (in_short_circuiting_chain ) = was_in_short_circuiting_chain ;
2784
2754
}
2785
2755
2786
2756
opline = zend_delayed_emit_op (result , ZEND_FETCH_DIM_R , & var_node , & dim_node );
@@ -2818,6 +2788,7 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t
2818
2788
}
2819
2789
CG (active_op_array )-> fn_flags |= ZEND_ACC_USES_THIS ;
2820
2790
} else {
2791
+ zend_short_circuiting_mark_inner (obj_ast );
2821
2792
opline = zend_delayed_compile_var (& obj_node , obj_ast , type , 0 );
2822
2793
zend_separate_if_call_and_write (& obj_node , obj_ast , type );
2823
2794
}
@@ -2826,10 +2797,7 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t
2826
2797
zend_emit_jmp_null (& obj_node );
2827
2798
}
2828
2799
2829
- zend_bool was_in_short_circuiting_chain = CG (in_short_circuiting_chain );
2830
- CG (in_short_circuiting_chain ) = 0 ;
2831
2800
zend_compile_expr (& prop_node , prop_ast );
2832
- CG (in_short_circuiting_chain ) = was_in_short_circuiting_chain ;
2833
2801
2834
2802
opline = zend_delayed_emit_op (result , ZEND_FETCH_OBJ_R , & obj_node , & prop_node );
2835
2803
if (opline -> op2_type == IS_CONST ) {
@@ -2862,12 +2830,10 @@ zend_op *zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type, i
2862
2830
znode class_node , prop_node ;
2863
2831
zend_op * opline ;
2864
2832
2833
+ zend_short_circuiting_mark_inner (class_ast );
2865
2834
zend_compile_class_ref (& class_node , class_ast , ZEND_FETCH_CLASS_EXCEPTION );
2866
2835
2867
- zend_bool was_in_short_circuiting_chain = CG (in_short_circuiting_chain );
2868
- CG (in_short_circuiting_chain ) = 0 ;
2869
2836
zend_compile_expr (& prop_node , prop_ast );
2870
- CG (in_short_circuiting_chain ) = was_in_short_circuiting_chain ;
2871
2837
2872
2838
if (delayed ) {
2873
2839
opline = zend_delayed_emit_op (result , ZEND_FETCH_STATIC_PROP_R , & prop_node , NULL );
@@ -3325,9 +3291,6 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */
3325
3291
zend_bool uses_arg_unpack = 0 ;
3326
3292
uint32_t arg_count = 0 ; /* number of arguments not including unpacks */
3327
3293
3328
- zend_bool was_in_short_circuiting_chain = CG (in_short_circuiting_chain );
3329
- CG (in_short_circuiting_chain ) = 0 ;
3330
-
3331
3294
for (i = 0 ; i < args -> children ; ++ i ) {
3332
3295
zend_ast * arg = args -> child [i ];
3333
3296
uint32_t arg_num = i + 1 ;
@@ -3448,8 +3411,6 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */
3448
3411
opline -> result .var = EX_NUM_TO_VAR (arg_num - 1 );
3449
3412
}
3450
3413
3451
- CG (in_short_circuiting_chain ) = was_in_short_circuiting_chain ;
3452
-
3453
3414
return arg_count ;
3454
3415
}
3455
3416
/* }}} */
@@ -4286,6 +4247,7 @@ void zend_compile_method_call(znode *result, zend_ast *ast, uint32_t type) /* {{
4286
4247
}
4287
4248
CG (active_op_array )-> fn_flags |= ZEND_ACC_USES_THIS ;
4288
4249
} else {
4250
+ zend_short_circuiting_mark_inner (obj_ast );
4289
4251
zend_compile_expr (& obj_node , obj_ast );
4290
4252
}
4291
4253
@@ -4360,12 +4322,10 @@ void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type) /* {{
4360
4322
zend_op * opline ;
4361
4323
zend_function * fbc = NULL ;
4362
4324
4325
+ zend_short_circuiting_mark_inner (class_ast );
4363
4326
zend_compile_class_ref (& class_node , class_ast , ZEND_FETCH_CLASS_EXCEPTION );
4364
4327
4365
- zend_bool was_in_short_circuiting_chain = CG (in_short_circuiting_chain );
4366
- CG (in_short_circuiting_chain ) = 0 ;
4367
4328
zend_compile_expr (& method_node , method_ast );
4368
- CG (in_short_circuiting_chain ) = was_in_short_circuiting_chain ;
4369
4329
4370
4330
if (method_node .op_type == IS_CONST ) {
4371
4331
zval * name = & method_node .u .constant ;
@@ -8689,17 +8649,12 @@ void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */
8689
8649
8690
8650
ZEND_ASSERT (ast -> kind == ZEND_AST_ISSET || ast -> kind == ZEND_AST_EMPTY );
8691
8651
8692
- uint32_t begin_short_circuiting_chain_flags = zend_begin_short_circuiting_chain (ast -> kind , 1 );
8693
- zend_current_short_circuiting_chain ()-> flags = ast -> kind == ZEND_AST_ISSET
8694
- ? ZEND_SHORT_CIRCUITING_CHAIN_ISSET
8695
- : ZEND_SHORT_CIRCUITING_CHAIN_EMPTY ;
8696
-
8652
+ zend_short_circuiting_mark_inner (var_ast );
8697
8653
if (!zend_is_variable (var_ast )) {
8698
8654
if (ast -> kind == ZEND_AST_EMPTY ) {
8699
8655
/* empty(expr) can be transformed to !expr */
8700
8656
zend_ast * not_ast = zend_ast_create_ex (ZEND_AST_UNARY_OP , ZEND_BOOL_NOT , var_ast );
8701
8657
zend_compile_expr (result , not_ast );
8702
- zend_end_short_circuiting_chain (begin_short_circuiting_chain_flags , result );
8703
8658
return ;
8704
8659
} else {
8705
8660
zend_error_noreturn (E_COMPILE_ERROR ,
@@ -8740,8 +8695,6 @@ void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */
8740
8695
if (!(ast -> kind == ZEND_AST_ISSET )) {
8741
8696
opline -> extended_value |= ZEND_ISEMPTY ;
8742
8697
}
8743
-
8744
- zend_end_short_circuiting_chain (begin_short_circuiting_chain_flags , result );
8745
8698
}
8746
8699
/* }}} */
8747
8700
@@ -9606,9 +9559,9 @@ static void zend_compile_expr_inner(znode *result, zend_ast *ast) /* {{{ */
9606
9559
9607
9560
void zend_compile_expr (znode * result , zend_ast * ast )
9608
9561
{
9609
- uint32_t begin_short_circuiting_chain_flags = zend_begin_short_circuiting_chain ( ast -> kind , 0 );
9562
+ uint32_t checkpoint = zend_short_circuiting_checkpoint ( );
9610
9563
zend_compile_expr_inner (result , ast );
9611
- zend_end_short_circuiting_chain ( begin_short_circuiting_chain_flags , result );
9564
+ zend_short_circuiting_commit ( checkpoint , result , ast );
9612
9565
}
9613
9566
9614
9567
static zend_op * zend_compile_var_inner (znode * result , zend_ast * ast , uint32_t type , int by_ref )
@@ -9651,10 +9604,9 @@ static zend_op *zend_compile_var_inner(znode *result, zend_ast *ast, uint32_t ty
9651
9604
9652
9605
zend_op * zend_compile_var (znode * result , zend_ast * ast , uint32_t type , int by_ref ) /* {{{ */
9653
9606
{
9654
- uint32_t begin_short_circuiting_chain_flags = zend_begin_short_circuiting_chain ( ast -> kind , 0 );
9607
+ uint32_t checkpoint = zend_short_circuiting_checkpoint ( );
9655
9608
zend_op * opcode = zend_compile_var_inner (result , ast , type , by_ref );
9656
- zend_end_short_circuiting_chain (begin_short_circuiting_chain_flags , result );
9657
-
9609
+ zend_short_circuiting_commit (checkpoint , result , ast );
9658
9610
return opcode ;
9659
9611
}
9660
9612
0 commit comments