@@ -503,6 +503,15 @@ static int zend_jit_trace_call_level(const zend_execute_data *call)
503
503
return call_level ;
504
504
}
505
505
506
+ static int zend_jit_trace_subtrace (zend_jit_trace_rec * trace_buffer , int start , int end , uint8_t event , const zend_op_array * op_array , const zend_op * opline )
507
+ {
508
+ int idx ;
509
+
510
+ TRACE_START (ZEND_JIT_TRACE_START , event , op_array , opline );
511
+ memmove (trace_buffer + idx , trace_buffer + start , (end - start ) * sizeof (zend_jit_trace_rec ));
512
+ return idx + (end - start );
513
+ }
514
+
506
515
/*
507
516
* Trace Linking Rules
508
517
* ===================
@@ -559,6 +568,9 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
559
568
int backtrack_ret_recursion = -1 ;
560
569
int backtrack_ret_recursion_level = 0 ;
561
570
int loop_unroll_limit = 0 ;
571
+ int last_loop = -1 ;
572
+ int last_loop_level = -1 ;
573
+ const zend_op * last_loop_opline = NULL ;
562
574
uint32_t megamorphic = 0 ;
563
575
const zend_op_array * unrolled_calls [ZEND_JIT_TRACE_MAX_CALL_DEPTH + ZEND_JIT_TRACE_MAX_RET_DEPTH ];
564
576
#ifdef HAVE_GCC_GLOBAL_REGS
@@ -832,6 +844,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
832
844
833
845
unrolled_calls [ret_level ] = & EX (func )-> op_array ;
834
846
ret_level ++ ;
847
+ last_loop_opline = NULL ;
835
848
836
849
if (prev_call ) {
837
850
int ret = zend_jit_trace_record_fake_init_call (prev_call , trace_buffer , idx , 0 , & megamorphic , ret_level + level );
@@ -854,6 +867,9 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
854
867
}
855
868
} else {
856
869
level -- ;
870
+ if (level < last_loop_level ) {
871
+ last_loop_opline = NULL ;
872
+ }
857
873
TRACE_RECORD (ZEND_JIT_TRACE_BACK , 0 , op_array );
858
874
}
859
875
}
@@ -960,24 +976,44 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
960
976
stop = ZEND_JIT_TRACE_STOP_BLACK_LIST ;
961
977
break ;
962
978
} else if (trace_flags & ZEND_JIT_TRACE_START_LOOP ) {
963
- if (start != ZEND_JIT_TRACE_START_SIDE ) {
964
- uint8_t bad_stop ;
979
+ uint8_t bad_stop ;
965
980
981
+ if (start != ZEND_JIT_TRACE_START_SIDE ) {
966
982
if (opline == orig_opline && level + ret_level == 0 ) {
967
983
stop = ZEND_JIT_TRACE_STOP_LOOP ;
968
984
break ;
969
985
}
970
- /* Fail to try creating a trace for inner loop first.
971
- If this doesn't work try unroling loop. */
986
+ }
987
+
988
+ if (start != ZEND_JIT_TRACE_START_SIDE
989
+ || level + ret_level != 0 ) {
990
+ /* First try creating a trace for inner loop.
991
+ If this doesn't work try loop unroling. */
972
992
bad_stop = zend_jit_trace_bad_stop_event (opline ,
973
993
JIT_G (blacklist_root_trace ) / 2 );
974
994
if (bad_stop != ZEND_JIT_TRACE_STOP_INNER_LOOP
975
995
&& bad_stop != ZEND_JIT_TRACE_STOP_LOOP_EXIT ) {
976
- stop = ZEND_JIT_TRACE_STOP_INNER_LOOP ;
977
- break ;
996
+ if (start == ZEND_JIT_TRACE_START_SIDE
997
+ || zend_jit_trace_bad_stop_event (orig_opline ,
998
+ JIT_G (blacklist_root_trace ) / 2 ) != ZEND_JIT_TRACE_STOP_INNER_LOOP ) {
999
+ stop = ZEND_JIT_TRACE_STOP_INNER_LOOP ;
1000
+ break ;
1001
+ }
978
1002
}
979
1003
}
980
- if (loop_unroll_limit < JIT_G (max_loops_unroll )) {
1004
+
1005
+ if (opline == last_loop_opline
1006
+ && level == last_loop_level ) {
1007
+ idx = zend_jit_trace_subtrace (trace_buffer ,
1008
+ last_loop , idx , ZEND_JIT_TRACE_START_LOOP , op_array , opline );
1009
+ start = ZEND_JIT_TRACE_START_LOOP ;
1010
+ stop = ZEND_JIT_TRACE_STOP_LOOP ;
1011
+ ret_level = 0 ;
1012
+ break ;
1013
+ } else if (loop_unroll_limit < JIT_G (max_loops_unroll )) {
1014
+ last_loop = idx ;
1015
+ last_loop_opline = opline ;
1016
+ last_loop_level = level ;
981
1017
loop_unroll_limit ++ ;
982
1018
} else {
983
1019
stop = ZEND_JIT_TRACE_STOP_LOOP_UNROLL ;
0 commit comments