@@ -2612,6 +2612,51 @@ static void zend_jit_trace_setup_ret_counter(const zend_op *opline, size_t offse
2612
2612
}
2613
2613
}
2614
2614
2615
+ static zend_bool zend_jit_may_delay_fetch_this (zend_ssa * ssa , const zend_op * * ssa_opcodes , int var )
2616
+ {
2617
+ int i ;
2618
+ int use = ssa -> vars [var ].use_chain ;
2619
+ const zend_op * opline ;
2620
+
2621
+ if (use < 0
2622
+ || ssa -> vars [var ].phi_use_chain
2623
+ || ssa -> ops [use ].op1_use != var
2624
+ || ssa -> ops [use ].op1_use_chain != -1 ) {
2625
+ return 0 ;
2626
+ }
2627
+
2628
+ opline = ssa_opcodes [use ];
2629
+ if (opline -> opcode == ZEND_FETCH_OBJ_FUNC_ARG ) {
2630
+ if (!JIT_G (current_frame )
2631
+ || !JIT_G (current_frame )-> call
2632
+ || !JIT_G (current_frame )-> call -> func
2633
+ || !TRACE_FRAME_IS_LAST_SEND_BY_VAL (JIT_G (current_frame )-> call )) {
2634
+ return 0 ;
2635
+ }
2636
+ } else if (opline -> opcode != ZEND_FETCH_OBJ_R
2637
+ && opline -> opcode != ZEND_FETCH_OBJ_IS
2638
+ && opline -> opcode != ZEND_FETCH_OBJ_W ) {
2639
+ return 0 ;
2640
+ }
2641
+
2642
+ if (opline -> op2_type != IS_CONST
2643
+ || Z_TYPE_P (RT_CONSTANT (opline , opline -> op2 )) != IS_STRING
2644
+ || Z_STRVAL_P (RT_CONSTANT (opline , opline -> op2 ))[0 ] == '\0' ) {
2645
+ return 0 ;
2646
+ }
2647
+
2648
+ for (i = ssa -> vars [var ].definition ; i < use ; i ++ ) {
2649
+ if (ssa_opcodes [i ]-> opcode == ZEND_DO_UCALL
2650
+ || ssa_opcodes [i ]-> opcode == ZEND_DO_FCALL_BY_NAME
2651
+ || ssa_opcodes [i ]-> opcode == ZEND_DO_FCALL
2652
+ || ssa_opcodes [i ]-> opcode == ZEND_INCLUDE_OR_EVAL ) {
2653
+ return 0 ;
2654
+ }
2655
+ }
2656
+
2657
+ return 1 ;
2658
+ }
2659
+
2615
2660
static const void * zend_jit_trace (zend_jit_trace_rec * trace_buffer , uint32_t parent_trace , uint32_t exit_num )
2616
2661
{
2617
2662
const void * handler = NULL ;
@@ -2622,6 +2667,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
2622
2667
void * checkpoint ;
2623
2668
const zend_op_array * op_array ;
2624
2669
zend_ssa * ssa , * op_array_ssa ;
2670
+ const zend_op * * ssa_opcodes ;
2625
2671
zend_jit_trace_rec * p ;
2626
2672
zend_jit_op_array_trace_extension * jit_extension ;
2627
2673
int num_op_arrays = 0 ;
@@ -2634,6 +2680,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
2634
2680
zend_jit_addr op1_addr , op1_def_addr , op2_addr , op2_def_addr , res_addr ;
2635
2681
zend_class_entry * ce ;
2636
2682
zend_bool ce_is_instanceof ;
2683
+ zend_bool delayed_fetch_this = 0 ;
2637
2684
uint32_t i ;
2638
2685
zend_jit_trace_stack_frame * frame , * top , * call ;
2639
2686
zend_jit_trace_stack * stack ;
@@ -2652,6 +2699,8 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
2652
2699
goto jit_cleanup ;
2653
2700
}
2654
2701
2702
+ ssa_opcodes = ((zend_tssa * )ssa )-> tssa_opcodes ;
2703
+
2655
2704
/* Register allocation */
2656
2705
if ((JIT_G (opt_flags ) & (ZEND_JIT_REG_ALLOC_LOCAL |ZEND_JIT_REG_ALLOC_GLOBAL ))
2657
2706
&& JIT_G (opt_level ) >= ZEND_JIT_LEVEL_INLINE ) {
@@ -2768,6 +2817,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
2768
2817
if (!zend_jit_store_var (& dasm_state , ssa -> var_info [i ].type , i , STACK_REG (parent_stack , i ))) {
2769
2818
goto jit_failure ;
2770
2819
}
2820
+ } else if (STACK_REG (parent_stack , i ) == ZREG_THIS ) {
2821
+ if (!zend_jit_load_this (& dasm_state , EX_NUM_TO_VAR (i ))) {
2822
+ goto jit_failure ;
2823
+ }
2771
2824
} else {
2772
2825
SET_STACK_REG (stack , i , ZREG_NONE );
2773
2826
if (!zend_jit_store_const (& dasm_state , i , STACK_REG (parent_stack , i ))) {
@@ -3732,6 +3785,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
3732
3785
case ZEND_FETCH_OBJ_R :
3733
3786
case ZEND_FETCH_OBJ_IS :
3734
3787
case ZEND_FETCH_OBJ_W :
3788
+ delayed_fetch_this = 0 ;
3735
3789
if (opline -> op2_type != IS_CONST
3736
3790
|| Z_TYPE_P (RT_CONSTANT (opline , opline -> op2 )) != IS_STRING
3737
3791
|| Z_STRVAL_P (RT_CONSTANT (opline , opline -> op2 ))[0 ] == '\0' ) {
@@ -3778,9 +3832,13 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
3778
3832
}
3779
3833
}
3780
3834
}
3835
+ if (ssa_op -> op1_use >= 0 ) {
3836
+ delayed_fetch_this = ssa -> var_info [ssa_op -> op1_use ].delayed_fetch_this ;
3837
+ }
3781
3838
}
3782
3839
if (!zend_jit_fetch_obj (& dasm_state , opline , op_array ,
3783
3840
op1_info , op1_addr , op1_indirect , ce , ce_is_instanceof ,
3841
+ delayed_fetch_this ,
3784
3842
zend_may_throw (opline , ssa_op , op_array , ssa ))) {
3785
3843
goto jit_failure ;
3786
3844
}
@@ -3861,7 +3919,14 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
3861
3919
}
3862
3920
goto done ;
3863
3921
case ZEND_FETCH_THIS :
3864
- if (!zend_jit_fetch_this (& dasm_state , opline , op_array )) {
3922
+ delayed_fetch_this = 0 ;
3923
+ if (ssa_op -> result_def >= 0 ) {
3924
+ if (zend_jit_may_delay_fetch_this (ssa , ssa_opcodes , ssa_op -> result_def )) {
3925
+ ssa -> var_info [ssa_op -> result_def ].delayed_fetch_this = 1 ;
3926
+ delayed_fetch_this = 1 ;
3927
+ }
3928
+ }
3929
+ if (!zend_jit_fetch_this (& dasm_state , opline , op_array , delayed_fetch_this )) {
3865
3930
goto jit_failure ;
3866
3931
}
3867
3932
goto done ;
@@ -3942,6 +4007,11 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
3942
4007
zend_jit_trace_clenup_stack (stack , opline , ssa_op , ssa , ra );
3943
4008
}
3944
4009
4010
+ if ((opline -> op1_type & (IS_VAR |IS_TMP_VAR ))
4011
+ && STACK_REG (stack , EX_VAR_TO_NUM (opline -> op1 .var )) == ZREG_THIS ) {
4012
+ SET_STACK_REG (stack , EX_VAR_TO_NUM (opline -> op1 .var ), ZREG_NONE );
4013
+ }
4014
+
3945
4015
if (ssa_op ) {
3946
4016
/* Keep information about known types on abstract stack */
3947
4017
if (ssa_op -> result_def >= 0 ) {
@@ -3975,7 +4045,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
3975
4045
SET_RES_STACK_VAR_TYPE (type );
3976
4046
if (type != IS_UNKNOWN ) {
3977
4047
ssa -> var_info [ssa_op -> result_def ].type &= ~MAY_BE_GUARD ;
3978
- if (ra && ra [ssa_op -> result_def ]) {
4048
+ if (opline -> opcode == ZEND_FETCH_THIS
4049
+ && delayed_fetch_this ) {
4050
+ SET_STACK_REG (stack , EX_VAR_TO_NUM (opline -> result .var ), ZREG_THIS );
4051
+ } else if (ra && ra [ssa_op -> result_def ]) {
3979
4052
SET_STACK_REG (stack , EX_VAR_TO_NUM (opline -> result .var ), ra [ssa_op -> result_def ]-> reg );
3980
4053
}
3981
4054
}
@@ -4323,21 +4396,23 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
4323
4396
}
4324
4397
} else if (p -> stop == ZEND_JIT_TRACE_STOP_LINK
4325
4398
|| p -> stop == ZEND_JIT_TRACE_STOP_INTERPRETER ) {
4326
- if (ra ) {
4327
- /* Generate code for trace deoptimization */
4328
- int i ;
4329
-
4330
- for (i = 0 ; i < op_array -> last_var + op_array -> T ; i ++ ) {
4331
- if (STACK_REG (stack , i ) != ZREG_NONE ) {
4332
- // TODO: optimize out useless stores ????
4333
- if (STACK_REG (stack , i ) < ZREG_NUM ) {
4334
- if (!zend_jit_store_var (& dasm_state , 1 << STACK_TYPE (stack , i ), i , STACK_REG (stack , i ))) {
4335
- goto jit_failure ;
4336
- }
4337
- } else {
4338
- if (!zend_jit_store_const (& dasm_state , i , STACK_REG (stack , i ))) {
4339
- goto jit_failure ;
4340
- }
4399
+ /* Generate code for trace deoptimization */
4400
+ int i ;
4401
+
4402
+ for (i = 0 ; i < op_array -> last_var + op_array -> T ; i ++ ) {
4403
+ if (STACK_REG (stack , i ) != ZREG_NONE ) {
4404
+ // TODO: optimize out useless stores ????
4405
+ if (STACK_REG (stack , i ) < ZREG_NUM ) {
4406
+ if (!zend_jit_store_var (& dasm_state , 1 << STACK_TYPE (stack , i ), i , STACK_REG (stack , i ))) {
4407
+ goto jit_failure ;
4408
+ }
4409
+ } else if (STACK_REG (stack , i ) == ZREG_THIS ) {
4410
+ if (!zend_jit_load_this (& dasm_state , EX_NUM_TO_VAR (i ))) {
4411
+ goto jit_failure ;
4412
+ }
4413
+ } else {
4414
+ if (!zend_jit_store_const (& dasm_state , i , STACK_REG (stack , i ))) {
4415
+ goto jit_failure ;
4341
4416
}
4342
4417
}
4343
4418
}
@@ -4484,6 +4559,10 @@ static const void *zend_jit_trace_exit_to_vm(uint32_t trace_num, uint32_t exit_n
4484
4559
if (!zend_jit_store_var (& dasm_state , 1 << STACK_TYPE (stack , i ), i , STACK_REG (stack , i ))) {
4485
4560
goto jit_failure ;
4486
4561
}
4562
+ } else if (STACK_REG (stack , i ) == ZREG_THIS ) {
4563
+ if (!zend_jit_load_this (& dasm_state , EX_NUM_TO_VAR (i ))) {
4564
+ goto jit_failure ;
4565
+ }
4487
4566
} else {
4488
4567
if (!zend_jit_store_const (& dasm_state , i , STACK_REG (stack , i ))) {
4489
4568
goto jit_failure ;
@@ -4904,6 +4983,8 @@ static void zend_jit_dump_exit_info(zend_jit_trace_info *t)
4904
4983
if (STACK_REG (stack , j ) != ZREG_NONE ) {
4905
4984
if (STACK_REG (stack , j ) < ZREG_NUM ) {
4906
4985
fprintf (stderr , "(%s)" , zend_reg_name [STACK_REG (stack , j )]);
4986
+ } else if (STACK_REG (stack , j ) == ZREG_THIS ) {
4987
+ fprintf (stderr , "(this)" );
4907
4988
} else {
4908
4989
fprintf (stderr , "(const_%d)" , STACK_REG (stack , j ) - ZREG_NUM );
4909
4990
}
@@ -5357,6 +5438,11 @@ int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf
5357
5438
ZEND_UNREACHABLE ();
5358
5439
}
5359
5440
ZVAL_DOUBLE (EX_VAR_NUM (i ), val );
5441
+ } else if (STACK_REG (stack , i ) == ZREG_THIS ) {
5442
+ zend_object * obj = Z_OBJ (EX (This ));
5443
+
5444
+ GC_ADDREF (obj );
5445
+ ZVAL_OBJ (EX_VAR_NUM (i ), obj );
5360
5446
} else {
5361
5447
ZEND_UNREACHABLE ();
5362
5448
}
0 commit comments