From: Dmitry Stogov Date: Thu, 11 Jan 2018 16:15:52 +0000 (+0300) Subject: Get rid of zend_op_array.early_binding X-Git-Tag: php-7.3.0alpha1~658 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c9034c3b3344287a1a636e43dbcb781bcfbd31af;p=php Get rid of zend_op_array.early_binding --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 68cd87d40b..dbabfb3633 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1217,12 +1217,7 @@ void zend_do_early_binding(void) /* {{{ */ ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES) && (ce->type == ZEND_INTERNAL_CLASS))) { if (CG(compiler_options) & ZEND_COMPILE_DELAYED_BINDING) { - uint32_t *opline_num = &CG(active_op_array)->early_binding; - - while (*opline_num != (uint32_t)-1) { - opline_num = &CG(active_op_array)->opcodes[*opline_num].result.opline_num; - } - *opline_num = opline - CG(active_op_array)->opcodes; + CG(active_op_array)->fn_flags |= ZEND_ACC_EARLY_BINDING; opline->opcode = ZEND_DECLARE_INHERITED_CLASS_DELAYED; opline->result_type = IS_UNUSED; opline->result.opline_num = -1; @@ -1287,11 +1282,33 @@ static void zend_mark_function_as_generator() /* {{{ */ } /* }}} */ -ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array) /* {{{ */ +ZEND_API uint32_t zend_build_delayed_early_binding_list(const zend_op_array *op_array) /* {{{ */ +{ + if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) { + uint32_t first_early_binding_opline = (uint32_t)-1; + uint32_t *prev_opline_num = &first_early_binding_opline; + zend_op *opline = op_array->opcodes; + zend_op *end = opline + op_array->last; + + while (opline < end) { + if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) { + *prev_opline_num = opline - op_array->opcodes; + prev_opline_num = &opline->result.opline_num; + } + ++opline; + } + *prev_opline_num = -1; + return first_early_binding_opline; + } + return (uint32_t)-1; +} +/* }}} */ + +ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array, uint32_t first_early_binding_opline) /* {{{ */ { - if (op_array->early_binding != (uint32_t)-1) { + if (first_early_binding_opline != (uint32_t)-1) { zend_bool orig_in_compilation = CG(in_compilation); - uint32_t opline_num = op_array->early_binding; + uint32_t opline_num = first_early_binding_opline; zend_class_entry *ce; CG(in_compilation) = 1; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index c9aa2261e5..1b0d0d9d32 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -203,7 +203,6 @@ typedef struct _zend_oparray_context { * Free flags: * 0x10 * 0x20 - * 0x8000 * 0x2000000 */ @@ -227,6 +226,9 @@ typedef struct _zend_oparray_context { #define ZEND_ACC_CTOR 0x2000 #define ZEND_ACC_DTOR 0x4000 +/* "main" op_array with ZEND_DECLARE_INHERITED_CLASS_DELAYED opcodes */ +#define ZEND_ACC_EARLY_BINDING 0x8000 + /* method flag used by Closure::__invoke() */ #define ZEND_ACC_USER_ARG_INFO 0x80 @@ -392,7 +394,6 @@ struct _zend_op_array { uint32_t line_start; uint32_t line_end; zend_string *doc_comment; - uint32_t early_binding; /* the linked list of delayed declarations */ int last_literal; zval *literals; @@ -723,7 +724,8 @@ void zend_do_free(znode *op1); ZEND_API int do_bind_function(const zend_op_array *op_array, const zend_op *opline, HashTable *function_table, zend_bool compile_time); ZEND_API zend_class_entry *do_bind_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_bool compile_time); ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time); -ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array); +ZEND_API uint32_t zend_build_delayed_early_binding_list(const zend_op_array *op_array); +ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array, uint32_t first_early_binding_opline); void zend_do_extended_info(void); void zend_do_extended_fcall_begin(void); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 4cb423d216..84470a59e4 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -87,8 +87,6 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->fn_flags = 0; - op_array->early_binding = -1; - op_array->last_literal = 0; op_array->literals = NULL; diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 8207eafa81..da4f7e5902 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -876,7 +876,7 @@ optimize_const_unary_op: } /* Rebuild plain (optimized) op_array from CFG */ -static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array) +static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_optimizer_ctx *ctx) { zend_basic_block *blocks = cfg->blocks; zend_basic_block *end = blocks + cfg->blocks_count; @@ -1093,20 +1093,10 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array) } /* adjust early binding list */ - if (op_array->early_binding != (uint32_t)-1) { - uint32_t *opline_num = &op_array->early_binding; - zend_op *end; - - opline = op_array->opcodes; - end = opline + op_array->last; - while (opline < end) { - if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) { - *opline_num = opline - op_array->opcodes; - opline_num = &opline->result.opline_num; - } - ++opline; - } - *opline_num = -1; + if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) { + ZEND_ASSERT(op_array == &ctx->script->main_op_array); + ctx->script->first_early_binding_opline = + zend_build_delayed_early_binding_list(op_array); } /* rebuild map (just for printing) */ @@ -1953,7 +1943,7 @@ void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx) zend_bitset_clear(usage, bitset_len); zend_t_usage(&cfg, op_array, usage, ctx); - assemble_code_blocks(&cfg, op_array); + assemble_code_blocks(&cfg, op_array, ctx); if (ctx->debug_level & ZEND_DUMP_AFTER_BLOCK_PASS) { zend_dump_op_array(op_array, ZEND_DUMP_CFG | ZEND_DUMP_HIDE_UNREACHABLE, "after block pass", &cfg); diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index 61047e8064..f24d407eeb 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -125,7 +125,7 @@ int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, return SUCCESS; } -static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa) +static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_optimizer_ctx *ctx) { zend_basic_block *blocks = ssa->cfg.blocks; zend_basic_block *end = blocks + ssa->cfg.blocks_count; @@ -263,9 +263,10 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa) } /* update early binding list */ - if (op_array->early_binding != (uint32_t)-1) { - uint32_t *opline_num = &op_array->early_binding; + if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) { + uint32_t *opline_num = &ctx->script->first_early_binding_opline; + ZEND_ASSERT(op_array == &ctx->script->main_op_array); do { *opline_num -= shiftlist[*opline_num]; opline_num = &op_array->opcodes[*opline_num].result.opline_num; @@ -1177,7 +1178,7 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx #endif if (remove_nops) { - zend_ssa_remove_nops(op_array, ssa); + zend_ssa_remove_nops(op_array, ssa, ctx); #if ZEND_DEBUG_DFA ssa_verify_integrity(op_array, ssa, "after nop"); #endif diff --git a/ext/opcache/Optimizer/nop_removal.c b/ext/opcache/Optimizer/nop_removal.c index 9d8377cedc..c7ecad4d0e 100644 --- a/ext/opcache/Optimizer/nop_removal.c +++ b/ext/opcache/Optimizer/nop_removal.c @@ -31,7 +31,7 @@ #include "zend_execute.h" #include "zend_vm.h" -void zend_optimizer_nop_removal(zend_op_array *op_array) +void zend_optimizer_nop_removal(zend_op_array *op_array, zend_optimizer_ctx *ctx) { zend_op *end, *opline; uint32_t new_count, i, shift; @@ -98,9 +98,10 @@ void zend_optimizer_nop_removal(zend_op_array *op_array) } /* update early binding list */ - if (op_array->early_binding != (uint32_t)-1) { - uint32_t *opline_num = &op_array->early_binding; + if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) { + uint32_t *opline_num = &ctx->script->first_early_binding_opline; + ZEND_ASSERT(op_array == &ctx->script->main_op_array); do { *opline_num -= shiftlist[*opline_num]; opline_num = &op_array->opcodes[*opline_num].result.opline_num; diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index d5975f1414..a5ac88651c 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -1055,7 +1055,7 @@ static void zend_optimize(zend_op_array *op_array, * - remove NOPs */ if (((ZEND_OPTIMIZER_PASS_10|ZEND_OPTIMIZER_PASS_5) & ctx->optimization_level) == ZEND_OPTIMIZER_PASS_10) { - zend_optimizer_nop_removal(op_array); + zend_optimizer_nop_removal(op_array, ctx); if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_10) { zend_dump_op_array(op_array, 0, "after pass 10", NULL); } diff --git a/ext/opcache/Optimizer/zend_optimizer.h b/ext/opcache/Optimizer/zend_optimizer.h index 27b7cedd38..e1c96bec45 100644 --- a/ext/opcache/Optimizer/zend_optimizer.h +++ b/ext/opcache/Optimizer/zend_optimizer.h @@ -84,6 +84,7 @@ typedef struct _zend_script { zend_op_array main_op_array; HashTable function_table; HashTable class_table; + uint32_t first_early_binding_opline; /* the linked list of delayed declarations */ } zend_script; int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level); diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h index 07decce3b4..914e6e717a 100644 --- a/ext/opcache/Optimizer/zend_optimizer_internal.h +++ b/ext/opcache/Optimizer/zend_optimizer_internal.h @@ -102,7 +102,7 @@ void zend_optimize_dfa(zend_op_array *op_array, zend_optimizer_ctx *ctx); int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa); void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa, zend_call_info **call_map); void zend_optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *ctx); -void zend_optimizer_nop_removal(zend_op_array *op_array); +void zend_optimizer_nop_removal(zend_op_array *op_array, zend_optimizer_ctx *ctx); void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx); void zend_optimizer_compact_vars(zend_op_array *op_array); int zend_optimizer_is_disabled_func(const char *name, size_t len); diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 347b5d6ed4..aa84b318c3 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -1723,6 +1723,10 @@ static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handl further anyway. */ zend_accel_move_user_functions(&ZCG(function_table), &new_persistent_script->script.function_table); + new_persistent_script->script.first_early_binding_opline = + (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) ? + zend_build_delayed_early_binding_list(op_array) : + (uint32_t)-1; new_persistent_script->script.main_op_array = *op_array; efree(op_array); /* we have valid persistent_script, so it's safe to free op_array */ diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index ce0c8f4ada..1e9b5e9868 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -733,10 +733,10 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, } } - if (op_array->early_binding != (uint32_t)-1) { + if (persistent_script->script.first_early_binding_opline != (uint32_t)-1) { zend_string *orig_compiled_filename = CG(compiled_filename); CG(compiled_filename) = persistent_script->script.filename; - zend_do_delayed_early_binding(op_array); + zend_do_delayed_early_binding(op_array, persistent_script->script.first_early_binding_opline); CG(compiled_filename) = orig_compiled_filename; }