diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index b015438b72b52..00ecdd2d2db3d 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1998,7 +1998,7 @@ ZEND_FUNCTION(create_function) if (retval==SUCCESS) { zend_op_array *func; - HashTable *static_variables; + zval *static_variables; func = zend_hash_str_find_ptr(EG(function_table), LAMBDA_TEMP_FUNCNAME, sizeof(LAMBDA_TEMP_FUNCNAME)-1); if (!func) { diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 55bea0b9a8c47..ad810249d57c9 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -424,10 +424,20 @@ static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp) /* {{{ ALLOC_HASHTABLE(debug_info); zend_hash_init(debug_info, 8, NULL, ZVAL_PTR_DTOR, 0); - if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) { - HashTable *static_variables = closure->func.op_array.static_variables; - ZVAL_ARR(&val, zend_array_dup(static_variables)); + if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.last_static_var) { + int i; + zval *entry; + + array_init(&val); zend_hash_str_update(debug_info, "static", sizeof("static")-1, &val); + for (i = 0; i < closure->func.op_array.last_static_var; i++) { + entry = &closure->func.op_array.static_variables[i]; + if (Z_TYPE_P(entry) == IS_REFERENCE && Z_REFCOUNT_P(entry) == 1) { + entry = Z_REFVAL_P(entry); + } + Z_TRY_ADDREF_P(entry); + zend_hash_update(Z_ARRVAL(val), closure->func.op_array.static_vars[i], entry); + } } if (Z_TYPE(closure->this_ptr) != IS_UNDEF) { @@ -474,10 +484,15 @@ static HashTable *zend_closure_get_gc(zval *obj, zval **table, int *n) /* {{{ */ { zend_closure *closure = (zend_closure *)Z_OBJ_P(obj); - *table = Z_TYPE(closure->this_ptr) != IS_NULL ? &closure->this_ptr : NULL; - *n = Z_TYPE(closure->this_ptr) != IS_NULL ? 1 : 0; - return (closure->func.type == ZEND_USER_FUNCTION) ? - closure->func.op_array.static_variables : NULL; + if (closure->func.type == ZEND_USER_FUNCTION) { + *n = closure->func.op_array.last_static_var + 1; + *table = closure->func.op_array.static_variables; + ZVAL_COPY_VALUE(*table + closure->func.op_array.last_static_var, &closure->this_ptr); + } else { + *n = Z_ISUNDEF(closure->this_ptr)? 0 : 1; + *table = Z_ISUNDEF(closure->this_ptr)? NULL : &closure->this_ptr; + } + return NULL; } /* }}} */ @@ -569,9 +584,15 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent memcpy(&closure->func, func, sizeof(zend_op_array)); closure->func.common.prototype = (zend_function*)closure; closure->func.common.fn_flags |= ZEND_ACC_CLOSURE; - if (closure->func.op_array.static_variables) { - closure->func.op_array.static_variables = - zend_array_dup(closure->func.op_array.static_variables); + closure->func.op_array.static_variables = (zval*)emalloc(sizeof(zval) * (func->op_array.last_static_var + 1)); + + if (func->op_array.static_variables) { + int i = func->op_array.last_static_var; + zval *static_variables = func->op_array.static_variables; + while (i > 0) { + i--; + ZVAL_COPY(&closure->func.op_array.static_variables[i], &static_variables[i]); + } } if (UNEXPECTED(!closure->func.op_array.run_time_cache)) { closure->func.op_array.run_time_cache = func->op_array.run_time_cache = zend_arena_alloc(&CG(arena), func->op_array.cache_size); @@ -626,11 +647,11 @@ ZEND_API void zend_create_fake_closure(zval *res, zend_function *func, zend_clas } /* }}} */ -void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var) /* {{{ */ +void zend_closure_bind_var(zval *closure_zv, uint32_t num, zval *var) /* {{{ */ { zend_closure *closure = (zend_closure *) Z_OBJ_P(closure_zv); - HashTable *static_variables = closure->func.op_array.static_variables; - zend_hash_update(static_variables, var_name, var); + zval *static_variables = closure->func.op_array.static_variables; + ZVAL_COPY_VALUE(&static_variables[num], var); } /* }}} */ diff --git a/Zend/zend_closures.h b/Zend/zend_closures.h index 7f8bac430c98f..22d9228d27063 100644 --- a/Zend/zend_closures.h +++ b/Zend/zend_closures.h @@ -25,7 +25,7 @@ BEGIN_EXTERN_C() void zend_register_closure_ce(void); -void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var); +void zend_closure_bind_var(zval *closure_zv, uint32_t num, zval *var); extern ZEND_API zend_class_entry *zend_ce_closure; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0384e8b5cf2b8..ff4db9624eaa4 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -230,6 +230,7 @@ void zend_oparray_context_begin(zend_oparray_context *prev_context) /* {{{ */ *prev_context = CG(context); CG(context).opcodes_size = INITIAL_OP_ARRAY_SIZE; CG(context).vars_size = 0; + CG(context).static_vars_size = 0; CG(context).literals_size = 0; CG(context).backpatch_count = 0; CG(context).in_finally = 0; @@ -413,8 +414,7 @@ static int lookup_cv(zend_op_array *op_array, zend_string* name) /* {{{ */{ } i++; } - i = op_array->last_var; - op_array->last_var++; + i = op_array->last_var++; if (op_array->last_var > CG(context).vars_size) { CG(context).vars_size += 16; /* FIXME */ op_array->vars = erealloc(op_array->vars, CG(context).vars_size * sizeof(zend_string*)); @@ -1025,8 +1025,12 @@ ZEND_API void function_add_ref(zend_function *function) /* {{{ */ (*op_array->refcount)++; } if (op_array->static_variables) { - if (!(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) { - GC_REFCOUNT(op_array->static_variables)++; + zval *static_vars = op_array->static_variables; + int i = op_array->last_static_var; + op_array->static_variables = emalloc(op_array->last_static_var * (sizeof(zval))); + while (i > 0) { + i--; + ZVAL_COPY(&op_array->static_variables[i], &static_vars[i]); } } op_array->run_time_cache = NULL; @@ -3719,39 +3723,53 @@ void zend_compile_global_var(zend_ast *ast) /* {{{ */ } /* }}} */ +static uint32_t zend_lookup_static_var(zend_op_array *op_array, zend_string *name) /* {{{ */ { + int i = 0; + zend_ulong hash_value = zend_string_hash_val(name); + + while (i < op_array->last_static_var) { + if (ZSTR_VAL(op_array->static_vars[i]) == ZSTR_VAL(name) || + (ZSTR_H(op_array->static_vars[i]) == hash_value && + ZSTR_LEN(op_array->static_vars[i]) == ZSTR_LEN(name) && + memcmp(ZSTR_VAL(op_array->static_vars[i]), ZSTR_VAL(name), ZSTR_LEN(name)) == 0)) { + zend_string_release(name); + return i; + } + i++; + } + i = op_array->last_static_var++; + if (op_array->last_static_var > CG(context).static_vars_size) { + CG(context).static_vars_size += 8; + op_array->static_vars = erealloc(op_array->static_vars, CG(context).static_vars_size * sizeof(zend_string*)); + op_array->static_variables = erealloc(op_array->static_variables, CG(context).static_vars_size * sizeof(zval)); + } + op_array->static_vars[i] = zend_new_interned_string(name); + return i; +} +/* }}} */ + static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, zend_bool by_ref) /* {{{ */ { - znode var_node, result; zend_op *opline; + uint32_t var_num; + zend_string *var_name = zend_ast_get_str(var_ast); - zend_compile_expr(&var_node, var_ast); - - if (!CG(active_op_array)->static_variables) { - if (CG(active_op_array)->scope) { - CG(active_op_array)->scope->ce_flags |= ZEND_HAS_STATIC_IN_METHODS; - } - ALLOC_HASHTABLE(CG(active_op_array)->static_variables); - zend_hash_init(CG(active_op_array)->static_variables, 8, NULL, ZVAL_PTR_DTOR, 0); + if (zend_string_equals_literal(var_name, "this")) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as lexical variable"); } - if (GC_REFCOUNT(CG(active_op_array)->static_variables) > 1) { - if (!(GC_FLAGS(CG(active_op_array)->static_variables) & IS_ARRAY_IMMUTABLE)) { - GC_REFCOUNT(CG(active_op_array)->static_variables)--; - } - CG(active_op_array)->static_variables = zend_array_dup(CG(active_op_array)->static_variables); + if (zend_is_auto_global(var_name)) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use auto-global as lexical variable"); } - zend_hash_update(CG(active_op_array)->static_variables, Z_STR(var_node.u.constant), value); - opline = zend_emit_op(&result, by_ref ? ZEND_FETCH_W : ZEND_FETCH_R, &var_node, NULL); - opline->extended_value = ZEND_FETCH_STATIC; + var_num = zend_lookup_static_var(CG(active_op_array), zend_string_copy(var_name)); + ZVAL_COPY_VALUE(&CG(active_op_array)->static_variables[var_num], value); - if (by_ref) { - zend_ast *fetch_ast = zend_ast_create(ZEND_AST_VAR, var_ast); - zend_emit_assign_ref_znode(fetch_ast, &result); - } else { - zend_ast *fetch_ast = zend_ast_create(ZEND_AST_VAR, var_ast); - zend_emit_assign_znode(fetch_ast, &result); - } + opline = zend_emit_op(NULL, ZEND_FETCH_STATIC, NULL, NULL); + opline->op1_type = IS_CV; + opline->op1.num = lookup_cv(CG(active_op_array), zend_string_copy(var_name)); + opline->op2.num = var_num; + opline->extended_value = by_ref; } /* }}} */ @@ -4896,7 +4914,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ } /* }}} */ -static void zend_compile_closure_binding(znode *closure, zend_ast *uses_ast) /* {{{ */ +static void zend_compile_closure_binding(zend_op_array *op_array, znode *closure, zend_ast *uses_ast) /* {{{ */ { zend_ast_list *list = zend_ast_get_list(uses_ast); uint32_t i; @@ -4917,7 +4935,8 @@ static void zend_compile_closure_binding(znode *closure, zend_ast *uses_ast) /* opline = zend_emit_op(NULL, ZEND_BIND_LEXICAL, closure, NULL); opline->op2_type = IS_CV; - opline->op2.var = lookup_cv(CG(active_op_array), zend_string_copy(var_name)); + opline->op2.num = lookup_cv(CG(active_op_array), zend_string_copy(var_name)); + opline->result.var = op_array->last_static_var++; opline->extended_value = by_ref; } } @@ -5186,7 +5205,7 @@ void zend_compile_func_decl(znode *result, zend_ast *ast) /* {{{ */ } else { zend_begin_func_decl(result, op_array, decl); if (uses_ast) { - zend_compile_closure_binding(result, uses_ast); + zend_compile_closure_binding(op_array, result, uses_ast); } } @@ -5209,8 +5228,11 @@ void zend_compile_func_decl(znode *result, zend_ast *ast) /* {{{ */ zend_compile_params(params_ast, return_type_ast); if (uses_ast) { + /* the order must be the same as zend_compile_closure_binding */ + op_array->last_static_var = 0; zend_compile_closure_uses(uses_ast); } + zend_compile_stmt(stmt_ast); if (is_method) { diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 2984f75b64a85..b403384c23cbb 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -189,6 +189,7 @@ typedef struct _zend_live_range { typedef struct _zend_oparray_context { uint32_t opcodes_size; int vars_size; + int static_vars_size; int literals_size; int backpatch_count; int in_finally; @@ -380,7 +381,9 @@ struct _zend_op_array { zend_try_catch_element *try_catch_array; /* static variables support */ - HashTable *static_variables; + zend_string **static_vars; + zval *static_variables; + int last_static_var; zend_string *filename; uint32_t line_start; @@ -890,7 +893,6 @@ ZEND_API void zend_assert_valid_class_name(const zend_string *const_name); /* global/local fetches */ #define ZEND_FETCH_GLOBAL 0x00000000 #define ZEND_FETCH_LOCAL 0x10000000 -#define ZEND_FETCH_STATIC 0x20000000 #define ZEND_FETCH_GLOBAL_LOCK 0x40000000 #define ZEND_FETCH_TYPE_MASK 0x70000000 diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 8f30373e87476..fffcb9cbb7b3c 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1537,15 +1537,6 @@ static zend_always_inline HashTable *zend_get_target_symbol_table(zend_execute_d if (EXPECTED(fetch_type == ZEND_FETCH_GLOBAL_LOCK) || EXPECTED(fetch_type == ZEND_FETCH_GLOBAL)) { ht = &EG(symbol_table); - } else if (EXPECTED(fetch_type == ZEND_FETCH_STATIC)) { - ZEND_ASSERT(EX(func)->op_array.static_variables != NULL); - ht = EX(func)->op_array.static_variables; - if (GC_REFCOUNT(ht) > 1) { - if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) { - GC_REFCOUNT(ht)--; - } - EX(func)->op_array.static_variables = ht = zend_array_dup(ht); - } } else { ZEND_ASSERT(fetch_type == ZEND_FETCH_LOCAL); if (!EX(symbol_table)) { diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index cf7688e8e4703..92ea67e87fd54 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -78,11 +78,20 @@ static zend_function *zend_duplicate_function(zend_function *func, zend_class_en /* reuse the same op_array structure */ return func; } - if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) { - GC_REFCOUNT(func->op_array.static_variables)++; - } new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); memcpy(new_function, func, sizeof(zend_op_array)); + if (func->op_array.static_variables) { + int i = func->op_array.last_static_var; + if (func->op_array.fn_flags & ZEND_ACC_CLOSURE) { + new_function->op_array.static_variables = emalloc(sizeof(zval) * (func->op_array.last_static_var + 1)); + } else { + new_function->op_array.static_variables = emalloc(sizeof(zval) * func->op_array.last_static_var); + } + while (i > 0) { + i--; + ZVAL_COPY(&new_function->op_array.static_variables[i], &func->op_array.static_variables[i]); + } + } } return new_function; } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 05c29ee8728ff..92da75b5e84cf 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -82,7 +82,10 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->try_catch_array = NULL; op_array->last_live_range = 0; + op_array->last_static_var = 0; op_array->static_variables = NULL; + op_array->static_vars = NULL; + op_array->last_try_catch = 0; op_array->this_var = -1; @@ -135,9 +138,13 @@ ZEND_API void zend_function_dtor(zval *zv) ZEND_API void zend_cleanup_op_array_data(zend_op_array *op_array) { - if (op_array->static_variables && - !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) { - zend_hash_clean(op_array->static_variables); + if (op_array->static_variables) { + int i = op_array->last_static_var; + while (i > 0) { + i--; + zval_ptr_dtor(&op_array->static_variables[i]); + ZVAL_NULL(&op_array->static_variables[i]); + } } } @@ -364,11 +371,13 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) zval *end; uint32_t i; - if (op_array->static_variables && - !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) { - if (--GC_REFCOUNT(op_array->static_variables) == 0) { - zend_array_destroy(op_array->static_variables); + if (op_array->static_variables) { + i = op_array->last_static_var; + while (i > 0) { + i--; + zval_ptr_dtor(&op_array->static_variables[i]); } + efree(op_array->static_variables); } if (op_array->run_time_cache && !op_array->function_name) { @@ -382,6 +391,16 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) efree_size(op_array->refcount, sizeof(*(op_array->refcount))); + if (op_array->static_vars) { + i = op_array->last_static_var; + while (i > 0) { + i--; + zend_string_release(op_array->static_vars[i]); + } + efree(op_array->static_vars); + } + + if (op_array->vars) { i = op_array->last_var; while (i > 0) { @@ -627,6 +646,14 @@ 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; } + + if (op_array->fn_flags & ZEND_ACC_CLOSURE) { + op_array->static_variables = (zval *)erealloc(op_array->static_variables, sizeof(zval) * (op_array->last_static_var + 1)); + } else if (CG(context).static_vars_size != op_array->last_static_var) { + op_array->static_variables = (zval *)erealloc(op_array->static_variables, sizeof(zval) * op_array->last_static_var); + } + CG(context).static_vars_size = op_array->last_static_var; + opline = op_array->opcodes; end = opline + op_array->last; while (opline < end) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index b0637fcc55a27..c27b0ef288daf 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1474,14 +1474,7 @@ ZEND_VM_HELPER(zend_fetch_var_address_helper, CONST|TMPVAR|CV, UNUSED, int type) } } - if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_STATIC) { - if (Z_CONSTANT_P(retval)) { - if (UNEXPECTED(zval_update_constant_ex(retval, 1, NULL) != SUCCESS)) { - FREE_OP1(); - HANDLE_EXCEPTION(); - } - } - } else if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { + if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { FREE_OP1(); } @@ -8002,7 +7995,6 @@ ZEND_VM_HANDLER(182, ZEND_BIND_LEXICAL, TMP, CV, REF) USE_OPLINE zend_free_op free_op1, free_op2; zval *closure, *var; - zend_string *var_name; closure = GET_OP1_ZVAL_PTR(BP_VAR_R); if (opline->extended_value) { @@ -8022,9 +8014,30 @@ ZEND_VM_HANDLER(182, ZEND_BIND_LEXICAL, TMP, CV, REF) ZVAL_DEREF(var); Z_TRY_ADDREF_P(var); } + zend_closure_bind_var(closure, opline->result.num, var); + ZEND_VM_NEXT_OPCODE(); +} + +ZEND_VM_HANDLER(183, ZEND_FETCH_STATIC, CV, UNUSED, REF) +{ + USE_OPLINE + zval *var = GET_OP1_ZVAL_PTR(BP_VAR_W); + zval *val = &EX(func)->op_array.static_variables[opline->op2.num]; + + if (UNEXPECTED(Z_CONSTANT_P(val))) { + SAVE_OPLINE(); + if (UNEXPECTED(zval_update_constant_ex(val, 1, NULL) != SUCCESS)) { + HANDLE_EXCEPTION(); + } + } + + if (opline->extended_value) { + ZVAL_MAKE_REF(val); + } + + zval_ptr_dtor(var); + ZVAL_COPY(var, val); - var_name = CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var)); - zend_closure_bind_var(closure, var_name, var); ZEND_VM_NEXT_OPCODE(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 4de081d4760e9..73d925858e9ac 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -7199,14 +7199,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_ } } - if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_STATIC) { - if (Z_CONSTANT_P(retval)) { - if (UNEXPECTED(zval_update_constant_ex(retval, 1, NULL) != SUCCESS)) { - - HANDLE_EXCEPTION(); - } - } - } else if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { + if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { } @@ -14215,7 +14208,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_LEXICAL_SPEC_TMP_CV_HANDL USE_OPLINE zend_free_op free_op1; zval *closure, *var; - zend_string *var_name; closure = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1); if (opline->extended_value) { @@ -14235,9 +14227,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_LEXICAL_SPEC_TMP_CV_HANDL ZVAL_DEREF(var); Z_TRY_ADDREF_P(var); } - - var_name = CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var)); - zend_closure_bind_var(closure, var_name, var); + zend_closure_bind_var(closure, opline->result.num, var); ZEND_VM_NEXT_OPCODE(); } @@ -33627,14 +33617,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_ } } - if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_STATIC) { - if (Z_CONSTANT_P(retval)) { - if (UNEXPECTED(zval_update_constant_ex(retval, 1, NULL) != SUCCESS)) { - - HANDLE_EXCEPTION(); - } - } - } else if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { + if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { } @@ -34620,6 +34603,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(Z ZEND_VM_RETURN(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *var = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var); + zval *val = &EX(func)->op_array.static_variables[opline->op2.num]; + + if (UNEXPECTED(Z_CONSTANT_P(val))) { + SAVE_OPLINE(); + if (UNEXPECTED(zval_update_constant_ex(val, 1, NULL) != SUCCESS)) { + HANDLE_EXCEPTION(); + } + } + + if (opline->extended_value) { + ZVAL_MAKE_REF(val); + } + + zval_ptr_dtor(var); + ZVAL_COPY(var, val); + + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -42016,14 +42022,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_ } } - if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_STATIC) { - if (Z_CONSTANT_P(retval)) { - if (UNEXPECTED(zval_update_constant_ex(retval, 1, NULL) != SUCCESS)) { - zval_ptr_dtor_nogc(free_op1); - HANDLE_EXCEPTION(); - } - } - } else if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { + if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) != ZEND_FETCH_GLOBAL_LOCK) { zval_ptr_dtor_nogc(free_op1); } @@ -49390,6 +49389,31 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_FETCH_STATIC_SPEC_CV_UNUSED_HANDLER, + ZEND_NULL_HANDLER, ZEND_NULL_HANDLER }; zend_opcode_handlers = labels; diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index a2ed83ee9e418..d81ff2d9901d8 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -21,7 +21,7 @@ #include #include -static const char *zend_vm_opcodes_names[183] = { +static const char *zend_vm_opcodes_names[184] = { "ZEND_NOP", "ZEND_ADD", "ZEND_SUB", @@ -205,9 +205,10 @@ static const char *zend_vm_opcodes_names[183] = { "ZEND_ISSET_ISEMPTY_STATIC_PROP", "ZEND_FETCH_CLASS_CONSTANT", "ZEND_BIND_LEXICAL", + "ZEND_FETCH_STATIC", }; -static uint32_t zend_vm_opcodes_flags[183] = { +static uint32_t zend_vm_opcodes_flags[184] = { 0x00000000, 0x00000707, 0x00000707, @@ -391,6 +392,7 @@ static uint32_t zend_vm_opcodes_flags[183] = { 0x00027307, 0x00000373, 0x00100101, + 0x00100101, }; ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) { diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index bb677134c668d..11cafaae7143e 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -255,7 +255,8 @@ END_EXTERN_C() #define ZEND_ISSET_ISEMPTY_STATIC_PROP 180 #define ZEND_FETCH_CLASS_CONSTANT 181 #define ZEND_BIND_LEXICAL 182 +#define ZEND_FETCH_STATIC 183 -#define ZEND_VM_LAST_OPCODE 182 +#define ZEND_VM_LAST_OPCODE 183 #endif diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 24a9157f2c84c..45b24ae1f31c0 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -1608,6 +1608,7 @@ static void zend_t_usage(zend_cfg *cfg, zend_op_array *op_array, zend_bitset use case ZEND_PRE_DEC: case ZEND_ASSIGN: case ZEND_ASSIGN_REF: + case ZEND_FETCH_STATIC: case ZEND_DO_FCALL: case ZEND_DO_ICALL: case ZEND_DO_UCALL: diff --git a/ext/opcache/Optimizer/zend_dfg.c b/ext/opcache/Optimizer/zend_dfg.c index 1266ae5e542c3..b7a1aba8e225d 100644 --- a/ext/opcache/Optimizer/zend_dfg.c +++ b/ext/opcache/Optimizer/zend_dfg.c @@ -100,6 +100,7 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg case ZEND_ADD_ARRAY_ELEMENT: case ZEND_INIT_ARRAY: case ZEND_BIND_LEXICAL: + case ZEND_FETCH_STATIC: if (!DFG_ISSET(use, set_size, j, EX_VAR_TO_NUM(opline->op1.var))) { // FIXME: include into "use" to ...? DFG_SET(use, set_size, j, EX_VAR_TO_NUM(opline->op1.var)); diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c index 1eacd401b165d..8a69f168c6875 100644 --- a/ext/opcache/Optimizer/zend_dump.c +++ b/ext/opcache/Optimizer/zend_dump.c @@ -510,9 +510,10 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block * case ZEND_FETCH_LOCAL: fprintf(stderr, " (local)"); break; - case ZEND_FETCH_STATIC: + /*case ZEND_FETCH_STATIC: fprintf(stderr, " (static)"); break; + */ case ZEND_FETCH_GLOBAL_LOCK: fprintf(stderr, " (global+lock)"); break; diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 3206634534c0e..8688629ce2a27 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -3076,6 +3076,9 @@ static void zend_update_type_info(const zend_op_array *op_array, } } break; + case ZEND_FETCH_STATIC: +//TODO: ??? We know nothing expect is_ref? + break; case ZEND_SEND_VAR_EX: case ZEND_SEND_VAR_NO_REF: case ZEND_SEND_REF: diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 1a1cebda9e7dd..c1c7b46c07191 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -773,9 +773,9 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend } else if (op_array->type == ZEND_USER_FUNCTION) { zend_op_array *orig_op_array; if ((orig_op_array = zend_hash_find_ptr(&op_array->scope->function_table, name)) != NULL) { - HashTable *ht = op_array->static_variables; + zval *static_vars = op_array->static_variables; *op_array = *orig_op_array; - op_array->static_variables = ht; + op_array->static_variables = static_vars; } } } ZEND_HASH_FOREACH_END(); @@ -845,9 +845,9 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend } else if (op_array->type == ZEND_USER_FUNCTION) { zend_op_array *orig_op_array; if ((orig_op_array = zend_hash_find_ptr(&op_array->scope->function_table, name)) != NULL) { - HashTable *ht = op_array->static_variables; + zval *static_vars = op_array->static_variables; *op_array = *orig_op_array; - op_array->static_variables = ht; + op_array->static_variables = static_vars; } } } ZEND_HASH_FOREACH_END(); diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index 70c042e946a4e..1f1d6858f769f 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -361,6 +361,13 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags, ssa_vars_count++; } break; + case ZEND_FETCH_STATIC: + if (opline->op1_type == IS_CV) { + ssa_ops[k].op1_def = ssa_vars_count; + var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count; + ssa_vars_count++; + } + break; default: break; } diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index f18488da1c5f1..a473274ce643c 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -2187,10 +2187,10 @@ static void zend_accel_fast_shutdown(void) break; } else { if (func->op_array.static_variables) { - if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) { - if (--GC_REFCOUNT(func->op_array.static_variables) == 0) { - accel_fast_hash_destroy(func->op_array.static_variables); - } + int i = func->op_array.last_static_var; + while (i > 0) { + i--; + accel_fast_zval_dtor(&func->op_array.static_variables[i]); } } zend_accel_fast_del_bucket(EG(function_table), HT_IDX_TO_HASH(_idx-1), _p); @@ -2209,10 +2209,10 @@ static void zend_accel_fast_shutdown(void) ZEND_HASH_FOREACH_PTR(&ce->function_table, func) { if (func->type == ZEND_USER_FUNCTION) { if (func->op_array.static_variables) { - if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) { - if (--GC_REFCOUNT(func->op_array.static_variables) == 0) { - accel_fast_hash_destroy(func->op_array.static_variables); - } + int i = func->op_array.last_static_var; + while (i > 0) { + i--; + accel_fast_zval_dtor(&func->op_array.static_variables[i]); } func->op_array.static_variables = NULL; } diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index 27731dd6249ae..8a7d0f8dc113a 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -48,11 +48,8 @@ static void zend_accel_destroy_zend_function(zval *zv) if (function->type == ZEND_USER_FUNCTION) { if (function->op_array.static_variables) { - if (!(GC_FLAGS(function->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) { - if (--GC_REFCOUNT(function->op_array.static_variables) == 0) { - FREE_HASHTABLE(function->op_array.static_variables); - } - } + zend_cleanup_op_array_data((zend_op_array*)function); + efree(function->op_array.static_variables); function->op_array.static_variables = NULL; } } @@ -277,6 +274,24 @@ static void zend_hash_clone_constants(HashTable *ht, HashTable *source) } } +static void zend_func_copy_ctor(zend_op_array *op_array) +{ + zval *dst, *end, *src = op_array->static_variables; + if (op_array->fn_flags & ZEND_ACC_CLOSURE) { + op_array->static_variables = emalloc(sizeof(zval) * (op_array->last_static_var + 1)); + } else if (src) { + op_array->static_variables = emalloc(sizeof(zval) * op_array->last_static_var); + } + + if (src) { + end = src + op_array->last_static_var; + dst = op_array->static_variables; + for (; src != end; src++, dst++) { + ZVAL_COPY_VALUE(dst, src); + } + } +} + static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class_entry *old_ce, zend_class_entry *ce) { Bucket *p, *q, *end; @@ -321,6 +336,7 @@ static void zend_hash_clone_methods(HashTable *ht, HashTable *source, zend_class /* Copy data */ ZVAL_PTR(&q->val, ARENA_REALLOC(Z_PTR(p->val))); new_entry = (zend_op_array*)Z_PTR(q->val); + zend_func_copy_ctor(new_entry); if ((void*)new_entry->scope >= ZCG(current_persistent_script)->arena_mem && (void*)new_entry->scope < (void*)((char*)ZCG(current_persistent_script)->arena_mem + ZCG(current_persistent_script)->arena_size)) { @@ -571,7 +587,7 @@ static void zend_accel_function_hash_copy(HashTable *target, HashTable *source) } } -static void zend_accel_function_hash_copy_from_shm(HashTable *target, HashTable *source) +static void zend_accel_function_hash_copy_from_shm(HashTable *target, HashTable *source, unique_copy_ctor_func_t pCopyConstructor) { zend_function *function1, *function2; Bucket *p, *end; @@ -594,6 +610,9 @@ static void zend_accel_function_hash_copy_from_shm(HashTable *target, HashTable } else { _zend_hash_append_ptr(target, p->key, ARENA_REALLOC(Z_PTR(p->val))); } + if (pCopyConstructor) { + pCopyConstructor(ARENA_REALLOC(Z_PTR(p->val))); + } } target->nInternalPointer = target->nNumOfElements ? 0 : HT_INVALID_IDX; return; @@ -687,6 +706,7 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, op_array = (zend_op_array *) emalloc(sizeof(zend_op_array)); *op_array = persistent_script->script.main_op_array; + zend_func_copy_ctor(op_array); if (EXPECTED(from_shared_memory)) { zend_hash_init(&ZCG(bind_hash), 10, NULL, NULL, 0); @@ -712,7 +732,7 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, /* we must first to copy all classes and then prepare functions, since functions may try to bind classes - which depend on pre-bind class entries existent in the class table */ if (zend_hash_num_elements(&persistent_script->script.function_table) > 0) { - zend_accel_function_hash_copy_from_shm(CG(function_table), &persistent_script->script.function_table); + zend_accel_function_hash_copy_from_shm(CG(function_table), &persistent_script->script.function_table, (unique_copy_ctor_func_t) zend_func_copy_ctor); } /* Register __COMPILER_HALT_OFFSET__ constant */ diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 6a9bb9c5809f9..966b715d3057b 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -350,12 +350,16 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra void *buf) { if (op_array->static_variables && !IS_SERIALIZED(op_array->static_variables)) { - HashTable *ht; + zval *p, *end; SERIALIZE_PTR(op_array->static_variables); - ht = op_array->static_variables; - UNSERIALIZE_PTR(ht); - zend_file_cache_serialize_hash(ht, script, info, buf, zend_file_cache_serialize_zval); + p = op_array->static_variables; + UNSERIALIZE_PTR(p); + end = p + op_array->last_static_var; + while (p < end) { + zend_file_cache_serialize_zval(p, script, info, buf); + p++; + } } if (op_array->literals && !IS_SERIALIZED(op_array->literals)) { @@ -446,6 +450,21 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra } } + if (op_array->static_vars) { + zend_string **p, **end; + + SERIALIZE_PTR(op_array->static_vars); + p = op_array->static_vars; + UNSERIALIZE_PTR(p); + end = p + op_array->last_static_var; + while (p < end) { + if (!IS_SERIALIZED(*p)) { + SERIALIZE_STR(*p); + } + p++; + } + } + if (op_array->vars) { zend_string **p, **end; @@ -930,12 +949,15 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr void *buf) { if (op_array->static_variables && !IS_UNSERIALIZED(op_array->static_variables)) { - HashTable *ht; + zval *p, *end; UNSERIALIZE_PTR(op_array->static_variables); - ht = op_array->static_variables; - zend_file_cache_unserialize_hash(ht, - script, buf, zend_file_cache_unserialize_zval, ZVAL_PTR_DTOR); + p = op_array->static_variables; + end = p + op_array->last_static_var; + while (p < end) { + zend_file_cache_unserialize_zval(p, script, buf); + p++; + } } if (op_array->literals && !IS_UNSERIALIZED(op_array->literals)) { @@ -1020,6 +1042,20 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr } } + if (op_array->static_vars) { + zend_string **p, **end; + + UNSERIALIZE_PTR(op_array->static_vars); + p = op_array->static_vars; + end = p + op_array->last_static_var; + while (p < end) { + if (!IS_UNSERIALIZED(*p)) { + UNSERIALIZE_STR(*p); + } + p++; + } + } + if (op_array->vars) { zend_string **p, **end; diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 48fefd8918179..5ce19ecfc6ffb 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -467,18 +467,14 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc } if (op_array->static_variables) { - HashTable *stored = zend_shared_alloc_get_xlat_entry(op_array->static_variables); - - if (stored) { - op_array->static_variables = stored; + int i; + if (op_array->fn_flags & ZEND_ACC_CLOSURE) { + zend_accel_store(op_array->static_variables, sizeof(zval) * (op_array->last_static_var + 1)); } else { - zend_hash_persist(op_array->static_variables, zend_persist_zval_static); - zend_accel_store(op_array->static_variables, sizeof(HashTable)); - /* make immutable array */ - GC_REFCOUNT(op_array->static_variables) = 2; - GC_TYPE_INFO(op_array->static_variables) = IS_ARRAY | (IS_ARRAY_IMMUTABLE << 8); - op_array->static_variables->u.flags |= HASH_FLAG_STATIC_KEYS; - op_array->static_variables->u.flags &= ~HASH_FLAG_APPLY_PROTECTION; + zend_accel_store(op_array->static_variables, sizeof(zval) * op_array->last_static_var); + } + for (i = 0; i < op_array->last_static_var; i++) { + zend_persist_zval_static(&op_array->static_variables[i]); } } @@ -645,6 +641,20 @@ 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->static_vars) { + if (already_stored) { + persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->static_vars); + ZEND_ASSERT(persist_ptr != NULL); + op_array->static_vars = (zend_string**)persist_ptr; + } else { + int i; + zend_accel_store(op_array->static_vars, sizeof(zend_string*) * op_array->last_static_var); + for (i = 0; i < op_array->last_static_var; i++) { + zend_accel_store_interned_string(op_array->static_vars[i]); + } + } + } + if (op_array->vars) { if (already_stored) { persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->vars); diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index 9516c4e53b0e9..8799effe2881b 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -162,12 +162,14 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array) } if (op_array->static_variables) { - if (!zend_shared_alloc_get_xlat_entry(op_array->static_variables)) { - HashTable *old = op_array->static_variables; - - ADD_DUP_SIZE(op_array->static_variables, sizeof(HashTable)); - zend_hash_persist_calc(op_array->static_variables, zend_persist_zval_calc); - zend_shared_alloc_register_xlat_entry(old, op_array->static_variables); + int i; + if (op_array->fn_flags & ZEND_ACC_CLOSURE) { + ADD_SIZE(sizeof(zval) * (op_array->last_static_var + 1)); + } else { + ADD_SIZE(sizeof(zval) * op_array->last_static_var); + } + for (i = 0; i < op_array->last_static_var; i++) { + zend_persist_zval_calc(&op_array->static_variables[i]); } } @@ -246,6 +248,15 @@ 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->static_vars) { + int i; + + ADD_DUP_SIZE(op_array->static_vars, sizeof(zend_string*) * op_array->last_static_var); + for (i = 0; i < op_array->last_static_var; i++) { + ADD_INTERNED_STRING(op_array->static_vars[i], 0); + } + } + if (op_array->vars) { int i; diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 7713137e8913e..6fc174dc0d2fc 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -771,26 +771,24 @@ static void _function_parameter_string(string *str, zend_function *fptr, char* i static void _function_closure_string(string *str, zend_function *fptr, char* indent) { uint32_t i, count; - zend_string *key; - HashTable *static_variables; + zend_string **static_names; if (fptr->type != ZEND_USER_FUNCTION || !fptr->op_array.static_variables) { return; } - static_variables = fptr->op_array.static_variables; - count = zend_hash_num_elements(static_variables); + static_names = fptr->op_array.static_vars; + count = fptr->op_array.last_static_var; if (!count) { return; } string_printf(str, "\n"); - string_printf(str, "%s- Bound Variables [%d] {\n", indent, zend_hash_num_elements(static_variables)); - i = 0; - ZEND_HASH_FOREACH_STR_KEY(static_variables, key) { - string_printf(str, "%s Variable #%d [ $%s ]\n", indent, i++, ZSTR_VAL(key)); - } ZEND_HASH_FOREACH_END(); + string_printf(str, "%s- Bound Variables [%d] {\n", indent, count); + for (i = 0; i < count; i++) { + string_printf(str, "%s Variable #%d [ $%s ]\n", indent, i, ZSTR_VAL(static_names[i])); + } string_printf(str, "%s}\n", indent); } /* }}} */ @@ -1927,18 +1925,15 @@ ZEND_METHOD(reflection_function, getStaticVariables) /* Return an empty array in case no static variables exist */ array_init(return_value); if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.static_variables != NULL) { - if (GC_REFCOUNT(fptr->op_array.static_variables) > 1) { - if (!(GC_FLAGS(fptr->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) { - GC_REFCOUNT(fptr->op_array.static_variables)--; - } - fptr->op_array.static_variables = zend_array_dup(fptr->op_array.static_variables); - } - ZEND_HASH_FOREACH_VAL(fptr->op_array.static_variables, val) { + int i; + for (i = 0; i < fptr->op_array.last_static_var; i++) { + val = &fptr->op_array.static_variables[i]; if (UNEXPECTED(zval_update_constant_ex(val, 1, fptr->common.scope) != SUCCESS)) { return; } - } ZEND_HASH_FOREACH_END(); - zend_hash_copy(Z_ARRVAL_P(return_value), fptr->op_array.static_variables, zval_add_ref); + Z_TRY_ADDREF_P(val); + zend_hash_update(Z_ARRVAL_P(return_value), fptr->op_array.static_vars[i], val); + } } } /* }}} */ diff --git a/sapi/phpdbg/phpdbg_opcode.c b/sapi/phpdbg/phpdbg_opcode.c index 70dab12656b97..6880fb26c878c 100644 --- a/sapi/phpdbg/phpdbg_opcode.c +++ b/sapi/phpdbg/phpdbg_opcode.c @@ -93,9 +93,9 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op) /*{{{ */ case ZEND_RECV: case ZEND_RECV_INIT: case ZEND_RECV_VARIADIC: + case ZEND_FETCH_STATIC: spprintf(&decode[1], 0, "%" PRIu32, op->op1.num); break; - default: decode[1] = phpdbg_decode_op(ops, &op->op1, op->op1_type); break; @@ -143,6 +143,7 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op) /*{{{ */ /* RESULT */ switch (op->opcode) { case ZEND_CATCH: + case ZEND_BIND_LEXICAL: spprintf(&decode[3], 0, "%" PRIu32, op->result.num); break; default: