11/*
22 +----------------------------------------------------------------------+
3- | Copyright (c) 1997-2020 Derick Rethans |
3+ | Copyright (c) 1997-2025 Derick Rethans |
44 +----------------------------------------------------------------------+
55 | This source file is subject to the 2-Clause BSD license which is |
66 | available through the LICENSE file, or online at |
@@ -33,6 +33,7 @@ xdebug_branch_info *xdebug_branch_info_create(unsigned int size)
3333 tmp -> path_info .paths_count = 0 ;
3434 tmp -> path_info .paths_size = 0 ;
3535 tmp -> path_info .paths = NULL ;
36+ tmp -> highest_out = 0 ;
3637
3738 return tmp ;
3839}
@@ -249,7 +250,7 @@ static void xdebug_branch_find_path(unsigned int nr, xdebug_branch_info *branch_
249250 int found = 0 ;
250251 size_t i = 0 ;
251252
252- if (branch_info -> path_info .paths_count > 4095 ) {
253+ if (branch_info -> path_info .paths_count >= XDEBUG_MAX_PATHS ) {
253254 return ;
254255 }
255256
@@ -335,23 +336,36 @@ void xdebug_branch_find_paths(xdebug_branch_info *branch_info)
335336 }
336337}
337338
339+ static int fetch_mark_file (zend_string * filename , xdebug_coverage_file * * file )
340+ {
341+ if (XG_COV (previous_mark_filename ) && zend_string_equals (XG_COV (previous_mark_filename ), filename )) {
342+ * file = XG_COV (previous_mark_file );
343+ return 1 ;
344+ }
345+
346+ if (!xdebug_hash_find (XG_COV (info ), ZSTR_VAL (filename ), ZSTR_LEN (filename ), (void * ) file )) {
347+ return 0 ;
348+ }
349+
350+ if (XG_COV (previous_mark_filename )) {
351+ zend_string_release (XG_COV (previous_mark_filename ));
352+ }
353+ XG_COV (previous_mark_filename ) = zend_string_copy ((* file )-> name );
354+ XG_COV (previous_mark_file ) = * file ;
355+
356+ return 1 ;
357+ }
358+
338359void xdebug_branch_info_mark_reached (zend_string * filename , char * function_name , zend_op_array * op_array , long opcode_nr )
339360{
340361 xdebug_coverage_file * file ;
341- xdebug_coverage_function * function ;
362+ xdebug_coverage_analysis_function * analysis_function = NULL ;
363+ xdebug_coverage_runtime_function * runtime_function ;
342364 xdebug_branch_info * branch_info ;
343365
344- if (XG_COV (previous_mark_filename ) && zend_string_equals (XG_COV (previous_mark_filename ), filename )) {
345- file = XG_COV (previous_mark_file );
346- } else {
347- if (!xdebug_hash_find (XG_COV (code_coverage_info ), ZSTR_VAL (filename ), ZSTR_LEN (filename ), (void * ) & file )) {
348- return ;
349- }
350- if (XG_COV (previous_mark_filename )) {
351- zend_string_release (XG_COV (previous_mark_filename ));
352- }
353- XG_COV (previous_mark_filename ) = zend_string_copy (file -> name );
354- XG_COV (previous_mark_file ) = file ;
366+ /* Find the information for the given filename */
367+ if (!fetch_mark_file (filename , & file )) {
368+ return ;
355369 }
356370
357371 /* If there is no branch info, we don't have to do more */
@@ -360,11 +374,17 @@ void xdebug_branch_info_mark_reached(zend_string *filename, char *function_name,
360374 }
361375
362376 /* Check if the function already exists in the hash */
363- if (!xdebug_hash_find (file -> functions , function_name , strlen (function_name ), (void * ) & function )) {
377+ if (!xdebug_hash_find (file -> analysis . functions , function_name , strlen (function_name ), (void * ) & analysis_function )) {
364378 return ;
365379 }
366380
367- branch_info = function -> branch_info ;
381+ /* Find the runtime function, and if it does not exist, create it */
382+ if (!xdebug_hash_find (file -> runtime .functions , function_name , strlen (function_name ), (void * ) & runtime_function )) {
383+ runtime_function = xdebug_coverage_runtime_function_ctor (function_name , analysis_function );
384+ xdebug_hash_add (file -> runtime .functions , function_name , strlen (function_name ), runtime_function );
385+ }
386+
387+ branch_info = analysis_function -> branch_info ;
368388
369389 if (opcode_nr != 0 && xdebug_set_in (branch_info -> entry_points , opcode_nr )) {
370390 xdebug_code_coverage_end_of_function (op_array , filename , function_name );
@@ -382,7 +402,8 @@ void xdebug_branch_info_mark_reached(zend_string *filename, char *function_name,
382402
383403 for (i = 0 ; i < branch_info -> branches [XG_COV (branches ).last_branch_nr [XDEBUG_VECTOR_COUNT (XG_BASE (stack ))]].outs_count ; i ++ ) {
384404 if (branch_info -> branches [XG_COV (branches ).last_branch_nr [XDEBUG_VECTOR_COUNT (XG_BASE (stack ))]].outs [i ] == opcode_nr ) {
385- branch_info -> branches [XG_COV (branches ).last_branch_nr [XDEBUG_VECTOR_COUNT (XG_BASE (stack ))]].outs_hit [i ] = 1 ;
405+ //printf("\nOUT HIT: %p (%d) (*%ld) %ld\n", runtime_function->hit_branch, XG_COV(branches).last_branch_nr[XDEBUG_VECTOR_COUNT(XG_BASE(stack))], branch_info->highest_out, i + 1);
406+ xdebug_set_add (runtime_function -> hit_branch , (XG_COV (branches ).last_branch_nr [XDEBUG_VECTOR_COUNT (XG_BASE (stack ))] * (1 + branch_info -> highest_out )) + i + 1 );
386407 }
387408 }
388409 }
@@ -395,78 +416,65 @@ void xdebug_branch_info_mark_reached(zend_string *filename, char *function_name,
395416 }
396417 xdfree (key );
397418
398- branch_info -> branches [opcode_nr ].hit = 1 ;
419+ //printf("\nIN HIT: %p (%ld) (*%ld) %d\n", runtime_function->hit_branch, opcode_nr, branch_info->highest_out, 0);
420+ xdebug_set_add (runtime_function -> hit_branch , opcode_nr * (1 + branch_info -> highest_out ));
399421
400422 XG_COV (branches ).last_branch_nr [XDEBUG_VECTOR_COUNT (XG_BASE (stack ))] = opcode_nr ;
401423 }
402424}
403425
426+ /* TODO: Store paths hit differently */
404427void xdebug_branch_info_mark_end_of_function_reached (zend_string * filename , char * function_name , char * key , int key_len )
405428{
406429 xdebug_coverage_file * file ;
407- xdebug_coverage_function * function ;
408- xdebug_branch_info * branch_info ;
430+ xdebug_coverage_analysis_function * analysis_function ;
431+ xdebug_coverage_runtime_function * runtime_function ;
409432 xdebug_path * path ;
410433
411- if (XG_COV (previous_mark_filename ) && zend_string_equals (XG_COV (previous_mark_filename ), filename ) == 0 ) {
412- file = XG_COV (previous_mark_file );
413- } else {
414- if (!xdebug_hash_find (XG_COV (code_coverage_info ), ZSTR_VAL (filename ), ZSTR_LEN (filename ), (void * ) & file )) {
415- return ;
416- }
417- zend_string_release (XG_COV (previous_mark_filename ));
418- XG_COV (previous_mark_filename ) = zend_string_copy (file -> name );
419- XG_COV (previous_mark_file ) = file ;
434+ /* Find the information for the given filename */
435+ if (!fetch_mark_file (filename , & file )) {
436+ return ;
420437 }
421438
422439 /* If there is no branch info, we don't have to do more */
423440 if (!file -> has_branch_info ) {
424441 return ;
425442 }
426443
427- /* Check if the function already exists in the hash */
428- if (!xdebug_hash_find (file -> functions , function_name , strlen (function_name ), (void * ) & function )) {
444+ /* Check if the function has been analysed, and hence exists in the hash */
445+ if (!xdebug_hash_find (file -> analysis . functions , function_name , strlen (function_name ), (void * ) & analysis_function )) {
429446 return ;
430447 }
431448
432- branch_info = function -> branch_info ;
433-
434- if (!xdebug_hash_find (branch_info -> path_info .path_hash , key , key_len , (void * ) & path )) {
449+ /* Check whether we know something about the current path */
450+ if (!xdebug_hash_find (analysis_function -> branch_info -> path_info .path_hash , key , key_len , (void * ) & path )) {
435451 return ;
436452 }
437- path -> hit = 1 ;
438- }
439453
440- void xdebug_branch_info_add_branches_and_paths (zend_string * filename , char * function_name , xdebug_branch_info * branch_info )
441- {
442- xdebug_coverage_file * file ;
443- xdebug_coverage_function * function ;
454+ /* Find the runtime function, and if it does not exist, create it */
455+ if (!xdebug_hash_find (file -> runtime .functions , function_name , strlen (function_name ), (void * ) & runtime_function )) {
456+ runtime_function = xdebug_coverage_runtime_function_ctor (function_name , analysis_function );
457+ xdebug_hash_add (file -> runtime .functions , function_name , strlen (function_name ), runtime_function );
458+ }
444459
445- if (XG_COV (previous_filename ) && zend_string_equals (XG_COV (previous_filename ), filename ) == 0 ) {
446- file = XG_COV (previous_file );
447- } else {
448- /* Check if the file already exists in the hash */
449- if (!xdebug_hash_find (XG_COV (code_coverage_info ), ZSTR_VAL (filename ), ZSTR_LEN (filename ), (void * ) & file )) {
450- /* The file does not exist, so we add it to the hash */
451- file = xdebug_coverage_file_ctor (filename );
460+ xdebug_hash_add (runtime_function -> hit_paths , key , key_len , NULL );
461+ }
452462
453- xdebug_hash_add (XG_COV (code_coverage_info ), ZSTR_VAL (filename ), ZSTR_LEN (filename ), file );
454- }
455- zend_string_release (XG_COV (previous_filename ));
456- XG_COV (previous_filename ) = zend_string_copy (file -> name );
457- XG_COV (previous_file ) = file ;
458- }
463+ void xdebug_branch_info_add_branches_and_paths (xdebug_coverage_file * file , char * function_name , xdebug_branch_info * branch_info )
464+ {
465+ xdebug_coverage_analysis_function * analysis_function ;
459466
467+ /* TODO: Check if creating things here is actually useful */
460468 /* Check if the function already exists in the hash */
461- if (!xdebug_hash_find (file -> functions , function_name , strlen (function_name ), (void * ) & function )) {
462- /* The file does not exist, so we add it to the hash */
463- function = xdebug_coverage_function_ctor (function_name );
469+ if (!xdebug_hash_find (file -> analysis . functions , function_name , strlen (function_name ), (void * ) & analysis_function )) {
470+ /* The function does not exist, so we add it to the hash */
471+ analysis_function = xdebug_coverage_analysis_function_ctor (function_name );
464472
465- xdebug_hash_add (file -> functions , function_name , strlen (function_name ), function );
473+ xdebug_hash_add (file -> analysis . functions , function_name , strlen (function_name ), analysis_function );
466474 }
467475
468476 if (branch_info ) {
469477 file -> has_branch_info = 1 ;
470478 }
471- function -> branch_info = branch_info ;
479+ analysis_function -> branch_info = branch_info ;
472480}
0 commit comments