diff options
Diffstat (limited to 'Zend/zend_opcode.c')
-rw-r--r-- | Zend/zend_opcode.c | 237 |
1 files changed, 15 insertions, 222 deletions
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 8f3ecddbda..a971a5e900 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -65,7 +65,6 @@ 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(); @@ -78,7 +77,9 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->scope = NULL; op_array->prototype = NULL; + op_array->brk_cont_array = NULL; op_array->try_catch_array = NULL; + op_array->last_brk_cont = 0; op_array->static_variables = NULL; op_array->last_try_catch = 0; @@ -382,12 +383,12 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) if (op_array->doc_comment) { zend_string_release(op_array->doc_comment); } + if (op_array->brk_cont_array) { + efree(op_array->brk_cont_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); } @@ -446,9 +447,9 @@ int get_next_op_number(zend_op_array *op_array) zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array) { - CG(context).last_brk_cont++; - CG(context).brk_cont_array = erealloc(CG(context).brk_cont_array, sizeof(zend_brk_cont_element)*CG(context).last_brk_cont); - return &CG(context).brk_cont_array[CG(context).last_brk_cont-1]; + op_array->last_brk_cont++; + op_array->brk_cont_array = erealloc(op_array->brk_cont_array, sizeof(zend_brk_cont_element)*op_array->last_brk_cont); + return &op_array->brk_cont_array[op_array->last_brk_cont-1]; } static void zend_update_extended_info(zend_op_array *op_array) @@ -575,7 +576,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; @@ -671,7 +672,7 @@ static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const ze int array_offset = opline->op1.num; zend_brk_cont_element *jmp_to; do { - jmp_to = &CG(context).brk_cont_array[array_offset]; + jmp_to = &op_array->brk_cont_array[array_offset]; if (nest_levels > 1) { array_offset = jmp_to->parent; } @@ -699,8 +700,11 @@ static void zend_resolve_finally_calls(zend_op_array *op_array) break; case ZEND_GOTO: if (Z_TYPE_P(CT_CONSTANT_EX(op_array, opline->op2.constant)) != IS_LONG) { + uint32_t num = opline->op2.constant; + ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2); - zend_resolve_goto_label(op_array, NULL, opline); + zend_resolve_goto_label(op_array, opline, 1); + opline->op2.constant = num; } /* break omitted intentionally */ case ZEND_JMP: @@ -747,9 +751,6 @@ 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; } - - zend_generate_var_liveliness_info(op_array); - opline = op_array->opcodes; end = opline + op_array->last; while (opline < end) { @@ -786,7 +787,7 @@ ZEND_API int pass_two(zend_op_array *op_array) break; case ZEND_GOTO: if (Z_TYPE_P(RT_CONSTANT(op_array, opline->op2)) != IS_LONG) { - zend_resolve_goto_label(op_array, NULL, opline); + zend_resolve_goto_label(op_array, opline, 1); } /* break omitted intentionally */ case ZEND_JMP: @@ -839,214 +840,6 @@ int pass_two_wrapper(zval *el) return pass_two((zend_op_array *) Z_PTR_P(el)); } -/* The following liveliness analyzing algorithm assumes that - * 1) temporary variables are defined before use - * 2) they have linear live-ranges without "holes" - * 3) Opcodes never use and define the same temorary variables - */ -typedef struct _op_var_info { - struct _op_var_info *next; - uint32_t var; -} op_var_info; - -static zend_always_inline uint32_t liveliness_kill_var(zend_op_array *op_array, zend_op *cur_op, uint32_t var, uint32_t *Tstart, op_var_info **opTs) -{ - uint32_t start = Tstart[var]; - uint32_t end = cur_op - op_array->opcodes; - uint32_t count = 0; - uint32_t var_offset, j; - - Tstart[var] = -1; - if (cur_op->opcode == ZEND_OP_DATA) { - end--; - } - start++; - if (op_array->opcodes[start].opcode == ZEND_OP_DATA - || op_array->opcodes[start].opcode == ZEND_FE_FETCH_R - || op_array->opcodes[start].opcode == ZEND_FE_FETCH_RW) { - start++; - } - if (start < end) { - op_var_info *new_opTs; - - var_offset = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + var); - if (op_array->opcodes[end].opcode == ZEND_ROPE_END) { - var_offset |= ZEND_LIVE_ROPE; - } else if (op_array->opcodes[end].opcode == ZEND_END_SILENCE) { - var_offset |= ZEND_LIVE_SILENCE; - } else if (op_array->opcodes[end].opcode == ZEND_FE_FREE) { - var_offset |= ZEND_LIVE_LOOP; - } - - if (opTs[start]) { - if (start > 0 && opTs[start-1] == opTs[start]) { - op_var_info *opT = opTs[start]; - do { - count++; - opT = opT->next; - } while (opT); - count += 2; - } else { - count++; - } - } else { - count += 2; - } - - new_opTs = zend_arena_alloc(&CG(arena), sizeof(op_var_info)); - new_opTs->next = opTs[start]; - new_opTs->var = var_offset; - opTs[start] = new_opTs; - - for (j = start + 1; j < end; j++) { - if (opTs[j-1]->next == opTs[j]) { - opTs[j] = opTs[j-1]; - } else { - if (opTs[j]) { - count++; - } else { - count += 2; - } - new_opTs = zend_arena_alloc(&CG(arena), sizeof(op_var_info)); - new_opTs->next = opTs[j]; - new_opTs->var = var_offset; - opTs[j] = new_opTs; - } - } - } - - return count; -} - -static zend_always_inline uint32_t *generate_var_liveliness_info_ex(zend_op_array *op_array, zend_bool done_pass_two) -{ - zend_op *opline, *end; - uint32_t var, i, op_live_total = 0; - uint32_t *info, info_off = op_array->last + 1; - void *checkpoint = zend_arena_checkpoint(CG(arena)); - uint32_t *Tstart = zend_arena_alloc(&CG(arena), sizeof(uint32_t) * op_array->T); - op_var_info **opTs = zend_arena_alloc(&CG(arena), sizeof(op_var_info *) * op_array->last); - - memset(Tstart, -1, sizeof(uint32_t) * op_array->T); - memset(opTs, 0, sizeof(op_var_info *) * op_array->last); - - opline = op_array->opcodes; - end = opline + op_array->last; - do { - if ((opline->result_type & (IS_VAR|IS_TMP_VAR)) - && !((opline)->result_type & EXT_TYPE_UNUSED) - /* the following opcodes are used in inline branching - * (and anyway always bool, so no need to free) and may - * not be defined depending on the taken branch */ - && opline->opcode != ZEND_BOOL - && opline->opcode != ZEND_JMPZ_EX - && opline->opcode != ZEND_JMPNZ_EX - /* these two consecutive ops appear on ternary, - * the result of true branch is undefined for false branch */ - && (opline->opcode != ZEND_QM_ASSIGN || (opline + 1)->opcode != ZEND_JMP) - /* exception for opcache, it might nowhere use the temporary - * (anyway bool, so no need to free) */ - && opline->opcode != ZEND_CASE - /* the following opcodes reuse TMP created before */ - && opline->opcode != ZEND_ROPE_ADD - && opline->opcode != ZEND_ADD_ARRAY_ELEMENT - /* passes fast_call */ - && opline->opcode != ZEND_FAST_CALL - /* the following opcodes pass class_entry */ - && opline->opcode != ZEND_FETCH_CLASS - && opline->opcode != ZEND_DECLARE_CLASS - && opline->opcode != ZEND_DECLARE_INHERITED_CLASS - && opline->opcode != ZEND_DECLARE_INHERITED_CLASS_DELAYED - && opline->opcode != ZEND_DECLARE_ANON_CLASS - && opline->opcode != ZEND_DECLARE_ANON_INHERITED_CLASS) { - if (done_pass_two) { - var = EX_VAR_TO_NUM(opline->result.var) - op_array->last_var; - } else { - var = opline->result.var; - } - /* Objects created via ZEND_NEW are only fully initialized after the DO_FCALL (constructor call) */ - if (opline->opcode == ZEND_NEW) { - Tstart[var] = opline->op2.opline_num - 1; - } else { - Tstart[var] = opline - op_array->opcodes; - } - } - if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) { - if (done_pass_two) { - var = EX_VAR_TO_NUM(opline->op1.var) - op_array->last_var; - } else { - var = opline->op1.var; - } - if (Tstart[var] != (uint32_t)-1 - /* the following opcodes don't free TMP */ - && opline->opcode != ZEND_ROPE_ADD - && opline->opcode != ZEND_FETCH_LIST - && opline->opcode != ZEND_CASE - && opline->opcode != ZEND_FE_FETCH_R - && opline->opcode != ZEND_FE_FETCH_RW) { - op_live_total += liveliness_kill_var(op_array, opline, var, Tstart, opTs); - } - } - if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) { - if (done_pass_two) { - var = EX_VAR_TO_NUM(opline->op2.var) - op_array->last_var; - } else { - var = opline->op2.var; - } - if (Tstart[var] != (uint32_t)-1) { - op_live_total += liveliness_kill_var(op_array, opline, var, Tstart, opTs); - } - } - } while (++opline != end); - -#if ZEND_DEBUG - /* Check that all TMP variable live-ranges are closed */ - for (i = 0; i < op_array->T; i++) { - ZEND_ASSERT(Tstart[i] == (uint32_t)-1); - } -#endif - - if (!op_live_total) { - info = NULL; - } else { - info = emalloc((op_array->last + 1 + op_live_total) * sizeof(uint32_t)); - - for (i = 0; i < op_array->last; i++) { - if (!opTs[i]) { - info[i] = (uint32_t)-1; - } else if (i > 0 && opTs[i-1] == opTs[i]) { - info[i] = info[i-1]; - } else { - op_var_info *opT = opTs[i]; - info[i] = info_off; - while (opT) { - info[info_off++] = opT->var; - opT = opT->next; - } - info[info_off++] = (uint32_t)-1; - } - } - info[op_array->last] = info_off; - ZEND_ASSERT(info_off == op_array->last + 1 + op_live_total); - } - - zend_arena_release(&CG(arena), checkpoint); - return info; -} - -ZEND_API void zend_generate_var_liveliness_info(zend_op_array *op_array) -{ - op_array->T_liveliness = generate_var_liveliness_info_ex(op_array, 0); -} - -ZEND_API void zend_regenerate_var_liveliness_info(zend_op_array *op_array) -{ - if (op_array->T_liveliness) { - efree(op_array->T_liveliness); - } - op_array->T_liveliness = generate_var_liveliness_info_ex(op_array, 1); -} - int print_class(zend_class_entry *class_entry) { printf("Class %s:\n", ZSTR_VAL(class_entry->name)); |