Merge branch 'temporary_cleaning' of https://github.com/dstogov/php-src into temporary_cleaning

This commit is contained in:
Xinchen Hui 2015-07-04 15:06:44 +08:00
commit 1dbb007e4a
10 changed files with 296 additions and 47 deletions

View file

@ -6276,10 +6276,8 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */
{
zend_ast *expr_ast = ast->child[0];
znode silence_node;
uint32_t begin_opline_num, end_opline_num;
zend_brk_cont_element *brk_cont_element;
begin_opline_num = get_next_op_number(CG(active_op_array));
zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL);
if (expr_ast->kind == ZEND_AST_VAR) {
@ -6290,15 +6288,7 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */
zend_compile_expr(result, expr_ast);
}
end_opline_num = get_next_op_number(CG(active_op_array));
zend_emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL);
/* Store BEGIN_SILENCE/END_SILENCE pair to restore previous
* EG(error_reporting) value on exception */
brk_cont_element = get_next_brk_cont_element(CG(active_op_array));
brk_cont_element->start = begin_opline_num;
brk_cont_element->cont = brk_cont_element->brk = end_opline_num;
brk_cont_element->parent = -1;
}
/* }}} */
@ -6626,10 +6616,6 @@ static void zend_compile_encaps_list(znode *result, zend_ast *ast) /* {{{ */
GET_NODE(result, opline->result);
} else {
uint32_t var;
zend_brk_cont_element *info = get_next_brk_cont_element(CG(active_op_array));
info->start = rope_init_lineno;
info->parent = CG(context).current_brk_cont;
info->cont = info->brk = opline - CG(active_op_array)->opcodes;
init_opline->extended_value = j;
opline->opcode = ZEND_ROPE_END;

View file

@ -328,6 +328,9 @@ typedef struct _zend_internal_function_info {
zend_bool _is_variadic;
} zend_internal_function_info;
#define ZEND_LIVE_ROPE (1 << 0)
#define ZEND_LIVE_SILENCE (1 << 1)
struct _zend_op_array {
/* Common elements */
zend_uchar type;
@ -351,6 +354,7 @@ struct _zend_op_array {
int last_var;
uint32_t T;
zend_string **vars;
uint32_t *T_liveliness;
int last_brk_cont;
int last_try_catch;
@ -727,6 +731,7 @@ ZEND_API int zend_execute_scripts(int type, zval *retval, int file_count, ...);
ZEND_API int open_file_for_scanning(zend_file_handle *file_handle);
ZEND_API void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size);
ZEND_API void destroy_op_array(zend_op_array *op_array);
ZEND_API uint32_t *generate_var_liveliness_info(zend_op_array *op_array);
ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle);
ZEND_API void zend_cleanup_user_class_data(zend_class_entry *ce);
ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce);

View file

@ -2385,6 +2385,41 @@ static zend_always_inline zend_generator *zend_get_running_generator(zend_execut
static zend_always_inline void i_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */
{
int i;
if (EX(func)->op_array.T_liveliness && op_num < EX(func)->op_array.last) {
uint32_t *off = EX(func)->op_array.T_liveliness + EX(func)->op_array.T_liveliness[op_num];
uint32_t *until = EX(func)->op_array.T_liveliness + EX(func)->op_array.T_liveliness[op_num + 1];
while (off < until) {
uint32_t var = *(off++);
if (var & ZEND_LIVE_ROPE) {
/* free incomplete rope */
zend_string **rope = (zend_string **) EX_VAR(var & ~ZEND_LIVE_ROPE);
zend_op *last = EX(func)->op_array.opcodes + op_num;
while (last->opcode != ZEND_ROPE_ADD && last->opcode != ZEND_ROPE_INIT) {
ZEND_ASSERT(last >= EX(func)->op_array.opcodes);
last--;
}
if (last->opcode == ZEND_ROPE_INIT) {
zend_string_release(*rope);
} else {
int j = last->extended_value;
do {
zend_string_release(rope[j]);
} while (j--);
}
} else if (var & ZEND_LIVE_SILENCE) {
/* restore previous error_reporting value */
var = var & ~ZEND_LIVE_SILENCE;
if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(var)) != 0) {
EG(error_reporting) = Z_LVAL_P(EX_VAR(var));
}
} else {
zval_ptr_dtor_nogc(EX_VAR(var));
}
}
}
if (UNEXPECTED(EX(call))) {
zend_execute_data *call = EX(call);
zend_op *opline = EX(func)->op_array.opcodes + op_num;
@ -2511,34 +2546,13 @@ static zend_always_inline void i_cleanup_unfinished_execution(zend_execute_data
if (!catch_op_num || catch_op_num >= brk_cont->brk) {
zend_op *brk_opline = &EX(func)->op_array.opcodes[brk_cont->brk];
if (brk_opline->opcode == ZEND_FREE) {
zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
} else if (brk_opline->opcode == ZEND_FE_FREE) {
/* ZEND_FREE opcodes are handled by temporary variable freeing */
if (brk_opline->opcode == ZEND_FE_FREE) {
zval *var = EX_VAR(brk_opline->op1.var);
if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
zend_hash_iterator_del(Z_FE_ITER_P(var));
}
zval_ptr_dtor_nogc(var);
} else if (brk_opline->opcode == ZEND_ROPE_END) {
zend_string **rope = (zend_string **) EX_VAR(brk_opline->op1.var);
zend_op *last = EX(func)->op_array.opcodes + op_num;
while (last->opcode != ZEND_ROPE_ADD && last->opcode != ZEND_ROPE_INIT) {
ZEND_ASSERT(last >= EX(func)->op_array.opcodes);
last--;
}
if (last->opcode == ZEND_ROPE_INIT) {
zend_string_release(*rope);
} else {
int j = last->extended_value;
do {
zend_string_release(rope[j]);
} while (j--);
}
} else if (brk_opline->opcode == ZEND_END_SILENCE) {
/* restore previous error_reporting value */
if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(brk_opline->op1.var)) != 0) {
EG(error_reporting) = Z_LVAL_P(EX_VAR(brk_opline->op1.var));
}
}
}
}

View file

@ -65,6 +65,7 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz
op_array->vars = NULL;
op_array->T = 0;
op_array->T_liveliness = NULL;
op_array->function_name = NULL;
op_array->filename = zend_get_compiled_filename();
@ -389,6 +390,9 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
if (op_array->try_catch_array) {
efree(op_array->try_catch_array);
}
if (op_array->T_liveliness) {
efree(op_array->T_liveliness);
}
if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array);
}
@ -576,7 +580,7 @@ static void zend_resolve_finally_call(zend_op_array *op_array, uint32_t op_num,
fast_call_var = op_array->opcodes[op_array->try_catch_array[i].finally_end].op1.var;
/* generate a FAST_CALL to finally block */
start_op = get_next_op_number(op_array);
start_op = get_next_op_number(op_array);
opline = get_next_op(op_array);
opline->opcode = ZEND_FAST_CALL;
@ -751,6 +755,9 @@ ZEND_API int pass_two(zend_op_array *op_array)
op_array->literals = (zval*)erealloc(op_array->literals, sizeof(zval) * op_array->last_literal);
CG(context).literals_size = op_array->last_literal;
}
op_array->T_liveliness = generate_var_liveliness_info(op_array);
opline = op_array->opcodes;
end = opline + op_array->last;
while (opline < end) {
@ -840,6 +847,174 @@ int pass_two_wrapper(zval *el)
return pass_two((zend_op_array *) Z_PTR_P(el));
}
typedef struct _var_live_info {
struct _var_live_info *next;
uint32_t start;
uint32_t end;
} var_live_info;
typedef struct _op_var_info {
struct _op_var_info *next;
uint32_t var;
} op_var_info;
ZEND_API uint32_t *generate_var_liveliness_info(zend_op_array *op_array)
{
void *checkpoint = zend_arena_checkpoint(CG(arena));
var_live_info **TsTop = zend_arena_alloc(&CG(arena), sizeof(var_live_info *) * op_array->T);
var_live_info **Ts = zend_arena_alloc(&CG(arena), sizeof(var_live_info *) * op_array->T);
int i, op_live_total = 0;
uint32_t *info, info_off = op_array->last + 1;
op_var_info *opTsTop = zend_arena_alloc(&CG(arena), sizeof(op_var_info) * (op_array->last + 1));
op_var_info **opTs = zend_arena_alloc(&CG(arena), sizeof(op_var_info *) * (op_array->last + 1));
for (i = 0; i < op_array->T; i++) {
TsTop[i] = Ts[i] = zend_arena_alloc(&CG(arena), sizeof(var_live_info));
Ts[i]->next = NULL;
Ts[i]->start = Ts[i]->end = -1;
}
for (i = 0; i <= op_array->last; i++) {
opTs[i] = &opTsTop[i];
opTs[i]->var = -1;
opTs[i]->next = NULL;
}
zend_op *end_op = op_array->opcodes + op_array->last;
zend_op *cur_op = op_array->opcodes;
for (; cur_op < end_op; cur_op++) {
if ((cur_op->result_type & (IS_VAR | IS_TMP_VAR))
&& !(cur_op->result_type & EXT_TYPE_UNUSED)
&& cur_op->opcode != ZEND_BOOL /* why ??? */
&& cur_op->opcode != ZEND_JMPZ_EX /* why ??? */
&& cur_op->opcode != ZEND_JMPNZ_EX /* why ??? */
&& (cur_op->opcode != ZEND_QM_ASSIGN
|| (cur_op + 1)->opcode != ZEND_JMP) /* why ??? */
&& cur_op->opcode != ZEND_CASE /* ??? exception for opcache, is anyway bool */
&& cur_op->opcode != ZEND_FE_RESET_R /* FOREACH TMP is handled using brk_cont_array */
&& cur_op->opcode != ZEND_FE_RESET_RW /* FOREACH TMP is handled using brk_cont_array */
&& cur_op->opcode != ZEND_ROPE_ADD /* the following opocodes reuse TMP created before */
&& cur_op->opcode != ZEND_ADD_ARRAY_ELEMENT
&& cur_op->opcode != ZEND_FAST_CALL /* passes fast_call */
&& cur_op->opcode != ZEND_FETCH_CLASS /* the following opcodes pass class_entry */
&& cur_op->opcode != ZEND_DECLARE_CLASS
&& cur_op->opcode != ZEND_DECLARE_INHERITED_CLASS
&& cur_op->opcode != ZEND_DECLARE_INHERITED_CLASS_DELAYED
&& cur_op->opcode != ZEND_DECLARE_ANON_CLASS
&& cur_op->opcode != ZEND_DECLARE_ANON_INHERITED_CLASS) {
var_live_info *T = Ts[cur_op->result.var];
if (~T->end) {
T = Ts[cur_op->result.var] = T->next = zend_arena_alloc(&CG(arena), sizeof(var_live_info));
T->next = NULL;
T->start = T->end = -1;
}
if (!~T->start) {
/* Objects created via ZEND_NEW are only fully initialized after the DO_FCALL (constructor call) */
if (cur_op->opcode == ZEND_NEW) {
T->start = cur_op->op2.opline_num - 1;
} else {
T->start = cur_op - op_array->opcodes;
}
}
}
if ((cur_op->op1_type & (IS_VAR | IS_TMP_VAR))
&& cur_op->opcode != ZEND_FE_FETCH_R /* FOREACH TMP is handled using brk_cont_array */
&& cur_op->opcode != ZEND_FE_FETCH_RW /* FOREACH TMP is handled using brk_cont_array */
&& cur_op->opcode != ZEND_FE_FREE /* FOREACH TMP is handled using brk_cont_array */
&& cur_op->opcode != ZEND_ROPE_ADD /* the following opcodes don't free TMP */
&& cur_op->opcode != ZEND_CASE
&& cur_op->opcode != ZEND_FETCH_LIST
&& cur_op->opcode != ZEND_FAST_RET /* uses fast_call */
&& cur_op->opcode != ZEND_NEW /* the following opcodes use class_entry */
&& cur_op->opcode != ZEND_INIT_STATIC_METHOD_CALL
&& cur_op->opcode != ZEND_FETCH_CONSTANT
&& cur_op->opcode != ZEND_ADD_INTERFACE
&& cur_op->opcode != ZEND_ADD_TRAIT
&& cur_op->opcode != ZEND_BIND_TRAITS
&& cur_op->opcode != ZEND_VERIFY_ABSTRACT_CLASS) {
var_live_info *T = Ts[cur_op->op1.var];
if (~T->start) {
T->end = cur_op - op_array->opcodes;
if (cur_op->opcode == ZEND_OP_DATA) {
T->end--;
}
}
}
if ((cur_op->op2_type & (IS_VAR | IS_TMP_VAR))
&& cur_op->opcode != ZEND_FETCH_R /* the following opcodes use class_entry */
&& cur_op->opcode != ZEND_FETCH_W
&& cur_op->opcode != ZEND_FETCH_RW
&& cur_op->opcode != ZEND_FETCH_IS
&& cur_op->opcode != ZEND_FETCH_FUNC_ARG
&& cur_op->opcode != ZEND_FETCH_UNSET
&& cur_op->opcode != ZEND_UNSET_VAR
&& cur_op->opcode != ZEND_ISSET_ISEMPTY_VAR
&& cur_op->opcode != ZEND_INSTANCEOF) {
var_live_info *T = Ts[cur_op->op2.var];
if (~T->start) {
T->end = cur_op - op_array->opcodes;
if (cur_op->opcode == ZEND_OP_DATA) {
T->end--;
}
}
}
}
for (i = 0; i < op_array->T; i++) {
int j;
var_live_info *T = TsTop[i];
do {
if (!~T->start) {
continue;
}
ZEND_ASSERT(~T->end);
for (j = T->start + 1; j < T->end; j++) {
if (op_array->opcodes[j].opcode != ZEND_THROW) {
op_var_info *opT = opTs[j];
if (~opT->var) {
opT = opTs[j] = opT->next = zend_arena_alloc(&CG(arena), sizeof(op_var_info));
opT->next = NULL;
}
opT->var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + i);;
if (op_array->opcodes[T->end].opcode == ZEND_ROPE_END) {
opT->var |= ZEND_LIVE_ROPE;
} else if (op_array->opcodes[T->end].opcode == ZEND_END_SILENCE) {
opT->var |= ZEND_LIVE_SILENCE;
}
op_live_total++;
}
}
} while ((T = T->next));
}
if (!op_live_total) {
zend_arena_release(&CG(arena), checkpoint);
return NULL;
}
info = emalloc(op_live_total * sizeof(uint32_t) + (op_array->last + 1) * sizeof(uint32_t));
for (i = 0; i < op_array->last; i++) {
op_var_info *opT = &opTsTop[i];
info[i] = info_off;
if (!~opT->var) {
opT = NULL;
}
while (opT) {
info[info_off++] = opT->var;
opT = opT->next;
}
}
info[i] = info_off;
zend_arena_release(&CG(arena), checkpoint);
return info;
}
int print_class(zend_class_entry *class_entry)
{
printf("Class %s:\n", ZSTR_VAL(class_entry->name));

View file

@ -207,17 +207,13 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
for (i = 0; i< op_array->last_brk_cont; i++) {
if (op_array->brk_cont_array[i].start >= 0 &&
(op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE ||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_ROPE_END ||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) {
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE)) {
int parent = op_array->brk_cont_array[i].parent;
while (parent >= 0 &&
op_array->brk_cont_array[parent].start < 0 &&
(op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FREE ||
op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FE_FREE ||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode != ZEND_ROPE_END ||
op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_END_SILENCE)) {
op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FE_FREE)) {
parent = op_array->brk_cont_array[parent].parent;
}
op_array->brk_cont_array[i].parent = parent;
@ -232,9 +228,7 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
for (i = 0; i< op_array->last_brk_cont; i++) {
if (op_array->brk_cont_array[i].start >= 0 &&
(op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE ||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_ROPE_END ||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) {
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE)) {
if (i != j) {
op_array->brk_cont_array[j] = op_array->brk_cont_array[i];
}

View file

@ -482,6 +482,8 @@ static void zend_accel_optimize(zend_op_array *op_array,
{
zend_op *opline, *end;
efree(op_array->T_liveliness);
/* Revert pass_two() */
opline = op_array->opcodes;
end = opline + op_array->last;
@ -527,15 +529,39 @@ static void zend_accel_optimize(zend_op_array *op_array,
/* Do actual optimizations */
zend_optimize(op_array, ctx);
opline = op_array->opcodes;
end = opline + op_array->last;
while (opline < end) {
if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
opline->op1.var = EX_VAR_TO_NUM(opline->op1.var) - op_array->last_var;
}
if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) {
opline->op2.var = EX_VAR_TO_NUM(opline->op2.var) - op_array->last_var;
}
if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
opline->result.var = EX_VAR_TO_NUM(opline->result.var) - op_array->last_var;
}
opline++;
}
op_array->T_liveliness = generate_var_liveliness_info(op_array);
/* Redo pass_two() */
opline = op_array->opcodes;
end = opline + op_array->last;
while (opline < end) {
if (opline->op1_type == IS_CONST) {
ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op1);
} else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
opline->op1.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, opline->op1.var + op_array->last_var);
}
if (opline->op2_type == IS_CONST) {
ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2);
} else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) {
opline->op2.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, opline->op2.var + op_array->last_var);
}
if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
opline->result.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, opline->result.var + op_array->last_var);
}
switch (opline->opcode) {
case ZEND_JMP:

View file

@ -464,6 +464,7 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra
SERIALIZE_STR(op_array->doc_comment);
SERIALIZE_PTR(op_array->try_catch_array);
SERIALIZE_PTR(op_array->prototype);
SERIALIZE_PTR(op_array->T_liveliness);
}
}
@ -987,6 +988,7 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr
UNSERIALIZE_STR(op_array->doc_comment);
UNSERIALIZE_PTR(op_array->try_catch_array);
UNSERIALIZE_PTR(op_array->prototype);
UNSERIALIZE_PTR(op_array->T_liveliness);
}
}

View file

@ -618,6 +618,10 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
zend_accel_store(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch);
}
if (op_array->T_liveliness) {
zend_accel_store(op_array->T_liveliness, sizeof(uint32_t) * op_array->T_liveliness[op_array->last]);
}
if (op_array->vars) {
if (already_stored) {
persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->vars);

View file

@ -241,6 +241,10 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array)
ADD_DUP_SIZE(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch);
}
if (op_array->T_liveliness) {
ADD_DUP_SIZE(op_array->T_liveliness, sizeof(uint32_t) * op_array->T_liveliness[op_array->last]);
}
if (op_array->vars) {
int i;

View file

@ -24,6 +24,7 @@
#include "phpdbg_opcode.h"
#include "phpdbg_utils.h"
#include "ext/standard/php_string.h"
#include "zend_smart_str.h"
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
@ -124,6 +125,44 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars) /*{
break;
}
#if 1
if (ops->T_liveliness) {
uint32_t *var = ops->T_liveliness + ops->T_liveliness[op - ops->opcodes];
uint32_t *end = ops->T_liveliness + ops->T_liveliness[op - ops->opcodes + 1];
if (var != end) {
smart_str str = {0};
smart_str_appends(&str, "; [@");
smart_str_append_long(&str, EX_VAR_TO_NUM(((*var) & ~0x3)) - ops->last_var);
while (++var != end) {
smart_str_appends(&str, ", @");
smart_str_append_long(&str, EX_VAR_TO_NUM(((*var) & ~0x3)) - ops->last_var);
}
smart_str_appendc(&str, ']');
smart_str_0(&str);
asprintf(&decode[0],
"%-20s %-20s %-20s%-20s",
decode[1] ? decode[1] : "",
decode[2] ? decode[2] : "",
decode[3] ? decode[3] : "",
ZSTR_VAL(str.s));
smart_str_free(&str);
if (decode[1])
free(decode[1]);
if (decode[2])
free(decode[2]);
if (decode[3])
free(decode[3]);
return decode[0];
}
}
#endif
asprintf(&decode[0],
"%-20s %-20s %-20s",
decode[1] ? decode[1] : "",