@@ -2581,18 +2581,6 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
2581
2581
return NULL ;
2582
2582
}
2583
2583
2584
- static int zend_jit_trace_stack_needs_deoptimization (zend_jit_trace_stack * stack , uint32_t stack_size )
2585
- {
2586
- uint32_t i ;
2587
-
2588
- for (i = 0 ; i < stack_size ; i ++ ) {
2589
- if (STACK_REG (stack , i ) != ZREG_NONE ) {
2590
- return 1 ;
2591
- }
2592
- }
2593
- return 0 ;
2594
- }
2595
-
2596
2584
static void zend_jit_trace_clenup_stack (zend_jit_trace_stack * stack , const zend_op * opline , const zend_ssa_op * ssa_op , const zend_ssa * ssa , zend_lifetime_interval * * ra )
2597
2585
{
2598
2586
uint32_t line = ssa_op - ssa -> ops ;
@@ -2674,6 +2662,140 @@ static zend_bool zend_jit_may_delay_fetch_this(zend_ssa *ssa, const zend_op **ss
2674
2662
return 1 ;
2675
2663
}
2676
2664
2665
+ static int zend_jit_trace_stack_needs_deoptimization (zend_jit_trace_stack * stack , uint32_t stack_size )
2666
+ {
2667
+ uint32_t i ;
2668
+
2669
+ for (i = 0 ; i < stack_size ; i ++ ) {
2670
+ if (STACK_REG (stack , i ) != ZREG_NONE ) {
2671
+ return 1 ;
2672
+ }
2673
+ }
2674
+ return 0 ;
2675
+ }
2676
+
2677
+ static int zend_jit_trace_exit_needs_deoptimization (uint32_t trace_num , uint32_t exit_num )
2678
+ {
2679
+ const zend_op * opline = zend_jit_traces [trace_num ].exit_info [exit_num ].opline ;
2680
+ uint32_t flags = zend_jit_traces [trace_num ].exit_info [exit_num ].flags ;
2681
+ uint32_t stack_size ;
2682
+ zend_jit_trace_stack * stack ;
2683
+
2684
+ if (opline || (flags & (ZEND_JIT_EXIT_RESTORE_CALL |ZEND_JIT_EXIT_FREE_OP1 |ZEND_JIT_EXIT_FREE_OP2 ))) {
2685
+ return 1 ;
2686
+ }
2687
+
2688
+ stack_size = zend_jit_traces [trace_num ].exit_info [exit_num ].stack_size ;
2689
+ stack = zend_jit_traces [trace_num ].stack_map + zend_jit_traces [trace_num ].exit_info [exit_num ].stack_offset ;
2690
+ return zend_jit_trace_stack_needs_deoptimization (stack , stack_size );
2691
+ }
2692
+
2693
+ static int zend_jit_trace_deoptimization (dasm_State * * Dst ,
2694
+ uint32_t flags ,
2695
+ const zend_op * opline ,
2696
+ zend_jit_trace_stack * parent_stack ,
2697
+ int parent_vars_count ,
2698
+ zend_jit_trace_stack * stack ,
2699
+ zend_lifetime_interval * * ra )
2700
+ {
2701
+ int i ;
2702
+ zend_bool has_constants = 0 ;
2703
+ zend_bool has_unsaved_vars = 0 ;
2704
+
2705
+ // TODO: Merge this loop with the following register LOAD loop to implement parallel move ???
2706
+ for (i = 0 ; i < parent_vars_count ; i ++ ) {
2707
+ int8_t reg = STACK_REG (parent_stack , i );
2708
+
2709
+ if (reg != ZREG_NONE ) {
2710
+ if (reg < ZREG_NUM ) {
2711
+ if (ra && ra [i ] && ra [i ]-> reg == reg ) {
2712
+ /* register already loaded by parent trace */
2713
+ if (stack ) {
2714
+ SET_STACK_REG (stack , i , reg );
2715
+ }
2716
+ has_unsaved_vars = 1 ;
2717
+ } else if (!zend_jit_store_var (Dst , 1 << STACK_TYPE (parent_stack , i ), i , reg )) {
2718
+ return 0 ;
2719
+ }
2720
+ } else {
2721
+ /* delay custom deoptimization instructions to prevent register cpobbering */
2722
+ has_constants = 1 ;
2723
+ }
2724
+ }
2725
+ }
2726
+
2727
+ if (has_unsaved_vars
2728
+ && (has_constants
2729
+ || (flags & (ZEND_JIT_EXIT_RESTORE_CALL |ZEND_JIT_EXIT_FREE_OP1 |ZEND_JIT_EXIT_FREE_OP2 )))) {
2730
+ for (i = 0 ; i < parent_vars_count ; i ++ ) {
2731
+ int8_t reg = STACK_REG (parent_stack , i );
2732
+
2733
+ if (reg != ZREG_NONE ) {
2734
+ if (reg < ZREG_NUM ) {
2735
+ if (ra && ra [i ] && ra [i ]-> reg == reg ) {
2736
+ if (stack ) {
2737
+ SET_STACK_REG (stack , i , ZREG_NONE );
2738
+ }
2739
+ if (!zend_jit_store_var (Dst , 1 << STACK_TYPE (parent_stack , i ), i , reg )) {
2740
+ return 0 ;
2741
+ }
2742
+ }
2743
+ }
2744
+ }
2745
+ }
2746
+ }
2747
+
2748
+ if (has_constants ) {
2749
+ for (i = 0 ; i < parent_vars_count ; i ++ ) {
2750
+ int8_t reg = STACK_REG (parent_stack , i );
2751
+
2752
+ if (reg != ZREG_NONE ) {
2753
+ if (reg < ZREG_NUM ) {
2754
+ /* pass */
2755
+ } else if (reg == ZREG_THIS ) {
2756
+ if (!zend_jit_load_this (Dst , EX_NUM_TO_VAR (i ))) {
2757
+ return 0 ;
2758
+ }
2759
+ } else {
2760
+ if (!zend_jit_store_const (Dst , i , reg )) {
2761
+ return 0 ;
2762
+ }
2763
+ }
2764
+ }
2765
+ }
2766
+ }
2767
+
2768
+ if (flags & ZEND_JIT_EXIT_RESTORE_CALL ) {
2769
+ if (!zend_jit_save_call_chain (Dst , -1 )) {
2770
+ return 0 ;
2771
+ }
2772
+ }
2773
+
2774
+ if (flags & ZEND_JIT_EXIT_FREE_OP2 ) {
2775
+ const zend_op * op = opline - 1 ;
2776
+
2777
+ if (!zend_jit_free_op (Dst , op , -1 , op -> op2 .var )) {
2778
+ return 0 ;
2779
+ }
2780
+ }
2781
+
2782
+ if (flags & ZEND_JIT_EXIT_FREE_OP1 ) {
2783
+ const zend_op * op = opline - 1 ;
2784
+
2785
+ if (!zend_jit_free_op (Dst , op , -1 , op -> op1 .var )) {
2786
+ return 0 ;
2787
+ }
2788
+ }
2789
+
2790
+ if (flags & (ZEND_JIT_EXIT_FREE_OP1 |ZEND_JIT_EXIT_FREE_OP2 )) {
2791
+ if (!zend_jit_check_exception (Dst )) {
2792
+ return 0 ;
2793
+ }
2794
+ }
2795
+
2796
+ return 1 ;
2797
+ }
2798
+
2677
2799
static const void * zend_jit_trace (zend_jit_trace_rec * trace_buffer , uint32_t parent_trace , uint32_t exit_num )
2678
2800
{
2679
2801
const void * handler = NULL ;
@@ -2824,49 +2946,11 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
2824
2946
2825
2947
if (parent_trace ) {
2826
2948
/* Deoptimization */
2827
-
2828
- // TODO: Merge this loop with the following LOAD loop to implement parallel move ???
2829
- for (i = 0 ; i < parent_vars_count ; i ++ ) {
2830
- if (STACK_REG (parent_stack , i ) != ZREG_NONE ) {
2831
- if (ra && ra [i ] && ra [i ]-> reg == STACK_REG (parent_stack , i )) {
2832
- /* register already loaded by parent trace */
2833
- SET_STACK_REG (stack , i , ra [i ]-> reg );
2834
- } else if (STACK_REG (parent_stack , i ) < ZREG_NUM ) {
2835
- if (!zend_jit_store_var (& dasm_state , ssa -> var_info [i ].type , i , STACK_REG (parent_stack , i ))) {
2836
- goto jit_failure ;
2837
- }
2838
- } else if (STACK_REG (parent_stack , i ) == ZREG_THIS ) {
2839
- SET_STACK_REG (stack , i , ZREG_NONE );
2840
- if (!zend_jit_load_this (& dasm_state , EX_NUM_TO_VAR (i ))) {
2841
- goto jit_failure ;
2842
- }
2843
- } else {
2844
- SET_STACK_REG (stack , i , ZREG_NONE );
2845
- if (!zend_jit_store_const (& dasm_state , i , STACK_REG (parent_stack , i ))) {
2846
- goto jit_failure ;
2847
- }
2848
- }
2849
- }
2850
- }
2851
- if (zend_jit_traces [parent_trace ].exit_info [exit_num ].flags & ZEND_JIT_EXIT_RESTORE_CALL ) {
2852
- zend_jit_save_call_chain (& dasm_state , -1 );
2853
- }
2854
- if (zend_jit_traces [parent_trace ].exit_info [exit_num ].flags & ZEND_JIT_EXIT_FREE_OP2 ) {
2855
- const zend_op * op = zend_jit_traces [parent_trace ].exit_info [exit_num ].opline - 1 ;
2856
- if (!zend_jit_free_op (& dasm_state , op , -1 , op -> op2 .var )) {
2857
- goto jit_failure ;
2858
- }
2859
- }
2860
- if (zend_jit_traces [parent_trace ].exit_info [exit_num ].flags & ZEND_JIT_EXIT_FREE_OP1 ) {
2861
- const zend_op * op = zend_jit_traces [parent_trace ].exit_info [exit_num ].opline - 1 ;
2862
- if (!zend_jit_free_op (& dasm_state , op , -1 , op -> op1 .var )) {
2863
- goto jit_failure ;
2864
- }
2865
- }
2866
- if (zend_jit_traces [parent_trace ].exit_info [exit_num ].flags & (ZEND_JIT_EXIT_FREE_OP1 |ZEND_JIT_EXIT_FREE_OP2 )) {
2867
- if (!zend_jit_check_exception (& dasm_state )) {
2868
- goto jit_failure ;
2869
- }
2949
+ if (!zend_jit_trace_deoptimization (& dasm_state ,
2950
+ zend_jit_traces [parent_trace ].exit_info [exit_num ].flags ,
2951
+ zend_jit_traces [parent_trace ].exit_info [exit_num ].opline ,
2952
+ parent_stack , parent_vars_count , stack , ra )) {
2953
+ goto jit_failure ;
2870
2954
}
2871
2955
}
2872
2956
@@ -4457,26 +4541,9 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
4457
4541
}
4458
4542
} else if (p -> stop == ZEND_JIT_TRACE_STOP_LINK
4459
4543
|| p -> stop == ZEND_JIT_TRACE_STOP_INTERPRETER ) {
4460
- /* Generate code for trace deoptimization */
4461
- int i ;
4462
-
4463
- for (i = 0 ; i < op_array -> last_var + op_array -> T ; i ++ ) {
4464
- if (STACK_REG (stack , i ) != ZREG_NONE ) {
4465
- // TODO: optimize out useless stores ????
4466
- if (STACK_REG (stack , i ) < ZREG_NUM ) {
4467
- if (!zend_jit_store_var (& dasm_state , 1 << STACK_TYPE (stack , i ), i , STACK_REG (stack , i ))) {
4468
- goto jit_failure ;
4469
- }
4470
- } else if (STACK_REG (stack , i ) == ZREG_THIS ) {
4471
- if (!zend_jit_load_this (& dasm_state , EX_NUM_TO_VAR (i ))) {
4472
- goto jit_failure ;
4473
- }
4474
- } else {
4475
- if (!zend_jit_store_const (& dasm_state , i , STACK_REG (stack , i ))) {
4476
- goto jit_failure ;
4477
- }
4478
- }
4479
- }
4544
+ if (!zend_jit_trace_deoptimization (& dasm_state , 0 , NULL ,
4545
+ stack , op_array -> last_var + op_array -> T , NULL , NULL )) {
4546
+ goto jit_failure ;
4480
4547
}
4481
4548
if (p -> stop == ZEND_JIT_TRACE_STOP_LINK ) {
4482
4549
if (!zend_jit_set_valid_ip (& dasm_state , p -> opline )) {
@@ -4572,30 +4639,14 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
4572
4639
return handler ;
4573
4640
}
4574
4641
4575
- static int zend_jit_trace_exit_needs_deoptimization (uint32_t trace_num , uint32_t exit_num )
4576
- {
4577
- const zend_op * opline = zend_jit_traces [trace_num ].exit_info [exit_num ].opline ;
4578
- uint32_t flags = zend_jit_traces [trace_num ].exit_info [exit_num ].flags ;
4579
- uint32_t stack_size ;
4580
- zend_jit_trace_stack * stack ;
4581
-
4582
- if (opline || (flags & ZEND_JIT_EXIT_RESTORE_CALL )) {
4583
- return 1 ;
4584
- }
4585
-
4586
- stack_size = zend_jit_traces [trace_num ].exit_info [exit_num ].stack_size ;
4587
- stack = zend_jit_traces [trace_num ].stack_map + zend_jit_traces [trace_num ].exit_info [exit_num ].stack_offset ;
4588
- return zend_jit_trace_stack_needs_deoptimization (stack , stack_size );
4589
- }
4590
-
4591
4642
static const void * zend_jit_trace_exit_to_vm (uint32_t trace_num , uint32_t exit_num )
4592
4643
{
4593
4644
const void * handler = NULL ;
4594
4645
dasm_State * dasm_state = NULL ;
4595
4646
void * checkpoint ;
4596
4647
char name [32 ];
4597
4648
const zend_op * opline ;
4598
- uint32_t i , stack_size ;
4649
+ uint32_t stack_size ;
4599
4650
zend_jit_trace_stack * stack ;
4600
4651
zend_bool original_handler = 0 ;
4601
4652
@@ -4614,46 +4665,18 @@ static const void *zend_jit_trace_exit_to_vm(uint32_t trace_num, uint32_t exit_n
4614
4665
zend_jit_align_func (& dasm_state );
4615
4666
4616
4667
/* Deoptimization */
4617
- if (zend_jit_traces [trace_num ].exit_info [exit_num ].flags & ZEND_JIT_EXIT_RESTORE_CALL ) {
4618
- zend_jit_save_call_chain (& dasm_state , -1 );
4619
- }
4620
4668
stack_size = zend_jit_traces [trace_num ].exit_info [exit_num ].stack_size ;
4621
4669
stack = zend_jit_traces [trace_num ].stack_map + zend_jit_traces [trace_num ].exit_info [exit_num ].stack_offset ;
4622
- for (i = 0 ; i < stack_size ; i ++ ) {
4623
- if (STACK_REG (stack , i ) != ZREG_NONE ) {
4624
- if (STACK_REG (stack , i ) < ZREG_NUM ) {
4625
- if (!zend_jit_store_var (& dasm_state , 1 << STACK_TYPE (stack , i ), i , STACK_REG (stack , i ))) {
4626
- goto jit_failure ;
4627
- }
4628
- } else if (STACK_REG (stack , i ) == ZREG_THIS ) {
4629
- if (!zend_jit_load_this (& dasm_state , EX_NUM_TO_VAR (i ))) {
4630
- goto jit_failure ;
4631
- }
4632
- } else {
4633
- if (!zend_jit_store_const (& dasm_state , i , STACK_REG (stack , i ))) {
4634
- goto jit_failure ;
4635
- }
4636
- }
4637
- }
4670
+
4671
+ if (!zend_jit_trace_deoptimization (& dasm_state ,
4672
+ zend_jit_traces [trace_num ].exit_info [exit_num ].flags ,
4673
+ zend_jit_traces [trace_num ].exit_info [exit_num ].opline ,
4674
+ stack , stack_size , NULL , NULL )) {
4675
+ goto jit_failure ;
4638
4676
}
4639
4677
4640
4678
opline = zend_jit_traces [trace_num ].exit_info [exit_num ].opline ;
4641
4679
if (opline ) {
4642
- if (zend_jit_traces [trace_num ].exit_info [exit_num ].flags & ZEND_JIT_EXIT_FREE_OP2 ) {
4643
- if (!zend_jit_free_op (& dasm_state , (opline - 1 ), -1 , (opline - 1 )-> op2 .var )) {
4644
- goto jit_failure ;
4645
- }
4646
- }
4647
- if (zend_jit_traces [trace_num ].exit_info [exit_num ].flags & ZEND_JIT_EXIT_FREE_OP1 ) {
4648
- if (!zend_jit_free_op (& dasm_state , (opline - 1 ), -1 , (opline - 1 )-> op1 .var )) {
4649
- goto jit_failure ;
4650
- }
4651
- }
4652
- if (zend_jit_traces [trace_num ].exit_info [exit_num ].flags & (ZEND_JIT_EXIT_FREE_OP1 |ZEND_JIT_EXIT_FREE_OP2 )) {
4653
- if (!zend_jit_check_exception (& dasm_state )) {
4654
- goto jit_failure ;
4655
- }
4656
- }
4657
4680
zend_jit_set_ip (& dasm_state , opline );
4658
4681
if (opline == zend_jit_traces [zend_jit_traces [trace_num ].root ].opline ) {
4659
4682
/* prevent endless loop */
0 commit comments