mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Merge branch 'temporary_cleaning' of github.com:bwoebi/php-src into temporary_cleaning
* 'temporary_cleaning' of github.com:bwoebi/php-src: Fix remaining issues with compacted temporaries Fix regression from last commit (+1 ?!) Fix off-by-one (opcache may remove last ZEND_RETURN) Speed algorithm up, more fail safety when reusing temporaries Dumb bug in opcode.c (forgot to update Ts[i]) Fix opcache support Exempt ROPE temporaries from freeing Hmm, we need temporary info for all the opcodes Add opcache support for cleaning in optimization step (Opcache seems to have a few unrelated issues which blow up together with that patch) Add proper temporary cleaning upon frame abortion Fix arena on small sizes (size < sizeof(zend_arena))
This commit is contained in:
commit
a4fce36907
8 changed files with 185 additions and 5 deletions
|
@ -33,7 +33,7 @@ struct _zend_arena {
|
|||
|
||||
static zend_always_inline zend_arena* zend_arena_create(size_t size)
|
||||
{
|
||||
zend_arena *arena = (zend_arena*)emalloc(size);
|
||||
zend_arena *arena = (zend_arena*)emalloc(size + ZEND_MM_ALIGNED_SIZE(sizeof(zend_arena)));
|
||||
|
||||
arena->ptr = (char*) arena + ZEND_MM_ALIGNED_SIZE(sizeof(zend_arena));
|
||||
arena->end = (char*) arena + size;
|
||||
|
|
|
@ -351,6 +351,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 +728,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);
|
||||
|
|
|
@ -2385,6 +2385,15 @@ 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 (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) {
|
||||
zval_ptr_dtor_nogc(ZEND_CALL_VAR_NUM(execute_data, *(off++)));
|
||||
}
|
||||
}
|
||||
|
||||
if (UNEXPECTED(EX(call))) {
|
||||
zend_execute_data *call = EX(call);
|
||||
zend_op *opline = EX(func)->op_array.opcodes + op_num;
|
||||
|
@ -2511,9 +2520,8 @@ 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));
|
||||
|
|
|
@ -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,133 @@ 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 T;
|
||||
} op_var_info;
|
||||
|
||||
ZEND_API uint32_t *generate_var_liveliness_info(zend_op_array *op_array)
|
||||
{
|
||||
zend_arena *arena = zend_arena_create((sizeof(var_live_info) + sizeof(op_var_info) + 2 * sizeof(var_live_info *)) * op_array->T + (sizeof(op_var_info) + sizeof(op_var_info *) + sizeof(zend_op *)) * (op_array->last + 1));
|
||||
var_live_info **TsTop = zend_arena_alloc(&arena, sizeof(var_live_info *) * op_array->T);
|
||||
var_live_info **Ts = zend_arena_alloc(&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(&arena, sizeof(op_var_info) * (op_array->last + 1));
|
||||
op_var_info **opTs = zend_arena_alloc(&arena, sizeof(op_var_info *) * (op_array->last + 1));
|
||||
|
||||
for (i = 0; i < op_array->T; i++) {
|
||||
TsTop[i] = Ts[i] = zend_arena_alloc(&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]->T = -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 && cur_op->opcode != ZEND_JMPZ_EX && cur_op->opcode != ZEND_JMPNZ_EX
|
||||
&& (cur_op->opcode != ZEND_QM_ASSIGN || (cur_op + 1)->opcode != ZEND_JMP)) {
|
||||
var_live_info *T = Ts[cur_op->result.var];
|
||||
if (~T->end) {
|
||||
T = Ts[cur_op->result.var] = T->next = zend_arena_alloc(&arena, sizeof(var_live_info));
|
||||
T->next = NULL;
|
||||
T->start = T->end = -1;
|
||||
}
|
||||
if (!~T->start
|
||||
&& cur_op->opcode != ZEND_CASE /* exception for opcache, is anyway bool */
|
||||
&& cur_op->opcode != ZEND_ROPE_INIT && cur_op->opcode != ZEND_ROPE_ADD
|
||||
&& cur_op->opcode != ZEND_FAST_CALL && cur_op->opcode != ZEND_FAST_RET
|
||||
&& cur_op->opcode != ZEND_FETCH_CLASS && 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) {
|
||||
/* 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_FREE
|
||||
&& cur_op->opcode != ZEND_ROPE_ADD && cur_op->opcode != ZEND_ROPE_END) {
|
||||
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)) {
|
||||
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->T) {
|
||||
opT = opTs[j] = opT->next = zend_arena_alloc(&arena, sizeof(op_var_info));
|
||||
opT->next = NULL;
|
||||
}
|
||||
opT->T = i;
|
||||
op_live_total++;
|
||||
}
|
||||
}
|
||||
} while ((T = T->next));
|
||||
}
|
||||
|
||||
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->T) {
|
||||
opT = NULL;
|
||||
}
|
||||
while (opT) {
|
||||
info[info_off++] = op_array->last_var + opT->T;
|
||||
opT = opT->next;
|
||||
}
|
||||
}
|
||||
info[i] = info_off;
|
||||
|
||||
zend_arena_destroy(arena);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
int print_class(zend_class_entry *class_entry)
|
||||
{
|
||||
printf("Class %s:\n", ZSTR_VAL(class_entry->name));
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue