@@ -457,7 +457,7 @@ static int zend_jit_trace_bad_loop_exit(const zend_op *opline)
457457 return 0 ;
458458}
459459
460- static int zend_jit_trace_record_fake_init_call (zend_execute_data * call , zend_jit_trace_rec * trace_buffer , int idx )
460+ static int zend_jit_trace_record_fake_init_call_ex (zend_execute_data * call , zend_jit_trace_rec * trace_buffer , int idx , zend_bool is_megamorphic , uint32_t * megamorphic , uint32_t level , uint32_t * call_level )
461461{
462462 zend_jit_trace_stop stop ZEND_ATTRIBUTE_UNUSED = ZEND_JIT_TRACE_STOP_ERROR ;
463463
@@ -466,7 +466,10 @@ static int zend_jit_trace_record_fake_init_call(zend_execute_data *call, zend_ji
466466 zend_jit_op_array_trace_extension * jit_extension ;
467467
468468 if (call -> prev_execute_data ) {
469- idx = zend_jit_trace_record_fake_init_call (call -> prev_execute_data , trace_buffer , idx );
469+ idx = zend_jit_trace_record_fake_init_call_ex (call -> prev_execute_data , trace_buffer , idx , is_megamorphic , megamorphic , level , call_level );
470+ if (idx < 0 ) {
471+ return idx ;
472+ }
470473 }
471474
472475 func = call -> func ;
@@ -483,11 +486,39 @@ static int zend_jit_trace_record_fake_init_call(zend_execute_data *call, zend_ji
483486 }
484487 func = (zend_function * )jit_extension -> op_array ;
485488 }
489+ if (is_megamorphic
490+ /* TODO: use more accurate check ??? */
491+ && ((ZEND_CALL_INFO (call ) & ZEND_CALL_DYNAMIC )
492+ || func -> common .scope )) {
493+ func = NULL ;
494+ * megamorphic |= (1 << (level + * call_level ));
495+ } else {
496+ * megamorphic &= ~(1 << (level + * call_level ));
497+ }
498+ (* call_level )++ ;
486499 TRACE_RECORD (ZEND_JIT_TRACE_INIT_CALL , ZEND_JIT_TRACE_FAKE_INIT_CALL , func );
487500 } while (0 );
488501 return idx ;
489502}
490503
504+ static int zend_jit_trace_record_fake_init_call (zend_execute_data * call , zend_jit_trace_rec * trace_buffer , int idx , zend_bool is_megamorphic , uint32_t * megamorphic , uint32_t level )
505+ {
506+ uint32_t call_level = 0 ;
507+
508+ return zend_jit_trace_record_fake_init_call_ex (call , trace_buffer , idx , is_megamorphic , megamorphic , level , & call_level );
509+ }
510+
511+ static int zend_jit_trace_call_level (const zend_execute_data * call )
512+ {
513+ int call_level = 0 ;
514+
515+ while (call -> prev_execute_data ) {
516+ call_level ++ ;
517+ call = call -> prev_execute_data ;
518+ }
519+ return call_level ;
520+ }
521+
491522/*
492523 * Trace Linking Rules
493524 * ===================
@@ -518,7 +549,8 @@ static int zend_jit_trace_record_fake_init_call(zend_execute_data *call, zend_ji
518549 *
519550 */
520551
521- zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute (zend_execute_data * ex , const zend_op * op , zend_jit_trace_rec * trace_buffer , uint8_t start )
552+ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute (zend_execute_data * ex , const zend_op * op , zend_jit_trace_rec * trace_buffer , uint8_t start , zend_bool is_megamorphic )
553+
522554{
523555#ifdef HAVE_GCC_GLOBAL_REGS
524556 zend_execute_data * save_execute_data = execute_data ;
@@ -528,6 +560,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
528560 zend_jit_trace_stop stop = ZEND_JIT_TRACE_STOP_ERROR ;
529561 int level = 0 ;
530562 int ret_level = 0 ;
563+ int call_level ;
531564 zend_vm_opcode_handler_t handler ;
532565 const zend_op_array * op_array ;
533566 zend_jit_op_array_trace_extension * jit_extension ;
@@ -539,6 +572,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
539572 int backtrack_ret_recursion = -1 ;
540573 int backtrack_ret_recursion_level = 0 ;
541574 int loop_unroll_limit = 0 ;
575+ uint32_t megamorphic = 0 ;
542576 const zend_op_array * unrolled_calls [ZEND_JIT_TRACE_MAX_CALL_DEPTH + ZEND_JIT_TRACE_MAX_RET_DEPTH ];
543577#ifdef HAVE_GCC_GLOBAL_REGS
544578 zend_execute_data * prev_execute_data = ex ;
@@ -571,7 +605,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
571605 TRACE_START (ZEND_JIT_TRACE_START , start , op_array , opline );
572606
573607 if (prev_call ) {
574- int ret = zend_jit_trace_record_fake_init_call (prev_call , trace_buffer , idx );
608+ int ret = zend_jit_trace_record_fake_init_call (prev_call , trace_buffer , idx , is_megamorphic , & megamorphic , ret_level + level );
575609 if (ret < 0 ) {
576610 return ZEND_JIT_TRACE_STOP_BAD_FUNC ;
577611 }
@@ -665,17 +699,18 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
665699 TRACE_RECORD (ZEND_JIT_TRACE_OP2_TYPE , 0 , ce2 );
666700 }
667701
668- switch (opline -> opcode ) {
669- case ZEND_DO_FCALL :
670- case ZEND_DO_ICALL :
671- case ZEND_DO_UCALL :
672- case ZEND_DO_FCALL_BY_NAME :
673- if (EX (call )-> func -> type == ZEND_INTERNAL_FUNCTION ) {
674- TRACE_RECORD (ZEND_JIT_TRACE_DO_ICALL , 0 , EX (call )-> func );
675- }
676- break ;
677- default :
702+ if (opline -> opcode == ZEND_DO_FCALL
703+ || opline -> opcode == ZEND_DO_ICALL
704+ || opline -> opcode == ZEND_DO_UCALL
705+ || opline -> opcode == ZEND_DO_FCALL_BY_NAME ) {
706+ call_level = zend_jit_trace_call_level (EX (call ));
707+ if (megamorphic & (1 << (ret_level + level + call_level ))) {
708+ stop = ZEND_JIT_TRACE_STOP_INTERPRETER ;
678709 break ;
710+ }
711+ if (EX (call )-> func -> type == ZEND_INTERNAL_FUNCTION ) {
712+ TRACE_RECORD (ZEND_JIT_TRACE_DO_ICALL , 0 , EX (call )-> func );
713+ }
679714 }
680715
681716 handler = (zend_vm_opcode_handler_t )ZEND_OP_TRACE_INFO (opline , offset )-> call_handler ;
@@ -779,7 +814,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
779814 ret_level ++ ;
780815
781816 if (prev_call ) {
782- int ret = zend_jit_trace_record_fake_init_call (prev_call , trace_buffer , idx );
817+ int ret = zend_jit_trace_record_fake_init_call (prev_call , trace_buffer , idx , 0 , & megamorphic , ret_level + level );
783818 if (ret < 0 ) {
784819 stop = ZEND_JIT_TRACE_STOP_BAD_FUNC ;
785820 break ;
@@ -827,6 +862,22 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
827862 }
828863 func = (zend_function * )jit_extension -> op_array ;
829864 }
865+
866+ #ifndef HAVE_GCC_GLOBAL_REGS
867+ opline = EX (opline );
868+ #endif
869+
870+ if (JIT_G (max_polymorphic_calls ) == 0
871+ && zend_jit_may_be_polymorphic_call (opline - 1 )) {
872+ func = NULL ;
873+ }
874+ call_level = zend_jit_trace_call_level (EX (call ));
875+ ZEND_ASSERT (ret_level + level + call_level < 32 );
876+ if (func ) {
877+ megamorphic &= ~(1 << (ret_level + level + call_level ));
878+ } else {
879+ megamorphic |= (1 << (ret_level + level + call_level ));
880+ }
830881 TRACE_RECORD (ZEND_JIT_TRACE_INIT_CALL , 0 , func );
831882 }
832883 prev_call = EX (call );
0 commit comments