[xdebug-dev] xdebug xdebug/xdebug_code_coverage.c xdebug/xdebug_code_coverage.h - Added a check which will eliminate some edge cases when only a single semicolon is used in a decision like for(%$....) if (foor) then bar.

From: Allister Beharry <allister.beharry[@]gmail.com>
Date: Mon, 20 Jul 2009 12:34:39 +0200

Date: Mon Jul 20 12:34:39 CEST 2009
User: Allister Beharry
Directory: xdebug

Log Message:
[2.1-dev]
- Added a check which will eliminate some edge cases when only a single semicolon is used in a decision like for(%$....) if (foor) then bar.
- Fixed bug in counting lines.
- Build basic blocks info and store it in a global.
-
Modified files:
           xdebug/xdebug_code_coverage.c (version: 1.53.4.4)
           xdebug/xdebug_code_coverage.h (version: 1.13.4.3)

[FILE: /xdebug/xdebug_code_coverage.c]

===================================================================
RCS file: cvstemp,v
retrieving revision 1.53.4.3
retrieving revision 1.53.4.4
diff -u -r1.53.4.3 -r1.53.4.4
--- xdebug/xdebug_code_coverage.c:1.53.4.3 Sat Jul 18 17:26:33 2009 GMT
+++ xdebug/xdebug_code_coverage.c Mon Jul 20 08:34:39 2009 GMT
@@ -23,10 +23,11 @@
 #include "xdebug_code_coverage.h"
 #include "xdebug_compat.h"
 #include "srm_oparray.h"
-
-extern ZEND_DECLARE_MODULE_GLOBALS(xdebug);
+#include "bytekit.h"
 
 extern const op_usage opcodes[];
+extern void bytekit_build_basic_blocks(zval *return_value, zend_op_array *ops, long flags TSRMLS_DC);
+extern ZEND_DECLARE_MODULE_GLOBALS(xdebug);
 
 void xdebug_coverage_decision_dtor(void *data)
 {
@@ -63,6 +64,8 @@
 void xdebug_coverage_function_dtor(void *data)
 {
  xdebug_coverage_function *function = (xdebug_coverage_function *) data;
+ xdfree(function->name);
+ xdfree(function->filename);
  xdebug_hash_destroy(function->lines);
  xdebug_hash_destroy(function->decisions);
  xdebug_set_free(function->total_branches_set);
@@ -93,8 +96,8 @@
  char *function_name;
  fprintf(stderr, "XDEBUG_CC: xdebug_count_instruction: starting...sline = %s sposition = %s filename = %s \n", sline, sposition, filename);
  if (op_array->type == ZEND_USER_FUNCTION) {
- if (op_array->function_name == NULL)
- function_name = "0" ;
+ if ((op_array->function_name == NULL) || (op_array->function_name == 0))
+ function_name = "_main" ;
    else
      function_name = op_array->function_name ;
    fprintf(stderr, "XDEBUG_CC: xdebug_count_instruction: setting function name to %s...\n", function_name);
@@ -137,11 +140,25 @@
  if (instruction->executed == 0) instruction->executed = 1;
  line->instructions_counted++;
 
- if (instruction->count > line->count)
+ if ((position_in_line == 0) &&
+ (
+ op->opcode == ZEND_JMP ||
+ op->opcode == ZEND_JMPZ ||
+ op->opcode == ZEND_JMPNZ ||
+ op->opcode == ZEND_JMPZ_EX ||
+ op->opcode == ZEND_JMPNZ_EX ||
+ op->opcode == ZEND_JMPZNZ
+ ));
+ else
  {
- line->count = instruction->count;
- file_line->count = instruction->count;
+ if (instruction->count > line->count)
+ {
+ line->count = instruction->count;
+ file_line->count = instruction->count;
+ }
  }
+
+
  if (instruction->position == (line->total_instructions - 1)) /*end of instructions for line*/
  {
   /*only set the executed flag when the final instruction executes*/
@@ -173,6 +190,8 @@
   xdebug_coverage_instruction *instruction;
   xdebug_coverage_decision *decision;
   zend_op previous_op;
+ zval *basic_blocks_file, *basic_blocks_function;
+ zval **basic_blocks_file_P;
   int position_in_line;
   unsigned int jmp_position1 = 0, jmp_position2 = 0;
   char *function_name;
@@ -182,10 +201,10 @@
   int num_known_opcodes = sizeof(op_array) / sizeof(op_array[0]);
   /*fprintf(stderr, "XDEBUG_CC: prefill_from_opcode: starting...sline = %s sposition = %s filename = %s \n", sline, xdebug_sprintf("%d", position), filename);*/
  
- if (op_array->function_name == NULL)
- function_name = "0" ;
+ if ((op_array->function_name == NULL) || (op_array->function_name == 0))
+ function_name = "_main" ;
   else
- function_name = op_array->function_name ;
+ function_name = op_array->function_name;
   /*fprintf(stderr, "XDEBUG_CC: xdebug_prefill_opcode: setting function name to %s...\n", function_name);*/
 
                 /* Check if the file already exists in the hash */
@@ -199,6 +218,9 @@
     file->branches_counted = 0;
     fprintf(stderr, "XDEBUG_CC: xdebug_prefill_opcode: adding file with filename=%s to hash...\n", filename);
                   xdebug_hash_add(XG(code_coverage), filename, strlen(filename), file);
+ MAKE_STD_ZVAL(basic_blocks_file);
+ array_init(basic_blocks_file);
+ add_assoc_zval_ex(XG(code_coverage_basic_blocks), file->name, strlen(file->name) + 1, basic_blocks_file);
          }
 
   /* Check if the function already exists in the code coverage hash */
@@ -206,6 +228,7 @@
     *instructions_prefilled = 0;
     function = xdmalloc(sizeof(xdebug_coverage_function));
     function->name = xdstrdup(function_name);
+ function->filename = xdstrdup(filename);
     function->dead = 0;
     function->count = 0;
     function->executed = 0;
@@ -218,9 +241,19 @@
     function->branches_counted = 0;
     function->branches_counted_set = xdebug_set_create(op_array->last);
     fprintf(stderr, "XDEBUG_CC: xdebug_prefill_opcode: adding function with name=%s to hash...\n", function->name);
- xdebug_hash_add(file->functions, function_name, strlen(function_name), function);
- }
-
+ xdebug_hash_add(file->functions, function_name, strlen(function_name), function);
+ if (zend_hash_find(HASH_OF(XG(code_coverage_basic_blocks)), file->name, strlen(file->name) + 1, (void **) &basic_blocks_file_P) != SUCCESS) {
+ /*bailout: error*/
+ php_error(E_USER_ERROR, xdebug_sprintf("XDEBUG_CC: xdebug_prefill_opcode: could not find %s in basic blocks.", file->name));
+ return;
+ }
+ MAKE_STD_ZVAL(basic_blocks_function);
+ array_init(basic_blocks_function);
+ bytekit_build_basic_blocks(basic_blocks_function, op_array, 0 TSRMLS_CC);
+ fprintf(stderr, "XDEBUG_CC: xdebug_prefill_opcode: adding function with name=%s to basic blocks...\n", function->name);
+ add_assoc_zval_ex(*basic_blocks_file_P, function->name, strlen(function->name) + 1, basic_blocks_function);
+ }
+
          /* Check if the line already exists in the function hash */
          if (!xdebug_hash_find(function->lines, sline, strlen(sline), (void *) &line)) {
            *instructions_prefilled = position;
@@ -581,6 +614,9 @@
         }
         XG(code_coverage_unused) = (options & XDEBUG_CC_OPTION_UNUSED);
         XG(code_coverage_dead_code_analysis) = (options & XDEBUG_CC_OPTION_DEAD_CODE);
+ XG(code_coverage_line_coverage_ex) = (options & XDEBUG_CC_OPTION_LINE_COVERAGE_EX);
+ XG(code_coverage_branch_coverage) = (options & XDEBUG_CC_OPTION_BRANCH_COVERAGE);
+ XG(code_coverage_dump_instructions) = (options & XDEBUG_CC_OPTION_DUMP_INSTRUCTIONS);
 
         if (XG(extended_info)) {
                 RETVAL_BOOL(!XG(do_code_coverage));
@@ -644,78 +680,149 @@
 
 static void add_line(void *ret, xdebug_hash_element *e)
 {
- xdebug_coverage_line *line = (xdebug_coverage_line*) e->ptr;
- zval *retval = (zval*) ret;
+ xdebug_coverage_line *line = (xdebug_coverage_line*) e->ptr;
+ zval *retval = (zval*) ret;
  zval *instructions;
  zval *line_zval;
- HashTable *target_hash;
+ HashTable *target_hash;
  
  TSRMLS_FETCH();
- MAKE_STD_ZVAL(line_zval);
- MAKE_STD_ZVAL(instructions);
- array_init(line_zval);
- array_init(instructions);
+
+ if (!XG(code_coverage_line_coverage_ex) && !XG(code_coverage_dump_instructions))
+ {
+ /*add_index_long(retval, line->lineno, line->executed ? line->count : 0);*/
+ add_index_long(retval, line->lineno, line->count);
+ }
+ else
+ {
+ MAKE_STD_ZVAL(line_zval);
+ array_init(line_zval);
+ add_assoc_long(line_zval, "lineno", line->lineno);
+ add_assoc_long(line_zval, "count", line->count);
+ add_assoc_long(line_zval, "executed", line->executed);
+ add_assoc_long(line_zval, "dead", line->dead);
+}
  
- xdebug_hash_apply(line->instructions, (void *) instructions, add_instruction);
- /* Sort instructions on position */
- target_hash = HASH_OF(instructions);
- zend_hash_sort(target_hash, zend_qsort, xdebug_lineno_cmp, 0 TSRMLS_CC);
- add_assoc_long(line_zval, "lineno", line->lineno);
- add_assoc_long(line_zval, "count", line->count);
- add_assoc_long(line_zval, "executed", line->executed);
- add_assoc_long(line_zval, "dead", line->dead);
+ if (XG(code_coverage_dump_instructions))
+ {
+ MAKE_STD_ZVAL(instructions);
+ array_init(instructions);
+ xdebug_hash_apply(line->instructions, (void *) instructions, add_instruction);
+ /* Sort instructions on position */
+ target_hash = HASH_OF(instructions);
+ zend_hash_sort(target_hash, zend_qsort, xdebug_lineno_cmp, 0 TSRMLS_CC);
+ add_assoc_zval(line_zval, "instructions", instructions);
+ }
  
- add_assoc_zval(line_zval, "instructions", instructions);
- add_index_zval(retval, line->lineno, line_zval);
+ if (XG(code_coverage_line_coverage_ex) || XG(code_coverage_dump_instructions)) add_index_zval(retval, line->lineno, line_zval);
 }
 
 static void add_cc_function(void *ret, xdebug_hash_element *e)
 {
- xdebug_coverage_function *function = (xdebug_coverage_function*) e->ptr;
- zval *retval = (zval*) ret;
- zval *lines;
+ xdebug_coverage_function *function = (xdebug_coverage_function*) e->ptr;
+ zval *retval = (zval*) ret;
+ zval *lines;
  zval *function_zval;
- TSRMLS_FETCH();
+ zval **file_P;
+ zval **basic_blocks_function_P;
  HashTable *target_hash;
 
- MAKE_STD_ZVAL(lines);
- array_init(lines);
+ TSRMLS_FETCH();
+ MAKE_STD_ZVAL(lines);
+ array_init(lines);
  MAKE_STD_ZVAL(function_zval);
  array_init(function_zval);
 
-
  xdebug_hash_apply(function->lines, (void *) lines, add_line);
-
         /* Sort on linenumber */
- target_hash = HASH_OF(lines);
- zend_hash_sort(target_hash, zend_qsort, xdebug_lineno_cmp, 0 TSRMLS_CC);
+ target_hash = HASH_OF(lines);
+ zend_hash_sort(target_hash, zend_qsort, xdebug_lineno_cmp, 0 TSRMLS_CC);
 
         /* Add all the lines */
  add_assoc_zval_ex(function_zval, "lines", strlen("lines") + 1, lines);
- add_assoc_long(function_zval, "total_branches", function->total_branches);
- add_assoc_long(function_zval, "branches_counted", function->branches_counted);
- add_assoc_zval_ex(retval, function->name, strlen(function->name) + 1, function_zval);
+
+ //if (XG(code_coverage_branch_coverage)) add_assoc_zval_ex(function_zval, "basic blocks", strlen("basic blocks") + 1, XG(code_coverage_basic_blocks));
+ if (XG(code_coverage_branch_coverage))
+ {
+ add_assoc_long(function_zval, "total_branches", function->total_branches);
+ add_assoc_long(function_zval, "branches_counted", function->branches_counted);
+ if (zend_hash_find(HASH_OF(XG(code_coverage_basic_blocks)), function->filename, strlen(function->filename) + 1, (void **) &file_P) != SUCCESS)
+ {
+ /*bailout: error*/
+ php_error(E_USER_ERROR, xdebug_sprintf("XDEBUG_CC: add_cc_function: could not find file %s in basic blocks.", function->filename));
+ return;
+ }
+ if (zend_hash_find(HASH_OF(*file_P), function->name, strlen(function->name) + 1, (void **) &basic_blocks_function_P) != SUCCESS)
+ {
+ /*bailout: error*/
+ php_error(E_USER_ERROR, xdebug_sprintf("XDEBUG_CC: add_cc_function: could not find function %s in basic blocks.", function->name));
+ return;
+ }
+ add_assoc_zval_ex(function_zval, "basic blocks", strlen("basic blocks") + 1, *basic_blocks_function_P);
+ }
+
+ add_assoc_zval_ex(retval, function->name, strlen(function->name) + 1, function_zval);
 }
 
 static void add_file(void *ret, xdebug_hash_element *e)
 {
  xdebug_coverage_file *file = (xdebug_coverage_file*) e->ptr;
- zval *retval = (zval*) ret;
- zval *functions;
- TSRMLS_FETCH();
-
+ zval *retval = (zval*) ret;
+ zval *file_zval;
+ zval *functions;
+ zval *lines;
+ zval **file_basic_blocks_P;
+ HashTable *target_hash;
+
+ TSRMLS_FETCH();
+ MAKE_STD_ZVAL(file_zval);
+ array_init(file_zval);
+ if (XG(code_coverage_dump_instructions))
+ {
         MAKE_STD_ZVAL(functions);
         array_init(functions);
-
         /* Add all the functions */
         xdebug_hash_apply(file->functions, (void *) functions, add_cc_function);
- add_assoc_zval_ex(retval, file->name, strlen(file->name) + 1, functions);
+ if (XG(code_coverage_branch_coverage))
+ {
+ add_assoc_zval_ex(file_zval, "functions", strlen("functions") + 1, functions);
+ if (zend_hash_find(HASH_OF(XG(code_coverage_basic_blocks)), file->name, strlen(file->name) + 1, (void **) &file_basic_blocks_P) != SUCCESS)
+ {
+ /*bailout: error*/
+ php_error(E_USER_ERROR, xdebug_sprintf("XDEBUG_CC: add_file: could not find file %s in basic blocks hash.", file->name));
+ return;
+ }
+ add_assoc_zval_ex(file_zval, "basic blocks", strlen("basic blocks") + 1, *file_basic_blocks_P);
+ add_assoc_zval_ex(retval, file->name, strlen(file->name) + 1, file_zval);
+ }
+ else
+ {
+ add_assoc_zval_ex(retval, file->name, strlen(file->name) + 1, functions);
+ }
+ }
+ else
+ {
+ MAKE_STD_ZVAL(lines);
+ array_init(lines);
+ xdebug_hash_apply(file->lines, (void *) lines, add_line);
+ /* Sort on line number */
+ target_hash = HASH_OF(lines);
+ zend_hash_sort(target_hash, zend_qsort, xdebug_lineno_cmp, 0 TSRMLS_CC);
+ if (XG(code_coverage_branch_coverage))
+ {
+ add_assoc_zval_ex(file_zval, "lines", strlen("lines") + 1, lines);
+ add_assoc_long(file_zval, "total branches", file->total_branches);
+ add_assoc_long(file_zval, "branches counted", file->branches_counted);
+ add_assoc_zval_ex(retval, file->name, strlen(file->name) + 1, file_zval);
+ }
+ else add_assoc_zval_ex(retval, file->name, strlen(file->name) + 1, lines);
+ }
 }
 
 PHP_FUNCTION(xdebug_get_code_coverage)
 {
- array_init(return_value);
- xdebug_hash_apply(XG(code_coverage), (void *) return_value, add_file);
+ array_init(return_value);
+ xdebug_hash_apply(XG(code_coverage), (void *) return_value, add_file);
 }
 
 PHP_FUNCTION(xdebug_get_function_count)

[FILE: /xdebug/xdebug_code_coverage.h]

===================================================================
RCS file: cvstemp,v
retrieving revision 1.13.4.2
retrieving revision 1.13.4.3
diff -u -r1.13.4.2 -r1.13.4.3
--- xdebug/xdebug_code_coverage.h:1.13.4.2 Sat Jul 18 17:26:33 2009 GMT
+++ xdebug/xdebug_code_coverage.h Mon Jul 20 08:34:39 2009 GMT
@@ -23,7 +23,6 @@
 #include "xdebug_hash.h"
 #include "xdebug_mm.h"
 #include "xdebug_set.h"
-#include "srm_oparray.h"
 
 typedef struct xdebug_coverage_decision
 {
@@ -77,6 +76,7 @@
 typedef struct xdebug_coverage_function
 {
  char *name;
+ char *filename;
  int dead;
  int count;
  int executed;
Received on Mon Jul 20 2009 - 12:34:44 BST

This archive was generated by hypermail 2.2.0 : Sun Jun 24 2018 - 04:00:03 BST