@@ -60,6 +60,12 @@ typedef struct _zend_loop_var {
60
60
uint32_t try_catch_offset ;
61
61
} zend_loop_var ;
62
62
63
+ typedef struct {
64
+ uint32_t opnum ;
65
+ bool delayed ;
66
+ uint32_t delayed_oplines_stack_level ;
67
+ } zend_jmp_null_opnum ;
68
+
63
69
static inline uint32_t zend_alloc_cache_slots (unsigned count ) {
64
70
if (count == 0 ) {
65
71
return (uint32_t ) -1 ;
@@ -368,10 +374,12 @@ void zend_init_compiler_data_structures(void) /* {{{ */
368
374
{
369
375
zend_stack_init (& CG (loop_var_stack ), sizeof (zend_loop_var ));
370
376
zend_stack_init (& CG (delayed_oplines_stack ), sizeof (zend_op ));
371
- zend_stack_init (& CG (short_circuiting_opnums ), sizeof (uint32_t ));
377
+ zend_stack_init (& CG (delayed_oplines_offset_stack ), sizeof (uint32_t ));
378
+ zend_stack_init (& CG (short_circuiting_opnums ), sizeof (zend_jmp_null_opnum ));
372
379
CG (active_class_entry ) = NULL ;
373
380
CG (in_compilation ) = 0 ;
374
381
CG (skip_shebang ) = 0 ;
382
+ CG (delayed_oplines_stack_level ) = 0 ;
375
383
376
384
CG (encoding_declared ) = 0 ;
377
385
CG (memoized_exprs ) = NULL ;
@@ -422,6 +430,7 @@ void shutdown_compiler(void) /* {{{ */
422
430
{
423
431
zend_stack_destroy (& CG (loop_var_stack ));
424
432
zend_stack_destroy (& CG (delayed_oplines_stack ));
433
+ zend_stack_destroy (& CG (delayed_oplines_offset_stack ));
425
434
zend_stack_destroy (& CG (short_circuiting_opnums ));
426
435
zend_hash_destroy (& CG (filenames_table ));
427
436
zend_arena_destroy (CG (arena ));
@@ -2208,21 +2217,45 @@ static inline zend_op *zend_delayed_emit_op(znode *result, zend_uchar opcode, zn
2208
2217
2209
2218
static inline uint32_t zend_delayed_compile_begin (void ) /* {{{ */
2210
2219
{
2211
- return zend_stack_count (& CG (delayed_oplines_stack ));
2220
+ uint32_t offset = zend_stack_count (& CG (delayed_oplines_stack ));
2221
+ zend_stack_push (& CG (delayed_oplines_offset_stack ), & offset );
2222
+ ++ CG (delayed_oplines_stack_level );
2223
+ return offset ;
2212
2224
}
2213
2225
/* }}} */
2214
2226
2215
2227
static zend_op * zend_delayed_compile_end (uint32_t offset ) /* {{{ */
2216
2228
{
2217
2229
zend_op * opline = NULL , * oplines = zend_stack_base (& CG (delayed_oplines_stack ));
2218
- uint32_t i , count = zend_stack_count ( & CG ( delayed_oplines_stack ) );
2230
+ uint32_t count , first_delayed_opnum = get_next_op_number ( );
2219
2231
2232
+ count = zend_stack_count (& CG (delayed_oplines_stack ));
2220
2233
ZEND_ASSERT (count >= offset );
2221
- for (i = offset ; i < count ; ++ i ) {
2234
+ for (uint32_t i = offset ; i < count ; ++ i ) {
2222
2235
opline = get_next_op ();
2223
2236
memcpy (opline , & oplines [i ], sizeof (zend_op ));
2224
2237
}
2225
2238
CG (delayed_oplines_stack ).top = offset ;
2239
+
2240
+ uint32_t delayed_oplines_stack_level = CG (delayed_oplines_stack_level );
2241
+ int32_t i = zend_stack_count (& CG (short_circuiting_opnums )) - 1 ;
2242
+ while (i >= 0 ) {
2243
+ zend_jmp_null_opnum * opnum = & ((zend_jmp_null_opnum * ) zend_stack_base (& CG (short_circuiting_opnums )))[i ];
2244
+
2245
+ if (opnum -> delayed_oplines_stack_level != delayed_oplines_stack_level ) {
2246
+ break ;
2247
+ }
2248
+
2249
+ if (opnum -> delayed ) {
2250
+ opnum -> opnum += first_delayed_opnum ;
2251
+ opnum -> delayed = 0 ;
2252
+ }
2253
+
2254
+ -- i ;
2255
+ }
2256
+
2257
+ -- CG (delayed_oplines_offset_stack ).top ;
2258
+ -- CG (delayed_oplines_stack_level );
2226
2259
return opline ;
2227
2260
}
2228
2261
/* }}} */
@@ -2293,8 +2326,15 @@ static void zend_short_circuiting_commit(uint32_t checkpoint, znode *result, zen
2293
2326
}
2294
2327
2295
2328
while (zend_stack_count (& CG (short_circuiting_opnums )) != checkpoint ) {
2296
- uint32_t opnum = * (uint32_t * ) zend_stack_top (& CG (short_circuiting_opnums ));
2297
- zend_op * opline = & CG (active_op_array )-> opcodes [opnum ];
2329
+ zend_jmp_null_opnum * opnum = zend_stack_top (& CG (short_circuiting_opnums ));
2330
+ zend_op * opline ;
2331
+ if (opnum -> delayed ) {
2332
+ uint32_t offset = * ((uint32_t * ) zend_stack_top (& CG (delayed_oplines_offset_stack ))) + opnum -> opnum ;
2333
+ opline = & ((zend_op * ) zend_stack_base (& CG (delayed_oplines_stack )))[offset ];
2334
+ } else {
2335
+ opline = & CG (active_op_array )-> opcodes [opnum -> opnum ];
2336
+ }
2337
+ ZEND_ASSERT (opline -> opcode == ZEND_JMP_NULL );
2298
2338
opline -> op2 .opline_num = get_next_op_number ();
2299
2339
SET_NODE (opline -> result , result );
2300
2340
opline -> extended_value =
@@ -2305,10 +2345,22 @@ static void zend_short_circuiting_commit(uint32_t checkpoint, znode *result, zen
2305
2345
}
2306
2346
}
2307
2347
2308
- static void zend_emit_jmp_null (znode * obj_node )
2348
+ static void zend_emit_jmp_null (znode * obj_node , bool delay )
2309
2349
{
2310
- uint32_t jmp_null_opnum = get_next_op_number ();
2311
- zend_op * opline = zend_emit_op (NULL , ZEND_JMP_NULL , obj_node , NULL );
2350
+ zend_jmp_null_opnum jmp_null_opnum ;
2351
+ jmp_null_opnum .delayed = delay ;
2352
+ jmp_null_opnum .delayed_oplines_stack_level = CG (delayed_oplines_stack_level );
2353
+ zend_op * opline ;
2354
+
2355
+ if (delay ) {
2356
+ uint32_t delayed_oplines_count = zend_stack_count (& CG (delayed_oplines_stack ));
2357
+ jmp_null_opnum .opnum = delayed_oplines_count - * ((uint32_t * ) zend_stack_top (& CG (delayed_oplines_offset_stack )));
2358
+ opline = zend_delayed_emit_op (NULL , ZEND_JMP_NULL , obj_node , NULL );
2359
+ } else {
2360
+ jmp_null_opnum .opnum = get_next_op_number ();
2361
+ opline = zend_emit_op (NULL , ZEND_JMP_NULL , obj_node , NULL );
2362
+ }
2363
+
2312
2364
if (opline -> op1_type == IS_CONST ) {
2313
2365
Z_TRY_ADDREF_P (CT_CONSTANT (opline -> op1 ));
2314
2366
}
@@ -2796,7 +2848,7 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t
2796
2848
opline = zend_delayed_compile_var (& obj_node , obj_ast , type , 0 );
2797
2849
zend_separate_if_call_and_write (& obj_node , obj_ast , type );
2798
2850
if (nullsafe ) {
2799
- zend_emit_jmp_null (& obj_node );
2851
+ zend_emit_jmp_null (& obj_node , 1 );
2800
2852
}
2801
2853
}
2802
2854
@@ -4356,7 +4408,7 @@ void zend_compile_method_call(znode *result, zend_ast *ast, uint32_t type) /* {{
4356
4408
zend_short_circuiting_mark_inner (obj_ast );
4357
4409
zend_compile_expr (& obj_node , obj_ast );
4358
4410
if (nullsafe ) {
4359
- zend_emit_jmp_null (& obj_node );
4411
+ zend_emit_jmp_null (& obj_node , 0 );
4360
4412
}
4361
4413
}
4362
4414
0 commit comments