Date: Mon Sep 25 22:20:01 CEST 2006
User: Derick Rethans
Directory: xdebug
Log Message:
[12.00]
- Implemented dead code analysis that should give much better code coverage
results.
Modified files:
xdebug/config.m4 (version: 1.23)
xdebug/php_xdebug.h (version: 1.114)
xdebug/xdebug.c (version: 1.343)
xdebug/xdebug_code_coverage.c (version: 1.21)
xdebug/xdebug_code_coverage.h (version: 1.9)
xdebug/xdebug_private.h (version: 1.20)
Added files:
xdebug/xdebug_set.c (new version: 1.1)
xdebug/xdebug_set.h (new version: 1.1)
[FILE: /xdebug/xdebug_set.c]
/*
+----------------------------------------------------------------------+
| Xdebug |
+----------------------------------------------------------------------+
| Copyright (c) 2002, 2003, 2004, 2005, 2006 Derick Rethans |
+----------------------------------------------------------------------+
| This source file is subject to version 1.0 of the Xdebug license, |
| that is bundled with this package in the file LICENSE, and is |
| available at through the world-wide-web at |
| http://xdebug.derickrethans.nl/license.php |
| If you did not receive a copy of the Xdebug license and are unable |
| to obtain it through the world-wide-web, please send a note to |
| xdebug[@]derickrethans.nl so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Derick Rethans <derick[@]xdebug.org> |
+----------------------------------------------------------------------+
*/
/* $Id: cvstemp,v 1.1 2006/09/25 20:20:01 derick Exp $ */
#include <stdlib.h>
#include <math.h>
#include "xdebug_set.h"
xdebug_set *xdebug_set_create(unsigned int size)
{
xdebug_set *tmp;
tmp = calloc(1, sizeof(xdebug_set));
tmp->size = size;
size = ceil((size + 7) / 8);
tmp->setinfo = calloc(1, size);
return tmp;
}
void xdebug_set_free(xdebug_set *set)
{
free(set->setinfo);
free(set);
}
void xdebug_set_add(xdebug_set *set, unsigned int position)
{
char *byte;
unsigned int bit;
byte = &(set->setinfo[position / 8]);
bit = position % 8;
*byte = *byte | 1 << bit;
}
void xdebug_set_remove(xdebug_set *set, unsigned int position)
{
char *byte;
unsigned int bit;
byte = &(set->setinfo[position / 8]);
bit = position % 8;
*byte = *byte & ~(1 << bit);
}
int xdebug_set_in_ex(xdebug_set *set, unsigned int position, int noisy)
{
char *byte;
unsigned int bit;
byte = &(set->setinfo[position / 8]);
bit = position % 8;
return (*byte & (1 << bit));
}
[FILE: /xdebug/xdebug_set.h]
/*
+----------------------------------------------------------------------+
| Xdebug |
+----------------------------------------------------------------------+
| Copyright (c) 2002, 2003, 2004, 2005, 2006 Derick Rethans |
+----------------------------------------------------------------------+
| This source file is subject to version 1.0 of the Xdebug license, |
| that is bundled with this package in the file LICENSE, and is |
| available at through the world-wide-web at |
| http://xdebug.derickrethans.nl/license.php |
| If you did not receive a copy of the Xdebug license and are unable |
| to obtain it through the world-wide-web, please send a note to |
| xdebug[@]derickrethans.nl so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Derick Rethans <derick[@]xdebug.org> |
+----------------------------------------------------------------------+
*/
/* $Id: cvstemp,v 1.1 2006/09/25 20:20:01 derick Exp $ */
#ifndef __XDEBUG_SET_H__
#define __XDEBUG_SET_H__
typedef struct _xdebug_set {
unsigned int size;
unsigned char *setinfo;
} xdebug_set;
xdebug_set *xdebug_set_create(unsigned int size);
void xdebug_set_add(xdebug_set *set, unsigned int position);
void xdebug_set_remove(xdebug_set *set, unsigned int position);
#define xdebug_set_in(x,y) xdebug_set_in_ex(x,y,1)
int xdebug_set_in_ex(xdebug_set *set, unsigned int position, int noisy);
void xdebug_set_dump(xdebug_set *set);
#endif
[FILE: /xdebug/config.m4]
===================================================================
RCS file: cvstemp,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -r1.22 -r1.23
--- xdebug/config.m4:1.22 Sat Dec 31 09:50:10 2005 GMT
+++ xdebug/config.m4 Mon Sep 25 18:20:01 2006 GMT
@@ -1,4 +1,4 @@
-dnl $Id: cvstemp,v 1.22 2005/12/31 10:50:10 derick Exp $
+dnl $Id: cvstemp,v 1.23 2006/09/25 20:20:01 derick Exp $
dnl config.m4 for extension xdebug
PHP_ARG_ENABLE(xdebug, whether to enable eXtended debugging support,
@@ -9,7 +9,7 @@
dnl much out.
CFLAGS=`echo $CFLAGS | sed 's/O2/O0/'`
- PHP_NEW_EXTENSION(xdebug, xdebug.c xdebug_code_coverage.c xdebug_com.c xdebug_compat.c xdebug_handler_dbgp.c xdebug_handler_gdb.c xdebug_handler_php3.c xdebug_handlers.c xdebug_llist.c xdebug_hash.c xdebug_private.c xdebug_profiler.c xdebug_str.c xdebug_superglobals.c xdebug_var.c xdebug_xml.c usefulstuff.c, $ext_shared)
+ PHP_NEW_EXTENSION(xdebug, xdebug.c xdebug_code_coverage.c xdebug_com.c xdebug_compat.c xdebug_handler_dbgp.c xdebug_handler_gdb.c xdebug_handler_php3.c xdebug_handlers.c xdebug_llist.c xdebug_hash.c xdebug_private.c xdebug_profiler.c xdebug_set.c xdebug_str.c xdebug_superglobals.c xdebug_var.c xdebug_xml.c usefulstuff.c, $ext_shared)
AC_DEFINE(HAVE_XDEBUG,1,[ ])
dnl Check for new current_execute_data field in zend_executor_globals
[FILE: /xdebug/php_xdebug.h]
===================================================================
RCS file: cvstemp,v
retrieving revision 1.113
retrieving revision 1.114
diff -u -r1.113 -r1.114
--- xdebug/php_xdebug.h:1.113 Tue Sep 05 12:46:20 2006 GMT
+++ xdebug/php_xdebug.h Mon Sep 25 18:20:01 2006 GMT
@@ -150,6 +150,7 @@
zend_bool do_code_coverage;
xdebug_hash *code_coverage;
zend_bool code_coverage_unused;
+ zend_bool code_coverage_dead_code_analysis;
xdebug_hash *code_coverage_op_array_cache;
unsigned int function_count;
[FILE: /xdebug/xdebug.c]
===================================================================
RCS file: cvstemp,v
retrieving revision 1.342
retrieving revision 1.343
diff -u -r1.342 -r1.343
--- xdebug/xdebug.c:1.342 Thu Sep 21 07:36:50 2006 GMT
+++ xdebug/xdebug.c Mon Sep 25 18:20:01 2006 GMT
@@ -462,7 +462,7 @@
file = op_array->filename; \
file_len = strlen(file); \
\
- xdebug_count_line(file, lineno, 0 TSRMLS_CC); \
+ xdebug_count_line(file, lineno, 0, 0 TSRMLS_CC); \
} \
return ZEND_USER_OPCODE_DISPATCH; \
}
@@ -487,7 +487,7 @@
file = op_array->filename; \
file_len = strlen(file); \
\
- xdebug_count_line(file, lineno, 0 TSRMLS_CC); \
+ xdebug_count_line(file, lineno, 0, 0 TSRMLS_CC); \
} \
return old_##f##_handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); \
}
@@ -576,6 +576,7 @@
REGISTER_LONG_CONSTANT("XDEBUG_TRACE_HTML", XDEBUG_TRACE_OPTION_HTML, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XDEBUG_CC_UNUSED", XDEBUG_CC_OPTION_UNUSED, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("XDEBUG_CC_DEAD_CODE", XDEBUG_CC_OPTION_DEAD_CODE, CONST_CS | CONST_PERSISTENT);
XG(breakpoint_count) = 0;
return SUCCESS;
@@ -1026,7 +1027,7 @@
}
if (XG(do_code_coverage)) {
- xdebug_count_line(tmp->filename, tmp->lineno, 0 TSRMLS_CC);
+ xdebug_count_line(tmp->filename, tmp->lineno, 0, 0 TSRMLS_CC);
}
if (XG(profiler_aggregate)) {
@@ -2693,7 +2694,7 @@
file_len = strlen(file);
if (XG(do_code_coverage)) {
- xdebug_count_line(file, lineno, 0 TSRMLS_CC);
+ xdebug_count_line(file, lineno, 0, 0 TSRMLS_CC);
}
if (XG(remote_enabled)) {
[FILE: /xdebug/xdebug_code_coverage.c]
===================================================================
RCS file: cvstemp,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -r1.20 -r1.21
--- xdebug/xdebug_code_coverage.c:1.20 Sun Sep 10 16:43:41 2006 GMT
+++ xdebug/xdebug_code_coverage.c Mon Sep 25 18:20:01 2006 GMT
@@ -18,6 +18,7 @@
#include "php_xdebug.h"
#include "xdebug_private.h"
+#include "xdebug_set.h"
#include "xdebug_var.h"
#include "xdebug_code_coverage.h"
@@ -39,7 +40,7 @@
xdfree(file);
}
-void xdebug_count_line(char *filename, int lineno, int executable TSRMLS_DC)
+void xdebug_count_line(char *filename, int lineno, int executable, int deadcode TSRMLS_DC)
{
xdebug_coverage_file *file;
xdebug_coverage_line *line;
@@ -69,7 +70,11 @@
}
if (executable) {
- line->executable = 1;
+ if (line->executable != 1 && deadcode) {
+ line->executable = 2;
+ } else {
+ line->executable = 1;
+ }
} else {
line->count++;
}
@@ -77,7 +82,7 @@
xdfree(sline);
}
-static void prefil_from_opcode(function_stack_entry *fse, char *fn, zend_op opcode TSRMLS_DC)
+static void prefil_from_opcode(function_stack_entry *fse, char *fn, zend_op opcode, int deadcode TSRMLS_DC)
{
if (
opcode.opcode != ZEND_NOP &&
@@ -88,14 +93,113 @@
&& opcode.opcode != ZEND_VERIFY_ABSTRACT_CLASS
#endif
) {
- xdebug_count_line(fn, opcode.lineno, 1 TSRMLS_CC);
+ xdebug_count_line(fn, opcode.lineno, 1, deadcode TSRMLS_CC);
}
}
+static zend_brk_cont_element* xdebug_find_brk_cont(zval *nest_levels_zval, int array_offset, zend_op_array *op_array)
+{
+ int nest_levels;
+ zend_brk_cont_element *jmp_to;
+
+ nest_levels = nest_levels_zval->value.lval;
+
+ do {
+ jmp_to = &op_array->brk_cont_array[array_offset];
+ array_offset = jmp_to->parent;
+ } while (--nest_levels > 0);
+ return jmp_to;
+}
+
+static int xdebug_find_jump(zend_op_array *opa, unsigned int position, unsigned int *jmp1, unsigned int *jmp2)
+{
+ zend_uint base_address = (zend_uint) &(opa->opcodes[0]);
+
+ zend_op opcode = opa->opcodes[position];
+ if (opcode.opcode == ZEND_JMP) {
+ *jmp1 = (opcode.op1.u.opline_num - base_address) / sizeof(zend_op);
+ return 1;
+ } else if (
+ opcode.opcode == ZEND_JMPZ ||
+ opcode.opcode == ZEND_JMPNZ ||
+ opcode.opcode == ZEND_JMPZ_EX ||
+ opcode.opcode == ZEND_JMPNZ_EX
+ ) {
+ *jmp1 = position + 1;
+ *jmp2 = (opcode.op2.u.opline_num - base_address) / sizeof(zend_op);
+ return 1;
+ } else if (opcode.opcode == ZEND_JMPZNZ) {
+ *jmp1 = opcode.op2.u.opline_num;
+ *jmp2 = opcode.extended_value;
+ return 1;
+ } else if (opcode.opcode == ZEND_BRK || opcode.opcode == ZEND_CONT) {
+ zend_brk_cont_element *el;
+
+ if (opcode.op2.op_type == IS_CONST) {
+ el = xdebug_find_brk_cont(&opcode.op2.u.constant, opcode.op1.u.opline_num, opa);
+ *jmp1 = opcode.opcode == ZEND_BRK ? el->brk : el->cont;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void xdebug_analyse_branch(zend_op_array *opa, unsigned int position, xdebug_set *set)
+{
+ unsigned int jump_found = 0;
+ int jump_pos1 = -1;
+ int jump_pos2 = -1;
+
+ /*(fprintf(stderr, "Branch analysis from position: %d\n", position);)*/
+ /* First we see if the branch has been visited, if so we bail out. */
+ if (xdebug_set_in(set, position)) {
+ return;
+ }
+ /* Loop over the opcodes until the end of the array, or until a jump point has been found */
+ xdebug_set_add(set, position);
+ /*(fprintf(stderr, "XDEBUG Adding %d\n", position);)*/
+ while (position < opa->size) {
+
+ /* See if we have a jump instruction */
+ if (xdebug_find_jump(opa, position, &jump_pos1, &jump_pos2)) {
+ /*(fprintf(stderr, "XDEBUG Jump found. Position 1 = %d", jump_pos1);)*/
+ if (jump_pos2 != -1) {
+ /*(fprintf(stderr, ", Position 2 = %d\n", jump_pos2);)*/
+ } else {
+ /*(fprintf(stderr, "\n");)*/
+ }
+ xdebug_analyse_branch(opa, jump_pos1, set);
+ if (jump_pos2 != -1) {
+ xdebug_analyse_branch(opa, jump_pos2, set);
+ }
+ break;
+ }
+ /* See if we have an exit instruction */
+ if (opa->opcodes[position].opcode == ZEND_EXIT) {
+ /* fprintf(stderr, "X* Return found\n"); */
+ break;
+ }
+ /* See if we have a return instruction */
+ if (opa->opcodes[position].opcode == ZEND_RETURN) {
+ /*(fprintf(stderr, "XDEBUG Return found\n");)*/
+ break;
+ }
+ /* See if we have a throw instruction */
+ if (opa->opcodes[position].opcode == ZEND_THROW) {
+ /* fprintf(stderr, "X/* Throw found\n"); */
+ break;
+ }
+
+ position++;
+ /*(fprintf(stderr, "XDEBUG Adding %d\n", position);)*/
+ xdebug_set_add(set, position);
+ }
+}
static void prefil_from_oparray(function_stack_entry *fse, char *fn, zend_op_array *opa TSRMLS_DC)
{
- unsigned int i, check_jumps = 0, jmp, marker, end, jump_over = 0;
+ unsigned int i;
zend_uint base_address = (zend_uint) &(opa->opcodes[0]);
+ xdebug_set *set = NULL;
#ifdef ZEND_ENGINE_2
/* Check for abstract methods and simply return from this function in those
@@ -106,52 +210,20 @@
}
#endif
- /* We need to figure out the last jump point to see if we can fix the
- * return at the end of the function. We only have to do that if the
- * last 5 opcodes are EXT_STMT, RETURN, EXT_STMT, RETURN and
- * ZEND_HANDLE_EXCEPTION though (for PHP 5). */
- if (opa->size >= 4) {
- if (
- opa->opcodes[opa->size - 4].opcode == ZEND_RETURN &&
- opa->opcodes[opa->size - 3].opcode == ZEND_EXT_STMT &&
- opa->opcodes[opa->size - 2].opcode == ZEND_RETURN &&
- opa->opcodes[opa->size - 1].opcode == ZEND_HANDLE_EXCEPTION
- ) {
- marker = opa->size - 5;
- check_jumps = 1;
- }
+ /* Run dead code analysis if requested */
+ if (XG(code_coverage_dead_code_analysis)) {
+ set = xdebug_set_create(opa->size);
+ xdebug_analyse_branch(opa, 0, set);
}
+
+ /* The normal loop then finally */
for (i = 0; i < opa->size; i++) {
zend_op opcode = opa->opcodes[i];
- if (check_jumps) {
- jmp = 0;
- if (opcode.opcode == ZEND_JMP) {
- jmp = (opcode.op1.u.opline_num - base_address) / sizeof(zend_op);
- } else if (
- opcode.opcode == ZEND_JMPZ ||
- opcode.opcode == ZEND_JMPNZ ||
- opcode.opcode == ZEND_JMPZ_EX ||
- opcode.opcode == ZEND_JMPNZ_EX
- ) {
- jmp = (opcode.op2.u.opline_num - base_address) / sizeof(zend_op);
- } else if (opcode.opcode == ZEND_JMPZNZ) {
- jmp = opcode.op2.u.opline_num;
- }
- if (jmp > marker) {
- jump_over = 1;
- }
- }
- }
- if (jump_over && check_jumps) {
- end = opa->size;
- } else {
- end = opa->size - 3;
+ prefil_from_opcode(NULL, fn, opcode, set ? !xdebug_set_in(set, i) : 0 TSRMLS_CC);
}
- /* The normal loop then finally */
- for (i = 0; i < end; i++) {
- zend_op opcode = opa->opcodes[i];
- prefil_from_opcode(NULL, fn, opcode TSRMLS_CC);
+ if (set) {
+ xdebug_set_free(set);
}
}
@@ -220,7 +292,8 @@
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &options) == FAILURE) {
return;
}
- XG(code_coverage_unused) = (options == XDEBUG_CC_OPTION_UNUSED);
+ XG(code_coverage_unused) = (options & XDEBUG_CC_OPTION_UNUSED);
+ XG(code_coverage_dead_code_analysis) = (options & XDEBUG_CC_OPTION_DEAD_CODE);
if (XG(extended_info)) {
XG(do_code_coverage) = 1;
@@ -267,7 +340,7 @@
zval *retval = (zval*) ret;
if (line->executable && (line->count == 0)) {
- add_index_long(retval, line->lineno, -1);
+ add_index_long(retval, line->lineno, -line->executable);
} else {
add_index_long(retval, line->lineno, 1);
}
[FILE: /xdebug/xdebug_code_coverage.h]
===================================================================
RCS file: cvstemp,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- xdebug/xdebug_code_coverage.h:1.8 Sun Jan 01 14:27:27 2006 GMT
+++ xdebug/xdebug_code_coverage.h Mon Sep 25 18:20:01 2006 GMT
@@ -37,7 +37,7 @@
void xdebug_coverage_line_dtor(void *data);
void xdebug_coverage_file_dtor(void *data);
-void xdebug_count_line(char *file, int lineno, int executable TSRMLS_DC);
+void xdebug_count_line(char *file, int lineno, int executable, int deadcode TSRMLS_DC);
void xdebug_prefil_code_coverage(function_stack_entry *fse, zend_op_array *op_array TSRMLS_DC);
PHP_FUNCTION(xdebug_start_code_coverage);
[FILE: /xdebug/xdebug_private.h]
===================================================================
RCS file: cvstemp,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -r1.19 -r1.20
--- xdebug/xdebug_private.h:1.19 Tue Sep 05 11:05:08 2006 GMT
+++ xdebug/xdebug_private.h Mon Sep 25 18:20:01 2006 GMT
@@ -71,6 +71,7 @@
#define XDEBUG_TRACE_OPTION_HTML 4
#define XDEBUG_CC_OPTION_UNUSED 1
+#define XDEBUG_CC_OPTION_DEAD_CODE 2
#define STATUS_STARTING 0
#define STATUS_STOPPING 1
Received on Mon Sep 25 2006 - 22:20:07 BST
This archive was generated by hypermail 2.2.0 : Sun Jun 24 2018 - 04:00:03 BST