Improved implementation of NOP removal pass from O(n^2) to O(n) (hnw)

This commit is contained in:
Dmitry Stogov 2013-07-30 22:31:37 +04:00
parent e2aba1cf9e
commit cb17c99511

View file

@ -558,6 +558,52 @@ static void zend_rebuild_access_path(zend_cfg *cfg, zend_op_array *op_array, int
convert_to_string((v)); \
}
static void strip_nop(zend_code_block *block)
{
zend_op *opline = block->start_opline;
zend_op *end, *new_end;
int new_len = 0;
/* remove leading NOPs */
while (block->len > 0 && block->start_opline->opcode == ZEND_NOP) {
if (block->len == 1) {
/* this block is all NOPs, join with following block */
if (block->follow_to) {
delete_code_block(block);
}
return;
}
block->start_opline++;
block->start_opline_no++;
block->len--;
}
/* strip the inside NOPs */
opline = new_end = block->start_opline;
end = opline + block->len;
while (opline < end) {
zend_op *src;
int len = 0;
while (opline < end && opline->opcode == ZEND_NOP) {
opline++;
}
src = opline;
while (opline < end && opline->opcode != ZEND_NOP) {
opline++;
}
len = opline - src;
/* move up non-NOP opcodes */
memmove(new_end, src, len*sizeof(zend_op));
new_end += len;
}
block->len = new_end - block->start_opline;
}
static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, char *used_ext TSRMLS_DC)
{
zend_op *opline = block->start_opline;
@ -1168,45 +1214,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
opline++;
}
/* remove leading NOPs */
while (block->len > 0 && block->start_opline->opcode == ZEND_NOP) {
if (block->len == 1) {
/* this block is all NOPs, join with following block */
if (block->follow_to) {
delete_code_block(block);
}
if (op_array->T) {
efree(Tsource);
}
return;
}
block->start_opline++;
block->start_opline_no++;
block->len--;
}
/* strip the inside NOPs */
opline = block->start_opline;
end = opline + block->len;
while (opline < end) {
if (opline->opcode == ZEND_NOP) {
zend_op *nop = opline + 1;
int noplen;
while (nop < end && nop->opcode == ZEND_NOP) {
nop++;
}
noplen = nop-opline;
if (nop < end) {
/* move up non-NOP opcodes */
memmove(opline, nop, (end-nop)*sizeof(zend_op));
} else {
/* all NOPs up to the end, do nothing */
}
block->len -= noplen;
end = block->start_opline + block->len;
}
opline++;
}
strip_nop(block);
if (op_array->T) {
efree(Tsource);