From 89c25854faf2958cab7b5f551ddc5b596c7ad277 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Sat, 5 Dec 2015 05:16:53 +0100 Subject: [PATCH 1/4] Restructure argument passing onto stack Arguments now are prepended to the execute_data, inside the (last!) temporaries of the previous stack frame. Every stack frame has place for sent arguments plus five optional args (RECV_INIT...) and the execute_data. This allows EG(vm_stack_top) and EX(call) to be removed and saves us from expensive comparisons to push a call frame completely in some cases (every ICALL). The only downside is that arguments now are in reverse order causing variadics to be in reverse order on the stack; extensions might need some update ... Also, freeing of args and execute_data is now completely handled by liveness. Finally, the patch gives 0.5%-3% improvement on applications. There likely is still some room for optimization (e.g. eliminating ZEND_SEND_VAL with TMPs or speeding up the unpacking, removing INIT_FCALL for UCALLs, ...). --- Zend/tests/arg_unpack/invalid_type.phpt | 12 +- Zend/zend_API.c | 9 +- Zend/zend_API.h | 8 +- Zend/zend_builtin_functions.c | 61 +- Zend/zend_closures.c | 3 +- Zend/zend_compile.c | 286 +- Zend/zend_compile.h | 39 +- Zend/zend_execute.c | 415 +- Zend/zend_execute.h | 125 +- Zend/zend_execute_API.c | 98 +- Zend/zend_generators.c | 16 +- Zend/zend_opcode.c | 140 +- Zend/zend_vm_def.h | 774 ++- Zend/zend_vm_execute.h | 5633 ++++++++++------- Zend/zend_vm_execute.skl | 4 +- Zend/zend_vm_opcodes.c | 32 +- Zend/zend_vm_opcodes.h | 2 +- ext/date/tests/bug53437.phpt | 4 +- ext/interbase/ibase_events.c | 4 +- ext/interbase/ibase_query.c | 8 +- ext/mbstring/mbstring.c | 4 +- ext/mysqli/mysqli_api.c | 6 +- ext/opcache/Optimizer/block_pass.c | 22 +- ext/opcache/Optimizer/optimize_func_calls.c | 24 +- ext/opcache/Optimizer/optimize_temp_vars_5.c | 73 +- ext/opcache/Optimizer/zend_call_graph.c | 3 +- ext/opcache/Optimizer/zend_cfg.c | 1 + ext/opcache/Optimizer/zend_optimizer.c | 29 +- ext/opcache/zend_file_cache.c | 8 +- ext/opcache/zend_persist.c | 6 +- ext/opcache/zend_persist_calc.c | 6 +- ext/reflection/php_reflection.c | 14 +- ext/session/session.c | 4 +- ext/soap/soap.c | 17 +- ext/standard/array.c | 76 +- ext/standard/formatted_print.c | 30 +- ext/standard/pack.c | 22 +- ext/standard/scanf.c | 18 +- ext/standard/string.c | 2 +- .../call_user_func_array_variation_003.phpt | 50 +- ext/standard/var.c | 4 +- ext/wddx/wddx.c | 4 +- sapi/cli/php_cli.c | 8 +- sapi/phpdbg/phpdbg_opcode.c | 13 +- sapi/phpdbg/phpdbg_prompt.c | 12 +- sapi/phpdbg/tests/print_001.phpt | 34 +- sapi/phpdbg/tests/print_002.phpt | 14 +- 47 files changed, 4584 insertions(+), 3593 deletions(-) diff --git a/Zend/tests/arg_unpack/invalid_type.phpt b/Zend/tests/arg_unpack/invalid_type.phpt index 1ef545558c7da..44c5354485b69 100644 --- a/Zend/tests/arg_unpack/invalid_type.phpt +++ b/Zend/tests/arg_unpack/invalid_type.phpt @@ -16,19 +16,19 @@ test(1, 2, 3, ...new StdClass, ...3.14, ...[4, 5]); ?> --EXPECTF-- -Warning: Only arrays and Traversables can be unpacked in %s on line %d +Warning: Argument unpacking at parameter 1 requires array or Traversable, null given in %s on line %d array(0) { } -Warning: Only arrays and Traversables can be unpacked in %s on line %d +Warning: Argument unpacking at parameter 1 requires array or Traversable, integer given in %s on line %d array(0) { } -Warning: Only arrays and Traversables can be unpacked in %s on line %d +Warning: Argument unpacking at parameter 1 requires array or Traversable, object of type stdClass given in %s on line %d array(0) { } -Warning: Only arrays and Traversables can be unpacked in %s on line %d +Warning: Argument unpacking at parameter 4 requires array or Traversable, string given in %s on line %d array(5) { [0]=> int(1) @@ -42,9 +42,9 @@ array(5) { int(5) } -Warning: Only arrays and Traversables can be unpacked in %s on line %d +Warning: Argument unpacking at parameter 4 requires array or Traversable, object of type stdClass given in %s on line %d -Warning: Only arrays and Traversables can be unpacked in %s on line %d +Warning: Argument unpacking at parameter 4 requires array or Traversable, float given in %s on line %d array(5) { [0]=> int(1) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 9d64f68a5c320..f6d73df93b538 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -70,7 +70,7 @@ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */ ZVAL_COPY_VALUE(param_ptr, &new_tmp); } *param = param_ptr; - param_ptr++; + param_ptr--; } va_end(ptr); @@ -97,7 +97,7 @@ ZEND_API int zend_get_parameters_ex(int param_count, ...) /* {{{ */ while (param_count-->0) { param = va_arg(ptr, zval **); *param = param_ptr; - param_ptr++; + param_ptr--; } va_end(ptr); @@ -120,7 +120,7 @@ ZEND_API int _zend_get_parameters_array_ex(int param_count, zval *argument_array while (param_count-->0) { ZVAL_COPY_VALUE(argument_array, param_ptr); argument_array++; - param_ptr++; + param_ptr--; } return SUCCESS; @@ -144,7 +144,7 @@ ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array) / Z_ADDREF_P(param_ptr); } zend_hash_next_index_insert_new(Z_ARRVAL_P(argument_array), param_ptr); - param_ptr++; + param_ptr--; } return SUCCESS; @@ -2158,6 +2158,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio internal_function->function_name = zend_new_interned_string(zend_string_init(ptr->fname, fname_len, 1)); internal_function->scope = scope; internal_function->prototype = NULL; + internal_function->stack_size = ZEND_CALL_FRAME_SLOT * ZEND_MM_ALIGNED_SIZE(sizeof(zval)); if (ptr->flags) { if (!(ptr->flags & ZEND_ACC_PPP_MASK)) { if (ptr->flags != ZEND_ACC_DEPRECATED || scope) { diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 055e2628b6ce6..0f15e142e2f4e 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -767,7 +767,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(int severity, in if (_optional) { \ if (UNEXPECTED(_i >_num_args)) break; \ } \ - _real_arg++; \ + _real_arg--; \ _arg = _real_arg; \ ZVAL_DEREF(_arg); \ if (separate) { \ @@ -1004,7 +1004,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(int severity, in ZEND_ASSERT(_i <= _min_num_args || _optional==1); \ ZEND_ASSERT(_i > _min_num_args || _optional==0); \ if (_optional && UNEXPECTED(_i >_num_args)) break; \ - _real_arg++; \ + _real_arg--; \ zend_parse_arg_zval(_real_arg, &dest, check_null); \ } @@ -1023,10 +1023,10 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(int severity, in #define Z_PARAM_VARIADIC_EX(spec, dest, dest_num, post_varargs) do { \ int _num_varargs = _num_args - _i - (post_varargs); \ if (EXPECTED(_num_varargs > 0)) { \ - dest = _real_arg + 1; \ + dest = _real_arg - 1; \ dest_num = _num_varargs; \ _i += _num_varargs; \ - _real_arg += _num_varargs; \ + _real_arg -= _num_varargs; \ } else { \ dest = NULL; \ dest_num = 0; \ diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index e5a9518f5469f..17278fba08f69 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -438,10 +438,9 @@ ZEND_FUNCTION(func_num_args) Get the $arg_num'th argument that was passed to the function */ ZEND_FUNCTION(func_get_arg) { - uint32_t arg_count, first_extra_arg; zval *arg; zend_long requested_offset; - zend_execute_data *ex; + zend_execute_data *ex = EX(prev_execute_data); if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &requested_offset) == FAILURE) { return; @@ -458,19 +457,12 @@ ZEND_FUNCTION(func_get_arg) RETURN_FALSE; } - arg_count = ZEND_CALL_NUM_ARGS(ex); - - if (requested_offset >= arg_count) { + if (requested_offset >= ZEND_CALL_NUM_ARGS(ex)) { zend_error(E_WARNING, "func_get_arg(): Argument " ZEND_LONG_FMT " not passed to function", requested_offset); RETURN_FALSE; } - first_extra_arg = ex->func->op_array.num_args; - if (requested_offset >= first_extra_arg && (ZEND_CALL_NUM_ARGS(ex) > first_extra_arg)) { - arg = ZEND_CALL_VAR_NUM(ex, ex->func->op_array.last_var + ex->func->op_array.T) + (requested_offset - first_extra_arg); - } else { - arg = ZEND_CALL_ARG(ex, requested_offset + 1); - } + arg = ZEND_CALL_ARG(ex, requested_offset + 1); if (EXPECTED(!Z_ISUNDEF_P(arg))) { ZVAL_DEREF(arg); ZVAL_COPY(return_value, arg); @@ -483,8 +475,7 @@ ZEND_FUNCTION(func_get_arg) ZEND_FUNCTION(func_get_args) { zval *p, *q; - uint32_t arg_count, first_extra_arg; - uint32_t i, n; + uint32_t arg_count, i, n; zend_execute_data *ex = EX(prev_execute_data); if (ZEND_CALL_INFO(ex) & ZEND_CALL_CODE) { @@ -496,29 +487,12 @@ ZEND_FUNCTION(func_get_args) array_init_size(return_value, arg_count); if (arg_count) { - first_extra_arg = ex->func->op_array.num_args; zend_hash_real_init(Z_ARRVAL_P(return_value), 1); ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { i = 0; n = 0; p = ZEND_CALL_ARG(ex, 1); - if (arg_count > first_extra_arg) { - while (i < first_extra_arg) { - q = p; - if (EXPECTED(Z_TYPE_INFO_P(q) != IS_UNDEF)) { - ZVAL_DEREF(q); - if (Z_OPT_REFCOUNTED_P(q)) { - Z_ADDREF_P(q); - } - n++; - } - ZEND_HASH_FILL_ADD(q); - p++; - i++; - } - p = ZEND_CALL_VAR_NUM(ex, ex->func->op_array.last_var + ex->func->op_array.T); - } - while (i < arg_count) { + do { q = p; if (EXPECTED(Z_TYPE_INFO_P(q) != IS_UNDEF)) { ZVAL_DEREF(q); @@ -528,9 +502,9 @@ ZEND_FUNCTION(func_get_args) n++; } ZEND_HASH_FILL_ADD(q); - p++; + p--; i++; - } + } while (i < arg_count); } ZEND_HASH_FILL_END(); Z_ARRVAL_P(return_value)->nNumOfElements = n; } @@ -2243,25 +2217,6 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / zend_hash_real_init(Z_ARRVAL_P(arg_array), 1); ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(arg_array)) { - if (call->func->type == ZEND_USER_FUNCTION) { - uint32_t first_extra_arg = call->func->op_array.num_args; - - if (ZEND_CALL_NUM_ARGS(call) > first_extra_arg) { - while (i < first_extra_arg) { - if (EXPECTED(Z_TYPE_INFO_P(p) != IS_UNDEF)) { - if (Z_OPT_REFCOUNTED_P(p)) { - Z_ADDREF_P(p); - } - n++; - } - ZEND_HASH_FILL_ADD(p); - p++; - i++; - } - p = ZEND_CALL_VAR_NUM(call, call->func->op_array.last_var + call->func->op_array.T); - } - } - while (i < num_args) { if (EXPECTED(Z_TYPE_INFO_P(p) != IS_UNDEF)) { if (Z_OPT_REFCOUNTED_P(p)) { @@ -2270,7 +2225,7 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) / n++; } ZEND_HASH_FILL_ADD(p); - p++; + p--; i++; } } ZEND_HASH_FILL_END(); diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index beca1cef0750c..3feade0541e30 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -147,7 +147,7 @@ ZEND_METHOD(Closure, call) fci.retval = &closure_result; fci.params = my_params; - fci.param_count = my_param_count; + fci.param_count = -my_param_count; fci.object = fci_cache.object = newobj; fci_cache.initialized = 1; fci_cache.called_scope = Z_OBJCE_P(newthis); @@ -277,6 +277,7 @@ ZEND_API zend_function *zend_get_closure_invoke_method(zend_object *object) /* { invoke->internal_function.module = 0; invoke->internal_function.scope = zend_ce_closure; invoke->internal_function.function_name = zend_string_init(ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1, 0); + invoke->internal_function.stack_size = ZEND_CALL_FRAME_SLOT * sizeof(zval); return invoke; } /* }}} */ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index e8752788dba18..ac69b06e3b3dd 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -399,28 +399,43 @@ static uint32_t get_temporary_variable(zend_op_array *op_array) /* {{{ */ } /* }}} */ -static int lookup_cv(zend_op_array *op_array, zend_string* name) /* {{{ */{ +static zend_bool find_cv(int *cv, 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_var) { + for (i = 0; i < op_array->last_var + op_array->num_args; i++) { if (ZSTR_VAL(op_array->vars[i]) == ZSTR_VAL(name) || (ZSTR_H(op_array->vars[i]) == hash_value && ZSTR_LEN(op_array->vars[i]) == ZSTR_LEN(name) && memcmp(ZSTR_VAL(op_array->vars[i]), ZSTR_VAL(name), ZSTR_LEN(name)) == 0)) { - zend_string_release(name); - return (int)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, i); + uint32_t negative_vars = op_array->num_args; + *cv = (int)(zend_intptr_t)(i >= negative_vars ? ZEND_CALL_VAR_NUM(NULL, i - negative_vars) : ZEND_CALL_ARG(NULL, i + 1)); + return 1; } - i++; } - i = op_array->last_var; - op_array->last_var++; - if (op_array->last_var > CG(context).vars_size) { + + return 0; +} +/* }}} */ + +static int lookup_cv(zend_op_array *op_array, zend_string* name) /* {{{ */ +{ + int i, offset; + + if (find_cv(&i, op_array, name)) { + zend_string_release(name); + return i; + } + + i = op_array->last_var++; + offset = i + op_array->num_args; + if (offset >= CG(context).vars_size) { CG(context).vars_size += 16; /* FIXME */ op_array->vars = erealloc(op_array->vars, CG(context).vars_size * sizeof(zend_string*)); } - op_array->vars[i] = zend_new_interned_string(name); + op_array->vars[offset] = zend_new_interned_string(name); return (int)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, i); } /* }}} */ @@ -586,7 +601,7 @@ void zend_stop_lexing(void) LANG_SCNG(yy_cursor) = LANG_SCNG(yy_limit); } -static uint32_t zend_start_live_range(zend_op_array *op_array, uint32_t start) /* {{{ */ +uint32_t zend_start_live_range(zend_op_array *op_array, uint32_t start) /* {{{ */ { zend_live_range *range; @@ -598,7 +613,7 @@ static uint32_t zend_start_live_range(zend_op_array *op_array, uint32_t start) / } /* }}} */ -static void zend_end_live_range(zend_op_array *op_array, uint32_t offset, uint32_t end, uint32_t kind, uint32_t var) /* {{{ */ +void zend_end_live_range(zend_op_array *op_array, uint32_t offset, uint32_t end, uint32_t kind, uint32_t var) /* {{{ */ { zend_live_range *range = op_array->live_range + offset; @@ -695,11 +710,6 @@ void zend_do_free(znode *op1) /* {{{ */ && opline->result.var == op1->u.op.var) { if (opline->opcode == ZEND_NEW) { opline->result_type |= EXT_TYPE_UNUSED; - opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1]; - while (opline->opcode != ZEND_DO_FCALL || opline->op1.num != ZEND_CALL_CTOR) { - opline--; - } - opline->op1.num |= ZEND_CALL_CTOR_RESULT_UNUSED; } break; } @@ -1852,34 +1862,6 @@ ZEND_API size_t zend_dirname(char *path, size_t len) } /* }}} */ -static void zend_adjust_for_fetch_type(zend_op *opline, uint32_t type) /* {{{ */ -{ - zend_uchar factor = (opline->opcode == ZEND_FETCH_STATIC_PROP_R) ? 1 : 3; - - switch (type & BP_VAR_MASK) { - case BP_VAR_R: - return; - case BP_VAR_W: - opline->opcode += 1 * factor; - return; - case BP_VAR_RW: - opline->opcode += 2 * factor; - return; - case BP_VAR_IS: - opline->opcode += 3 * factor; - return; - case BP_VAR_FUNC_ARG: - opline->opcode += 4 * factor; - opline->extended_value |= type >> BP_VAR_SHIFT; - return; - case BP_VAR_UNSET: - opline->opcode += 5 * factor; - return; - EMPTY_SWITCH_DEFAULT_CASE() - } -} -/* }}} */ - static inline void zend_make_var_result(znode *result, zend_op *opline) /* {{{ */ { opline->result_type = IS_VAR; @@ -2190,6 +2172,41 @@ static zend_op *zend_delayed_compile_end(uint32_t offset) /* {{{ */ } /* }}} */ +static void zend_adjust_for_fetch_type(zend_op *opline, uint32_t type, zend_bool delayed) /* {{{ */ +{ + zend_uchar factor = (opline->opcode == ZEND_FETCH_STATIC_PROP_R) ? 1 : 3; + + switch (type & BP_VAR_MASK) { + case BP_VAR_R: + return; + case BP_VAR_W: + opline->opcode += 1 * factor; + return; + case BP_VAR_RW: + opline->opcode += 2 * factor; + return; + case BP_VAR_IS: + opline->opcode += 3 * factor; + return; + case BP_VAR_FUNC_ARG: + opline->opcode += 4 * factor; + opline->extended_value |= type >> BP_VAR_SHIFT; + if (opline->opcode != ZEND_FETCH_FUNC_ARG) { + if (delayed) { + zend_delayed_emit_op(NULL, ZEND_OP_DATA, NULL, NULL); + } else { + zend_emit_op_data(NULL); + } + } + return; + case BP_VAR_UNSET: + opline->opcode += 5 * factor; + return; + EMPTY_SWITCH_DEFAULT_CASE() + } +} +/* }}} */ + static void zend_emit_return_type_check(znode *expr, zend_arg_info *return_info) /* {{{ */ { /* `return ...;` is illegal in a void function (but `return;` isn't) */ @@ -2404,6 +2421,7 @@ static int zend_try_compile_cv(znode *result, zend_ast *ast) /* {{{ */ zend_ast *name_ast = ast->child[0]; if (name_ast->kind == ZEND_AST_ZVAL) { zend_string *name = zval_get_string(zend_ast_get_zval(name_ast)); + zend_bool is_this = zend_string_equals_literal(name, "this");; if (zend_is_auto_global(name)) { zend_string_release(name); @@ -2413,12 +2431,10 @@ static int zend_try_compile_cv(znode *result, zend_ast *ast) /* {{{ */ result->op_type = IS_CV; result->u.op.var = lookup_cv(CG(active_op_array), name); - /* lookup_cv may be using another zend_string instance */ - name = CG(active_op_array)->vars[EX_VAR_TO_NUM(result->u.op.var)]; - - if (zend_string_equals_literal(name, "this")) { + if (is_this) { CG(active_op_array)->this_var = result->u.op.var; } + return SUCCESS; } @@ -2466,7 +2482,7 @@ static void zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t type, { if (zend_try_compile_cv(result, ast) == FAILURE) { zend_op *opline = zend_compile_simple_var_no_cv(result, ast, type, delayed); - zend_adjust_for_fetch_type(opline, type); + zend_adjust_for_fetch_type(opline, type, delayed); } } /* }}} */ @@ -2541,7 +2557,7 @@ static inline zend_op *zend_compile_dim_common(znode *result, zend_ast *ast, uin void zend_compile_dim(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ { zend_op *opline = zend_compile_dim_common(result, ast, type); - zend_adjust_for_fetch_type(opline, type); + zend_adjust_for_fetch_type(opline, type, 0); } /* }}} */ @@ -2593,7 +2609,7 @@ static zend_op *zend_compile_prop_common(znode *result, zend_ast *ast, uint32_t void zend_compile_prop(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ { zend_op *opline = zend_compile_prop_common(result, ast, type); - zend_adjust_for_fetch_type(opline, type); + zend_adjust_for_fetch_type(opline, type, 0); } /* }}} */ @@ -2633,7 +2649,7 @@ zend_op *zend_compile_static_prop_common(znode *result, zend_ast *ast, uint32_t void zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type, int delayed) /* {{{ */ { zend_op *opline = zend_compile_static_prop_common(result, ast, type, delayed); - zend_adjust_for_fetch_type(opline, type); + zend_adjust_for_fetch_type(opline, type, delayed); } /* }}} */ @@ -2903,27 +2919,39 @@ void zend_compile_compound_assign(znode *result, zend_ast *ast) /* {{{ */ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */ { zend_ast_list *args = zend_ast_get_list(ast); - uint32_t i; + uint32_t i, live_var; zend_bool uses_arg_unpack = 0; + zend_op *opline; + znode arg_node, unpack_node; uint32_t arg_count = 0; /* number of arguments not including unpacks */ for (i = 0; i < args->children; ++i) { zend_ast *arg = args->child[i]; uint32_t arg_num = i + 1; - znode arg_node; - zend_op *opline; zend_uchar opcode; zend_ulong flags = 0; if (arg->kind == ZEND_AST_UNPACK) { - uses_arg_unpack = 1; fbc = NULL; zend_compile_expr(&arg_node, arg->child[0]); - opline = zend_emit_op(NULL, ZEND_SEND_UNPACK, &arg_node, NULL); - opline->op2.num = arg_count; - opline->result.var = (uint32_t)(zend_intptr_t)ZEND_CALL_ARG(NULL, arg_count); + if (uses_arg_unpack++) { + opline = zend_emit_op(NULL, ZEND_SEND_UNPACK, &arg_node, NULL); + SET_NODE(opline->result, &unpack_node); + opline->extended_value = ZEND_ARG_IS_UNPACKED; + } else { + if (arg_num == args->children) { + unpack_node = arg_node; + continue; + } + + live_var = zend_start_live_range(CG(active_op_array), get_next_op_number(CG(active_op_array)) - 1); + opline = zend_emit_op_tmp(&unpack_node, ZEND_SEND_UNPACK, &arg_node, NULL); + opline->extended_value = 0; + uses_arg_unpack++; + } + opline->extended_value |= arg_count + 1; continue; } @@ -2936,6 +2964,7 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */ if (zend_is_variable(arg)) { if (zend_is_call(arg)) { zend_compile_var(&arg_node, arg, BP_VAR_R); +/* TODO: ZEND_SEND_VAL is redundant here for IS_TMP_VAR */ if (arg_node.op_type & (IS_CONST|IS_TMP_VAR)) { /* Function call was converted into builtin instruction */ opcode = ZEND_SEND_VAL; @@ -2983,8 +3012,9 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */ } opline = zend_emit_op(NULL, opcode, &arg_node, NULL); - opline->op2.opline_num = arg_num; - opline->result.var = (uint32_t)(zend_intptr_t)ZEND_CALL_ARG(NULL, arg_num); + opline->extended_value = arg_num; + /* temporary value, to be used and changed via zend_convert_arg_num_to_temps(); order must be maintained! */ + opline->result.num = zend_start_live_range(CG(active_op_array), opline - CG(active_op_array)->opcodes + 1); if (opcode == ZEND_SEND_VAR_NO_REF) { if (fbc) { @@ -2992,12 +3022,21 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */ } if ((flags & ZEND_ARG_COMPILE_TIME_BOUND) && !(flags & ZEND_ARG_SEND_BY_REF)) { opline->opcode = ZEND_SEND_VAR; - opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND; + opline->extended_value |= ZEND_ARG_COMPILE_TIME_BOUND; } else { - opline->extended_value = flags; + opline->extended_value |= flags; } } else if (fbc) { - opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND; + opline->extended_value |= ZEND_ARG_COMPILE_TIME_BOUND; + } + } + + if (uses_arg_unpack) { + opline = zend_emit_op(&arg_node, ZEND_DO_UNPACK_FCALL, NULL, &unpack_node); + opline->extended_value = arg_count + 1; + if (uses_arg_unpack > 1) { + zend_end_live_range(CG(active_op_array), live_var, get_next_op_number(CG(active_op_array)) - 1, ZEND_LIVE_TMPVAR, unpack_node.u.op.var); + opline->extended_value |= ZEND_ARG_IS_UNPACKED; } } @@ -3035,7 +3074,9 @@ void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function * zend_op *opline; uint32_t opnum_init = get_next_op_number(CG(active_op_array)) - 1; uint32_t arg_count; - uint32_t call_flags; + uint32_t live_var = zend_start_live_range(CG(active_op_array), opnum_init + 1); + zend_uchar call_op; + zend_bool is_variadic; zend_do_extended_fcall_begin(); @@ -3043,14 +3084,26 @@ void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function * opline = &CG(active_op_array)->opcodes[opnum_init]; opline->extended_value = arg_count; + call_op = zend_get_call_op(opline->opcode, fbc); - if (opline->opcode == ZEND_INIT_FCALL) { - opline->op1.num = zend_vm_calc_used_stack(arg_count, fbc); + opline = &CG(active_op_array)->opcodes[get_next_op_number(CG(active_op_array)) - 1]; + is_variadic = opline->opcode == ZEND_DO_UNPACK_FCALL; + if (is_variadic) { + GET_NODE(result, opline->result); + } else { + opline = zend_emit_op(result, call_op, NULL, NULL); + if (call_op == ZEND_DO_UCALL) { + opline->op2.num = zend_vm_calc_used_stack(0, fbc); + } } - call_flags = (opline->opcode == ZEND_NEW ? ZEND_CALL_CTOR : 0); - opline = zend_emit_op(result, zend_get_call_op(opline->opcode, fbc), NULL, NULL); - opline->op1.num = call_flags; + /* temporary value, to be used and changed via zend_convert_arg_num_to_temps(); order must be maintained! */ + opline->op1.num = live_var; + + opline = &CG(active_op_array)->opcodes[opnum_init]; + if (opline->opcode != ZEND_NEW) { + opline->result.num = is_variadic; + } zend_do_extended_fcall_end(); } @@ -3253,15 +3306,21 @@ static void zend_compile_init_user_func(zend_ast *name_ast, uint32_t num_args, z int zend_compile_func_cufa(znode *result, zend_ast_list *args, zend_string *lcname) /* {{{ */ { znode arg_node; + zend_op *opline; + uint32_t live_var; if (args->children != 2 || zend_args_contain_unpack(args)) { return FAILURE; } + live_var = zend_start_live_range(CG(active_op_array), get_next_op_number(CG(active_op_array))); zend_compile_init_user_func(args->child[0], 0, lcname); + opline = &CG(active_op_array)->opcodes[get_next_op_number(CG(active_op_array)) - 1]; + opline->result.num = 1; zend_compile_expr(&arg_node, args->child[1]); - zend_emit_op(NULL, ZEND_SEND_ARRAY, &arg_node, NULL); - zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL); + opline = zend_emit_op(result, ZEND_DO_UNPACK_FCALL, NULL, &arg_node); + opline->op1.num = live_var; + opline->extended_value = ZEND_ARG_IS_CUFA | 1; return SUCCESS; } @@ -3270,17 +3329,18 @@ int zend_compile_func_cufa(znode *result, zend_ast_list *args, zend_string *lcna /* cuf = call_user_func */ int zend_compile_func_cuf(znode *result, zend_ast_list *args, zend_string *lcname) /* {{{ */ { - uint32_t i; + uint32_t i, live_var; + zend_op *opline; if (args->children < 1 || zend_args_contain_unpack(args)) { return FAILURE; } + live_var = zend_start_live_range(CG(active_op_array), get_next_op_number(CG(active_op_array))); zend_compile_init_user_func(args->child[0], args->children - 1, lcname); for (i = 1; i < args->children; ++i) { zend_ast *arg_ast = args->child[i]; znode arg_node; - zend_op *opline; zend_bool send_user = 0; if (zend_is_variable(arg_ast) && !zend_is_call(arg_ast)) { @@ -3299,10 +3359,12 @@ int zend_compile_func_cuf(znode *result, zend_ast_list *args, zend_string *lcnam opline = zend_emit_op(NULL, ZEND_SEND_VAL, &arg_node, NULL); } - opline->op2.num = i; - opline->result.var = (uint32_t)(zend_intptr_t)ZEND_CALL_ARG(NULL, i); + opline->extended_value = i; + /* temporary value, to be used and changed via zend_convert_arg_num_to_temps(); order must be maintained! */ + opline->result.num = zend_start_live_range(CG(active_op_array), opline - CG(active_op_array)->opcodes + 1); } - zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL); + opline = zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL); + opline->op1.num = live_var; return SUCCESS; } @@ -4670,6 +4732,10 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ arg_infos = safe_emalloc(sizeof(zend_arg_info), list->children, 0); } + ZEND_ASSERT(op_array->vars == NULL); // assume we are the first to alloc, else we'd overwrite vars... + CG(context).vars_size = list->children; + op_array->vars = emalloc(CG(context).vars_size * sizeof(zend_string *)); + for (i = 0; i < list->children; ++i) { zend_ast *param_ast = list->child[i]; zend_ast *type_ast = param_ast->child[0]; @@ -4683,50 +4749,61 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ zend_uchar opcode; zend_op *opline; zend_arg_info *arg_info; + int cv; if (zend_is_auto_global(name)) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign auto-global variable %s", ZSTR_VAL(name)); } - var_node.op_type = IS_CV; - var_node.u.op.var = lookup_cv(CG(active_op_array), zend_string_copy(name)); + if (op_array->fn_flags & ZEND_ACC_VARIADIC) { + zend_error_noreturn(E_COMPILE_ERROR, "Only the last parameter can be variadic"); + } - if (EX_VAR_TO_NUM(var_node.u.op.var) != i) { + if (find_cv(&cv, CG(active_op_array), name)) { zend_error_noreturn(E_COMPILE_ERROR, "Redefinition of parameter $%s", ZSTR_VAL(name)); - } else if (zend_string_equals_literal(name, "this")) { - if (op_array->scope && (op_array->fn_flags & ZEND_ACC_STATIC) == 0) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this"); - } - op_array->this_var = var_node.u.op.var; } - if (op_array->fn_flags & ZEND_ACC_VARIADIC) { - zend_error_noreturn(E_COMPILE_ERROR, "Only the last parameter can be variadic"); - } + var_node.op_type = IS_CV; + var_node.u.op.var = (int)(zend_intptr_t)ZEND_CALL_ARG(NULL, i + 1); + op_array->vars[i] = zend_new_interned_string(zend_string_copy(name)); if (is_variadic) { opcode = ZEND_RECV_VARIADIC; default_node.op_type = IS_UNUSED; op_array->fn_flags |= ZEND_ACC_VARIADIC; + var_node.u.op.var = (int)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, 0); + op_array->last_var = 1; + if (default_ast) { zend_error_noreturn(E_COMPILE_ERROR, "Variadic parameter cannot have a default value"); } - } else if (default_ast) { - /* we cannot substitute constants here or it will break ReflectionParameter::getDefaultValueConstantName() and ReflectionParameter::isDefaultValueConstant() */ - uint32_t cops = CG(compiler_options); - CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION | ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION; - opcode = ZEND_RECV_INIT; - default_node.op_type = IS_CONST; - zend_const_expr_to_zval(&default_node.u.constant, default_ast); - CG(compiler_options) = cops; } else { - opcode = ZEND_RECV; - default_node.op_type = IS_UNUSED; - op_array->required_num_args = i + 1; + op_array->num_args++; + + if (default_ast) { + /* we cannot substitute constants here or it will break ReflectionParameter::getDefaultValueConstantName() and ReflectionParameter::isDefaultValueConstant() */ + uint32_t cops = CG(compiler_options); + CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION | ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION; + opcode = ZEND_RECV_INIT; + default_node.op_type = IS_CONST; + zend_const_expr_to_zval(&default_node.u.constant, default_ast); + CG(compiler_options) = cops; + } else { + opcode = ZEND_RECV; + default_node.op_type = IS_UNUSED; + op_array->required_num_args = i + 1; + } + } + + if (zend_string_equals_literal(name, "this")) { + if (op_array->scope && (op_array->fn_flags & ZEND_ACC_STATIC) == 0) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this"); + } + op_array->this_var = var_node.u.op.var; } opline = zend_emit_op(NULL, opcode, NULL, &default_node); @@ -4820,13 +4897,8 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ } /* These are assigned at the end to avoid unitialized memory in case of an error */ - op_array->num_args = list->children; op_array->arg_info = arg_infos; - /* Don't count the variadic argument */ - if (op_array->fn_flags & ZEND_ACC_VARIADIC) { - op_array->num_args--; - } zend_set_function_arg_flags((zend_function*)op_array); } /* }}} */ @@ -6569,7 +6641,7 @@ void zend_compile_include_or_eval(znode *result, zend_ast *ast) /* {{{ */ zend_do_extended_fcall_begin(); zend_compile_expr(&expr_node, expr_ast); - opline = zend_emit_op(result, ZEND_INCLUDE_OR_EVAL, &expr_node, NULL); + opline = zend_emit_op(result, ZEND_INCLUDE_OR_EVAL, NULL, &expr_node); opline->extended_value = ast->attr; zend_do_extended_fcall_end(); @@ -7490,11 +7562,11 @@ void zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type) /* {{ return; case ZEND_AST_DIM: opline = zend_delayed_compile_dim(result, ast, type); - zend_adjust_for_fetch_type(opline, type); + zend_adjust_for_fetch_type(opline, type, 1); return; case ZEND_AST_PROP: opline = zend_delayed_compile_prop(result, ast, type); - zend_adjust_for_fetch_type(opline, type); + zend_adjust_for_fetch_type(opline, type, 1); return; case ZEND_AST_STATIC_PROP: zend_compile_static_prop(result, ast, type, 1); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index c02cf5371df16..ed481b0474d1e 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -173,11 +173,12 @@ typedef struct _zend_try_catch_element { uint32_t finally_end; } zend_try_catch_element; -#define ZEND_LIVE_TMPVAR 0 -#define ZEND_LIVE_LOOP 1 -#define ZEND_LIVE_SILENCE 2 -#define ZEND_LIVE_ROPE 3 -#define ZEND_LIVE_MASK 3 +#define ZEND_LIVE_TMPVAR 0 +#define ZEND_LIVE_LOOP 1 +#define ZEND_LIVE_SILENCE 2 +#define ZEND_LIVE_ROPE 3 +#define ZEND_LIVE_EXECUTE_DATA 4 +#define ZEND_LIVE_MASK 7 typedef struct _zend_live_range { uint32_t var; /* low bits are used for variable type (ZEND_LIVE_* macros) */ @@ -361,6 +362,7 @@ struct _zend_op_array { uint32_t num_args; uint32_t required_num_args; zend_arg_info *arg_info; + uint32_t stack_size; /* END of common elements */ uint32_t *refcount; @@ -412,6 +414,7 @@ typedef struct _zend_internal_function { uint32_t num_args; uint32_t required_num_args; zend_internal_arg_info *arg_info; + uint32_t stack_size; /* END of common elements */ void (*handler)(INTERNAL_FUNCTION_PARAMETERS); @@ -434,6 +437,7 @@ union _zend_function { uint32_t num_args; uint32_t required_num_args; zend_arg_info *arg_info; + uint32_t stack_size; } common; zend_op_array op_array; @@ -449,11 +453,10 @@ typedef enum _zend_call_kind { struct _zend_execute_data { const zend_op *opline; /* executed opline */ - zend_execute_data *call; /* current call */ zval *return_value; zend_function *func; /* executed funcrion */ - zval This; /* this + call_info + num_args */ zend_class_entry *called_scope; + zval This; /* this + call_info + num_args */ zend_execute_data *prev_execute_data; zend_array *symbol_table; #if ZEND_EX_USE_RUN_TIME_CACHE @@ -509,7 +512,7 @@ struct _zend_execute_data { (((zval*)(call)) + (ZEND_CALL_FRAME_SLOT + ((int)(n)))) #define ZEND_CALL_ARG(call, n) \ - ZEND_CALL_VAR_NUM(call, ((int)(n)) - 1) + (((zval*)(call)) - ((int)(n))) #define EX(element) ((execute_data)->element) @@ -533,8 +536,11 @@ struct _zend_execute_data { #define EX_VAR(n) ZEND_CALL_VAR(execute_data, n) #define EX_VAR_NUM(n) ZEND_CALL_VAR_NUM(execute_data, n) +#define EX_ARG(n) ZEND_CALL_ARG(execute_data, n) #define EX_VAR_TO_NUM(n) ((uint32_t)(ZEND_CALL_VAR(NULL, n) - ZEND_CALL_VAR_NUM(NULL, 0))) +#define RT_CV_DEF_OF(op_array, i) ((op_array)->vars[0 > (int32_t) (i) ? - ZEND_CALL_FRAME_SLOT - i - 1 : i + (op_array)->num_args]) +#define CV_DEF_OF(i) RT_CV_DEF_OF(&EX(func)->op_array, i) #define ZEND_OPLINE_TO_OFFSET(opline, target) \ ((char*)(target) - (char*)(opline)) @@ -793,6 +799,9 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify uint32_t zend_get_class_fetch_type(zend_string *name); ZEND_API zend_uchar zend_get_call_op(zend_uchar init_op, zend_function *fbc); +uint32_t zend_start_live_range(zend_op_array *op_array, uint32_t start); +void zend_end_live_range(zend_op_array *op_array, uint32_t offset, uint32_t end, uint32_t kind, uint32_t var); + typedef zend_bool (*zend_auto_global_callback)(zend_string *name); typedef struct _zend_auto_global { zend_string *name; @@ -820,6 +829,9 @@ ZEND_API void zend_assert_valid_class_name(const zend_string *const_name); /* END: OPCODES */ +/* reserved slots for RECV_INIT vars */ +#define ZEND_RESERVED_RECV_SLOTS 5 + /* class fetches */ #define ZEND_FETCH_CLASS_DEFAULT 0 #define ZEND_FETCH_CLASS_SELF 1 @@ -909,10 +921,13 @@ ZEND_API void zend_assert_valid_class_name(const zend_string *const_name); #define ZEND_MEMBER_FUNC_CALL (1<<0) -#define ZEND_ARG_SEND_BY_REF (1<<0) -#define ZEND_ARG_COMPILE_TIME_BOUND (1<<1) -#define ZEND_ARG_SEND_FUNCTION (1<<2) -#define ZEND_ARG_SEND_SILENT (1<<3) +#define ZEND_ARG_SEND_BY_REF 0x10000000 +#define ZEND_ARG_COMPILE_TIME_BOUND 0x20000000 +#define ZEND_ARG_SEND_FUNCTION 0x40000000 +#define ZEND_ARG_SEND_SILENT 0x80000000 +#define ZEND_ARG_IS_UNPACKED 0x40000000 +#define ZEND_ARG_IS_CUFA 0x80000000 +#define ZEND_ARG_SEND_MASK 0x0fffffff #define ZEND_SEND_BY_VAL 0 #define ZEND_SEND_BY_REF 1 diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index e287abf470d33..e59bc1489ac7e 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -84,6 +84,7 @@ static const zend_internal_function zend_pass_function = { 0, /* num_args */ 0, /* required_num_args */ NULL, /* arg_info */ + ZEND_CALL_FRAME_SLOT * ZEND_MM_ALIGNED_SIZE(sizeof(zval *)), /* stack_size */ ZEND_FN(pass), /* handler */ NULL /* module */ }; @@ -121,8 +122,6 @@ static const zend_internal_function zend_pass_function = { /* End of zend_execute_locks.h */ -#define CV_DEF_OF(i) (EX(func)->op_array.vars[i]) - #define CTOR_CALL_BIT 0x1 #define CTOR_USED_BIT 0x2 @@ -150,7 +149,6 @@ static const zend_internal_function zend_pass_function = { static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend_vm_stack prev) { zend_vm_stack page = (zend_vm_stack)emalloc(size); - page->top = ZEND_VM_STACK_ELEMENTS(page); page->end = (zval*)((char*)page + size); page->prev = prev; return page; @@ -159,8 +157,6 @@ static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend ZEND_API void zend_vm_stack_init(void) { EG(vm_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE(0 /* main stack */), NULL); - EG(vm_stack)->top++; - EG(vm_stack_top) = EG(vm_stack)->top; EG(vm_stack_end) = EG(vm_stack)->end; } @@ -178,18 +174,13 @@ ZEND_API void zend_vm_stack_destroy(void) ZEND_API void* zend_vm_stack_extend(size_t size) { zend_vm_stack stack; - void *ptr; - stack = EG(vm_stack); - stack->top = EG(vm_stack_top); EG(vm_stack) = stack = zend_vm_stack_new_page( EXPECTED(size < ZEND_VM_STACK_FREE_PAGE_SIZE(0)) ? ZEND_VM_STACK_PAGE_SIZE(0) : ZEND_VM_STACK_PAGE_ALIGNED_SIZE(0, size), - stack); - ptr = stack->top; - EG(vm_stack_top) = (void*)(((char*)ptr) + size); + EG(vm_stack)); EG(vm_stack_end) = stack->end; - return ptr; + return ZEND_VM_STACK_ELEMENTS(stack); } ZEND_API zval* zend_get_compiled_variable_value(const zend_execute_data *execute_data, uint32_t var) @@ -605,6 +596,22 @@ static inline int make_real_object(zval *object) return 1; } +/* necessary to not confuse symtable rebuilds and backtrace fetches before all the args are set */ +static void zend_undef_unpassed_args(zend_execute_data *execute_data) +{ + if (ZEND_USER_CODE(EX(func)->type)) { + uint32_t passed_args = EX_NUM_ARGS(), args = EX(func)->op_array.num_args;; + if (passed_args < args) { + zval *arg = ZEND_CALL_ARG(execute_data, passed_args); + zval *end = ZEND_CALL_ARG(execute_data, args); + do { + --arg; + ZVAL_UNDEF(arg); + } while (arg != end); + } + } +} + static char * zend_verify_internal_arg_class_kind(const zend_internal_arg_info *cur_arg_info, char **class_name, zend_class_entry **pce) { zend_string *key; @@ -634,6 +641,8 @@ static ZEND_COLD void zend_verify_arg_error(const zend_function *zf, uint32_t ar const char *fsep; const char *fclass; + zend_undef_unpassed_args(EG(current_execute_data)); + if (zf->common.scope) { fsep = "::"; fclass = ZSTR_VAL(zf->common.scope->name); @@ -902,6 +911,8 @@ static ZEND_COLD void zend_verify_missing_arg(zend_execute_data *execute_data, u const char *func_name = EX(func)->common.function_name ? ZSTR_VAL(EX(func)->common.function_name) : "main"; zend_execute_data *ptr = EX(prev_execute_data); + zend_undef_unpassed_args(EG(current_execute_data)); + if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) { zend_error(E_WARNING, "Missing argument %u for %s%s%s(), called in %s on line %d and defined", arg_num, class_name, space, func_name, ZSTR_VAL(ptr->func->op_array.filename), ptr->opline->lineno); } else { @@ -2023,6 +2034,110 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c } } +static zend_always_inline zend_bool zend_check_abstract_or_deprecated(zend_function *fbc) { + if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { + zend_throw_error(NULL, "Cannot call abstract method %s::%s()", ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name)); + return 1; + } + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { + zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", + fbc->common.scope ? ZSTR_VAL(fbc->common.scope->name) : "", + fbc->common.scope ? "::" : "", + ZSTR_VAL(fbc->common.function_name)); + return UNEXPECTED(EG(exception) != NULL); + } + } + return 0; +} + +static zend_always_inline void unpack_iterator_to_array(zend_object_iterator *iter, HashTable *ht, zend_execute_data *execute_data, uint32_t arg_num) +{ + zval *arg; + + if (iter->funcs->rewind) { + iter->funcs->rewind(iter); + if (UNEXPECTED(EG(exception) != NULL)) { + goto unpack_iter_dtor; + } + } + + while (iter->funcs->valid(iter) == SUCCESS) { + if (UNEXPECTED(EG(exception) != NULL)) { + goto unpack_iter_dtor; + } + + arg = iter->funcs->get_current_data(iter); + if (UNEXPECTED(EG(exception) != NULL)) { + goto unpack_iter_dtor; + } + + if (iter->funcs->get_current_key) { + zval key; + iter->funcs->get_current_key(iter, &key); + if (UNEXPECTED(EG(exception) != NULL)) { + goto unpack_iter_dtor; + } + + if (Z_TYPE(key) == IS_STRING) { + zend_throw_error(NULL, + "Cannot unpack Traversable with string keys"); + zend_string_release(Z_STR(key)); + goto unpack_iter_dtor; + } + + zval_dtor(&key); + } + + if (ARG_MUST_BE_SENT_BY_REF(EX(func), arg_num)) { + zend_error( + E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" + " by unpacking a Traversable, passing by-value instead", arg_num, + EX(func)->common.scope ? ZSTR_VAL(EX(func)->common.scope->name) : "", + EX(func)->common.scope ? "::" : "", + ZSTR_VAL(EX(func)->common.function_name) + ); + } + + if (Z_ISREF_P(arg)) { + ZVAL_DUP(arg, Z_REFVAL_P(arg)); + } else { + Z_TRY_ADDREF_P(arg); + } + + zend_hash_next_index_insert(ht, arg); + arg_num++; + + iter->funcs->move_forward(iter); + if (UNEXPECTED(EG(exception) != NULL)) { + goto unpack_iter_dtor; + } + } + +unpack_iter_dtor: + zend_iterator_dtor(iter); +} + +static zend_always_inline void unpack_array_separate(zval *args, HashTable **ht, zend_execute_data *execute_data, uint32_t arg_num, zend_uchar op_type) +{ + if (op_type != IS_CONST && op_type != IS_TMP_VAR && Z_IMMUTABLE_P(args)) { + uint32_t i, elements = zend_hash_num_elements(*ht); + int separate = 0; + + /* check if any of arguments are going to be passed by reference */ + for (i = 0; i < elements; i++) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(func), arg_num + i)) { + separate = 1; + break; + } + } + if (separate) { + zval_copy_ctor(args); + *ht = Z_ARRVAL_P(args); + } + } +} + #if ZEND_INTENSIVE_DEBUGGING #define CHECK_SYMBOL_TABLES() \ @@ -2116,18 +2231,20 @@ void zend_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */ * ================== * * +========================================+ + * | ARG[N+1] (extra_args) | + * | ... | + * EX_PARAM_NUM(num_args) --> | VAR[-op_array->num_args-ZCFS] = ARG[N] | + * | ... | + * EX_PARAM_NUM(1) ---------> | VAR[-1-ZEND_CALL_FRAME_SLOT] = ARG[1] | + * +----------------------------------------+ * EG(current_execute_data) -> | zend_execute_data | * +----------------------------------------+ - * EX_CV_NUM(0) ---------> | VAR[0] = ARG[1] | - * | ... | - * | VAR[op_array->num_args-1] = ARG[N] | + * EX_VAR_NUM(0) -----------> | VAR[0] = CV[0] | * | ... | - * | VAR[op_array->last_var-1] | + * | VAR[op_array->last_var-1] = CV[N] | * | VAR[op_array->last_var] = TMP[0] | * | ... | * | VAR[op_array->last_var+op_array->T-1] | - * | ARG[N+1] (extra_args) | - * | ... | * +----------------------------------------+ */ @@ -2137,48 +2254,35 @@ static zend_always_inline void i_init_func_execute_data(zend_execute_data *execu ZEND_ASSERT(EX(func) == (zend_function*)op_array); EX(opline) = op_array->opcodes; - EX(call) = NULL; EX(return_value) = return_value; /* Handle arguments */ first_extra_arg = op_array->num_args; num_args = EX_NUM_ARGS(); if (UNEXPECTED(num_args > first_extra_arg)) { - zval *end, *src, *dst; - uint32_t type_flags = 0; - +/* ??? uint32_t type_flags = 0; + zval *end, *src; +*/ if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) { /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */ EX(opline) += first_extra_arg; } - /* move extra args into separate array after all CV and TMP vars */ - end = EX_VAR_NUM(first_extra_arg - 1); - src = end + (num_args - first_extra_arg); - dst = src + (op_array->last_var + op_array->T - first_extra_arg); - if (EXPECTED(src != dst)) { - do { - type_flags |= Z_TYPE_INFO_P(src); - ZVAL_COPY_VALUE(dst, src); - ZVAL_UNDEF(src); - src--; - dst--; - } while (src != end); - } else { - do { - type_flags |= Z_TYPE_INFO_P(src); - src--; - } while (src != end); - } +/* ??? src = EX_PARAM_NUM(first_extra_arg); + end = EX_PARAM_NUM(num_args); + do { + type_flags |= Z_TYPE_INFO_P(src); + } while (src-- != end); ZEND_ADD_CALL_FLAG(execute_data, ((type_flags >> Z_TYPE_FLAGS_SHIFT) & IS_TYPE_REFCOUNTED)); +*/ } else if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) { /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */ EX(opline) += num_args; } /* Initialize CV variables (skip arguments) */ - if (EXPECTED((int)num_args < op_array->last_var)) { - zval *var = EX_VAR_NUM(num_args); + if (EXPECTED(op_array->last_var)) { + zval *var = EX_VAR_NUM(0); zval *end = EX_VAR_NUM(op_array->last_var); do { @@ -2209,7 +2313,6 @@ static zend_always_inline void i_init_code_execute_data(zend_execute_data *execu ZEND_ASSERT(EX(func) == (zend_function*)op_array); EX(opline) = op_array->opcodes; - EX(call) = NULL; EX(return_value) = return_value; if (UNEXPECTED(op_array->this_var != (uint32_t)-1) && EXPECTED(Z_OBJ(EX(This)))) { @@ -2238,7 +2341,6 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da ZEND_ASSERT(EX(func) == (zend_function*)op_array); EX(opline) = op_array->opcodes; - EX(call) = NULL; EX(return_value) = return_value; if (UNEXPECTED(EX(symbol_table) != NULL)) { @@ -2257,41 +2359,29 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da first_extra_arg = op_array->num_args; num_args = EX_NUM_ARGS(); if (UNEXPECTED(num_args > first_extra_arg)) { - zval *end, *src, *dst; +/* ??? zval *end, *src; uint32_t type_flags = 0; - +*/ if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) { /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */ EX(opline) += first_extra_arg; } - /* move extra args into separate array after all CV and TMP vars */ - end = EX_VAR_NUM(first_extra_arg - 1); - src = end + (num_args - first_extra_arg); - dst = src + (op_array->last_var + op_array->T - first_extra_arg); - if (EXPECTED(src != dst)) { - do { - type_flags |= Z_TYPE_INFO_P(src); - ZVAL_COPY_VALUE(dst, src); - ZVAL_UNDEF(src); - src--; - dst--; - } while (src != end); - } else { - do { - type_flags |= Z_TYPE_INFO_P(src); - src--; - } while (src != end); - } +/* ??? src = EX_PARAM_NUM(first_extra_arg); + end = EX_PARAM_NUM(num_args); + do { + type_flags |= Z_TYPE_INFO_P(src); + } while (src-- != end); ZEND_ADD_CALL_FLAG(execute_data, ((type_flags >> Z_TYPE_FLAGS_SHIFT) & IS_TYPE_REFCOUNTED)); +*/ } else if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) { /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */ EX(opline) += num_args; } /* Initialize CV variables (skip arguments) */ - if (EXPECTED((int)num_args < op_array->last_var)) { - zval *var = EX_VAR_NUM(num_args); + if (EXPECTED(op_array->last_var)) { + zval *var = EX_VAR_NUM(0); zval *end = EX_VAR_NUM(op_array->last_var); do { @@ -2335,7 +2425,8 @@ ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data */ zend_execute_data *execute_data; uint32_t num_args = ZEND_CALL_NUM_ARGS(call); - size_t stack_size = (ZEND_CALL_FRAME_SLOT + MAX(op_array->last_var + op_array->T, num_args)) * sizeof(zval); + uint32_t arg_offset = MAX(num_args, op_array->num_args); + size_t stack_size = op_array->stack_size + (arg_offset * sizeof(zval)); uint32_t call_info; EG(vm_stack) = zend_vm_stack_new_page( @@ -2343,32 +2434,31 @@ ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data ZEND_VM_STACK_PAGE_SIZE(1) : ZEND_VM_STACK_PAGE_ALIGNED_SIZE(1, stack_size), NULL); - EG(vm_stack_top) = EG(vm_stack)->top; EG(vm_stack_end) = EG(vm_stack)->end; + execute_data = (zend_execute_data *) (ZEND_VM_STACK_ELEMENTS(EG(vm_stack)) + arg_offset); call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_ALLOCATED | (ZEND_CALL_INFO(call) & (ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS)); if (Z_OBJ(call->This)) { call_info |= ZEND_CALL_RELEASE_THIS; } - execute_data = zend_vm_stack_push_call_frame( + zend_init_call_frame(execute_data, call_info, (zend_function*)op_array, num_args, call->called_scope, Z_OBJ(call->This)); EX(prev_execute_data) = NULL; - EX_NUM_ARGS() = num_args; /* copy arguments */ if (num_args > 0) { zval *arg_src = ZEND_CALL_ARG(call, 1); zval *arg_dst = ZEND_CALL_ARG(execute_data, 1); - zval *end = arg_src + num_args; + zval *end = arg_src - num_args; do { ZVAL_COPY_VALUE(arg_dst, arg_src); - arg_src++; - arg_dst++; + arg_src--; + arg_dst--; } while (arg_src != end); } @@ -2394,13 +2484,14 @@ static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(const zend_op } /* }}} */ +/* This function must be called *at most once* per call frame to avoid leaking */ static zend_execute_data *zend_vm_stack_copy_call_frame(zend_execute_data *call, uint32_t passed_args, uint32_t additional_args) /* {{{ */ { zend_execute_data *new_call; - int used_stack = (EG(vm_stack_top) - (zval*)call) + additional_args; + int total_args = MAX(call->func->op_array.num_args, passed_args + additional_args); /* copy call frame into new stack segment */ - new_call = zend_vm_stack_extend(used_stack * sizeof(zval)); + new_call = (zend_execute_data *) (((zval *) zend_vm_stack_extend(zend_vm_calc_used_stack(total_args, call->func))) + total_args); *new_call = *call; ZEND_SET_CALL_INFO(new_call, ZEND_CALL_INFO(new_call) | ZEND_CALL_ALLOCATED); @@ -2409,33 +2500,25 @@ static zend_execute_data *zend_vm_stack_copy_call_frame(zend_execute_data *call, zval *dst = ZEND_CALL_ARG(new_call, 1); do { ZVAL_COPY_VALUE(dst, src); - passed_args--; - src++; - dst++; - } while (passed_args); - } - - /* delete old call_frame from previous stack segment */ - EG(vm_stack)->prev->top = (zval*)call; - - /* delete previous stack segment if it becames empty */ - if (UNEXPECTED(EG(vm_stack)->prev->top == ZEND_VM_STACK_ELEMENTS(EG(vm_stack)->prev))) { - zend_vm_stack r = EG(vm_stack)->prev; - - EG(vm_stack)->prev = r->prev; - efree(r); + src--; + dst--; + } while (--passed_args); } return new_call; } /* }}} */ -static zend_always_inline void zend_vm_stack_extend_call_frame(zend_execute_data **call, uint32_t passed_args, uint32_t additional_args) /* {{{ */ +/* Same as for zend_vm_stack_copy_call_frame(), at most one call per call frame */ +static zend_always_inline zend_execute_data *zend_vm_stack_extend_call_frame(zend_execute_data *call, uint32_t passed_args, uint32_t additional_args) /* {{{ */ { - if (EXPECTED((uint32_t)(EG(vm_stack_end) - EG(vm_stack_top)) > additional_args)) { - EG(vm_stack_top) += additional_args; + uint32_t stack_size = zend_vm_calc_used_stack(additional_args, call->func); + if (EXPECTED(((intptr_t) EG(vm_stack_end)) - ((intptr_t) call) > stack_size)) { + zval *src = ((zval *) call) - passed_args; + memmove(src + additional_args, src, sizeof(zval) * (passed_args + ZEND_CALL_FRAME_SLOT)); + return (zend_execute_data *) (((zval *) call) + additional_args); } else { - *call = zend_vm_stack_copy_call_frame(*call, passed_args, additional_args); + return zend_vm_stack_copy_call_frame(call, passed_args, additional_args); } } /* }}} */ @@ -2450,129 +2533,32 @@ static zend_always_inline zend_generator *zend_get_running_generator(zend_execut } /* }}} */ -static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t op_num) /* {{{ */ +static zend_always_inline void cleanup_this_object_call(zend_execute_data *execute_data, zend_bool check_ctor_call) /* {{{ */ { - if (UNEXPECTED(EX(call))) { - zend_execute_data *call = EX(call); - zend_op *opline = EX(func)->op_array.opcodes + op_num; - int level; - int do_exit; - - if (UNEXPECTED(opline->opcode == ZEND_INIT_FCALL || - opline->opcode == ZEND_INIT_FCALL_BY_NAME || - opline->opcode == ZEND_INIT_DYNAMIC_CALL || - opline->opcode == ZEND_INIT_METHOD_CALL || - opline->opcode == ZEND_INIT_STATIC_METHOD_CALL)) { - ZEND_ASSERT(op_num); - opline--; - } - - do { - /* If the exception was thrown during a function call there might be - * arguments pushed to the stack that have to be dtor'ed. */ - - /* find the number of actually passed arguments */ - level = 0; - do_exit = 0; - do { - switch (opline->opcode) { - case ZEND_DO_FCALL: - case ZEND_DO_ICALL: - case ZEND_DO_UCALL: - case ZEND_DO_FCALL_BY_NAME: - level++; - break; - case ZEND_INIT_FCALL: - case ZEND_INIT_FCALL_BY_NAME: - case ZEND_INIT_NS_FCALL_BY_NAME: - case ZEND_INIT_DYNAMIC_CALL: - case ZEND_INIT_USER_CALL: - case ZEND_INIT_METHOD_CALL: - case ZEND_INIT_STATIC_METHOD_CALL: - case ZEND_NEW: - if (level == 0) { - ZEND_CALL_NUM_ARGS(call) = 0; - do_exit = 1; - } - level--; - break; - case ZEND_SEND_VAL: - case ZEND_SEND_VAL_EX: - case ZEND_SEND_VAR: - case ZEND_SEND_VAR_EX: - case ZEND_SEND_REF: - case ZEND_SEND_VAR_NO_REF: - case ZEND_SEND_USER: - if (level == 0) { - ZEND_CALL_NUM_ARGS(call) = opline->op2.num; - do_exit = 1; - } - break; - case ZEND_SEND_ARRAY: - case ZEND_SEND_UNPACK: - if (level == 0) { - do_exit = 1; - } - break; - } - if (!do_exit) { - opline--; - } - } while (!do_exit); - if (call->prev_execute_data) { - /* skip current call region */ - level = 0; - do_exit = 0; - do { - switch (opline->opcode) { - case ZEND_DO_FCALL: - case ZEND_DO_ICALL: - case ZEND_DO_UCALL: - case ZEND_DO_FCALL_BY_NAME: - level++; - break; - case ZEND_INIT_FCALL: - case ZEND_INIT_FCALL_BY_NAME: - case ZEND_INIT_NS_FCALL_BY_NAME: - case ZEND_INIT_DYNAMIC_CALL: - case ZEND_INIT_USER_CALL: - case ZEND_INIT_METHOD_CALL: - case ZEND_INIT_STATIC_METHOD_CALL: - case ZEND_NEW: - if (level == 0) { - do_exit = 1; - } - level--; - break; - } - opline--; - } while (!do_exit); - } - - zend_vm_stack_free_args(EX(call)); - - if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) { - if (ZEND_CALL_INFO(call) & ZEND_CALL_CTOR) { - if (!(ZEND_CALL_INFO(call) & ZEND_CALL_CTOR_RESULT_UNUSED)) { - GC_REFCOUNT(Z_OBJ(call->This))--; - } - if (GC_REFCOUNT(Z_OBJ(call->This)) == 1) { - zend_object_store_ctor_failed(Z_OBJ(call->This)); - } - } - OBJ_RELEASE(Z_OBJ(call->This)); + if (UNEXPECTED(EX_CALL_INFO() & ZEND_CALL_RELEASE_THIS)) { + zend_object *object = Z_OBJ(EX(This)); + if (check_ctor_call && (EX_CALL_INFO() & ZEND_CALL_CTOR)) { + if (!(EX_CALL_INFO() & ZEND_CALL_CTOR_RESULT_UNUSED)) { + GC_REFCOUNT(object)--; } - if (call->func->common.fn_flags & ZEND_ACC_CLOSURE) { - zend_object_release((zend_object *) call->func->common.prototype); - } else if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) { - zend_string_release(call->func->common.function_name); - zend_free_trampoline(call->func); + if (GC_REFCOUNT(object) == 1) { + zend_object_store_ctor_failed(object); } + } + OBJ_RELEASE(object); + } +} +/* }}} */ + +static void cleanup_uncalled_execute_data(zend_execute_data *execute_data) /* {{{ */ +{ + cleanup_this_object_call(execute_data, 1); - EX(call) = call->prev_execute_data; - zend_vm_stack_free_call_frame(call); - call = EX(call); - } while (call); + if (EX(func)->common.fn_flags & ZEND_ACC_CLOSURE) { + zend_object_release((zend_object *) EX(func)->common.prototype); + } else if (EX(func)->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) { + zend_string_release(EX(func)->common.function_name); + zend_free_trampoline(EX(func)); } } /* }}} */ @@ -2615,6 +2601,8 @@ static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, zend_string_release(rope[j]); } while (j--); } + } else if (kind == ZEND_LIVE_EXECUTE_DATA) { + cleanup_uncalled_execute_data((zend_execute_data *) var); } else if (kind == ZEND_LIVE_SILENCE) { /* restore previous error_reporting value */ if (!EG(error_reporting) && Z_LVAL_P(var) != 0) { @@ -2628,7 +2616,6 @@ static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, /* }}} */ void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) { - cleanup_unfinished_calls(execute_data, op_num); cleanup_live_vars(execute_data, op_num, catch_op_num); } diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 18f13396ad0ca..b6d774686040b 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -137,7 +137,6 @@ ZEND_API int zval_update_constant_ex(zval *pp, zend_bool inline_change, zend_cla /* dedicated Zend executor functions - do not use! */ struct _zend_vm_stack { - zval *top; zval *end; zend_vm_stack prev; }; @@ -156,8 +155,8 @@ struct _zend_vm_stack { * The following "#if ZEND_DEBUG" eliminates it. */ #if ZEND_DEBUG -# define ZEND_ASSERT_VM_STACK(stack) ZEND_ASSERT(stack->top > (zval *) stack && stack->end > (zval *) stack && stack->top <= stack->end) -# define ZEND_ASSERT_VM_STACK_GLOBAL ZEND_ASSERT(EG(vm_stack_top) > (zval *) EG(vm_stack) && EG(vm_stack_end) > (zval *) EG(vm_stack) && EG(vm_stack_top) <= EG(vm_stack_end)) +# define ZEND_ASSERT_VM_STACK(stack) ZEND_ASSERT(stack->end > (zval *) stack) +# define ZEND_ASSERT_VM_STACK_GLOBAL ZEND_ASSERT(EG(vm_stack_end) > (zval *) EG(vm_stack)) #else # define ZEND_ASSERT_VM_STACK(stack) # define ZEND_ASSERT_VM_STACK_GLOBAL @@ -167,117 +166,121 @@ ZEND_API void zend_vm_stack_init(void); ZEND_API void zend_vm_stack_destroy(void); ZEND_API void* zend_vm_stack_extend(size_t size); -static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame_ex(uint32_t used_stack, uint32_t call_info, zend_function *func, uint32_t num_args, zend_class_entry *called_scope, zend_object *object) +static zend_always_inline void zend_init_call_frame(zend_execute_data *execute_data, uint32_t call_info, zend_function *func, uint32_t num_args, zend_class_entry *called_scope, zend_object *object) { - zend_execute_data *call = (zend_execute_data*)EG(vm_stack_top); + ZEND_SET_CALL_INFO(execute_data, call_info); + EX(func) = func; + Z_OBJ(EX(This)) = object; + EX_NUM_ARGS() = num_args; + EX(called_scope) = called_scope; +} + +static zend_always_inline uint32_t zend_vm_calc_used_stack(uint32_t num_args, zend_function *func) +{ + return func->common.stack_size + (num_args * sizeof(zval)); +} + +/* to be used only when the exact number of args is already known at init time */ +static zend_always_inline zend_execute_data *zend_push_call_frame(zend_execute_data *execute_data, uint32_t call_info, zend_function *func, uint32_t num_args, zend_class_entry *called_scope, zend_object *object) { + size_t stack_size = zend_vm_calc_used_stack(0, func); + uint32_t total_args; - ZEND_ASSERT_VM_STACK_GLOBAL; + if (EXPECTED(((uintptr_t) execute_data) + stack_size < (uintptr_t) EG(vm_stack_end))) { + zend_init_call_frame(execute_data, call_info, func, num_args, called_scope, object); + return execute_data; + } - if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) { - call = (zend_execute_data*)zend_vm_stack_extend(used_stack); - ZEND_SET_CALL_INFO(call, call_info | ZEND_CALL_ALLOCATED); + if (ZEND_USER_CODE(func->type) && num_args < func->op_array.num_args) { + total_args = func->op_array.num_args; } else { - EG(vm_stack_top) = (zval*)((char*)call + used_stack); - ZEND_SET_CALL_INFO(call, call_info); + total_args = num_args; } - ZEND_ASSERT_VM_STACK_GLOBAL; + execute_data = (zend_execute_data *) (((zval *) zend_vm_stack_extend(stack_size + total_args * sizeof(zval *))) + total_args); - call->func = func; - Z_OBJ(call->This) = object; - ZEND_CALL_NUM_ARGS(call) = num_args; - call->called_scope = called_scope; - return call; + zend_init_call_frame(execute_data, call_info | ZEND_CALL_ALLOCATED, func, num_args, called_scope, object); + return execute_data; } -static zend_always_inline uint32_t zend_vm_calc_used_stack(uint32_t num_args, zend_function *func) -{ - uint32_t used_stack = ZEND_CALL_FRAME_SLOT + num_args; +static zend_always_inline zend_execute_data *zend_push_top_call_frame(uint32_t call_info, zend_function *func, uint32_t num_args, zend_class_entry *called_scope, zend_object *object) { + zend_execute_data *execute_data = EG(current_execute_data); + uint32_t passed_args = num_args; - if (EXPECTED(ZEND_USER_CODE(func->type))) { - used_stack += func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args); + if (UNEXPECTED(func->type == ZEND_USER_FUNCTION && num_args < func->op_array.num_args)) { + num_args = func->op_array.num_args; } - return used_stack * sizeof(zval); -} -static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(uint32_t call_info, zend_function *func, uint32_t num_args, zend_class_entry *called_scope, zend_object *object) -{ - uint32_t used_stack = zend_vm_calc_used_stack(num_args, func); + if (EXPECTED(execute_data)) { + execute_data = (zend_execute_data *) (((char *) execute_data) + zend_vm_calc_used_stack(num_args, EX(func))); + } else { + execute_data = (zend_execute_data *) (ZEND_VM_STACK_ELEMENTS(EG(vm_stack)) + num_args); + } - return zend_vm_stack_push_call_frame_ex(used_stack, call_info, - func, num_args, called_scope, object); + return zend_push_call_frame(execute_data, call_info, func, passed_args, called_scope, object); } -static zend_always_inline void zend_vm_stack_free_extra_args_ex(uint32_t call_info, zend_execute_data *call) +/* internal calls *and* cleanup of not yet called user funcs */ +static zend_always_inline void zend_free_args_internal(zend_execute_data *call, uint32_t num_args) { - if (UNEXPECTED(call_info & ZEND_CALL_FREE_EXTRA_ARGS)) { - zval *end = ZEND_CALL_VAR_NUM(call, call->func->op_array.last_var + call->func->op_array.T); - zval *p = end + (ZEND_CALL_NUM_ARGS(call) - call->func->op_array.num_args); + if (EXPECTED(num_args > 0)) { + zval *p = ZEND_CALL_ARG(call, 0); + zval *end = p - num_args; + do { p--; if (Z_REFCOUNTED_P(p)) { if (!Z_DELREF_P(p)) { zend_refcounted *r = Z_COUNTED_P(p); - ZVAL_NULL(p); + ZVAL_NULL(p); /* TODO: check if still necessary??? */ zval_dtor_func_for_ptr(r); - } else { - GC_ZVAL_CHECK_POSSIBLE_ROOT(p); } } } while (p != end); - } -} - -static zend_always_inline void zend_vm_stack_free_extra_args(zend_execute_data *call) -{ - zend_vm_stack_free_extra_args_ex(ZEND_CALL_INFO(call), call); + } } -static zend_always_inline void zend_vm_stack_free_args(zend_execute_data *call) +static zend_always_inline void zend_free_args_user(zend_execute_data *call) { - uint32_t num_args = ZEND_CALL_NUM_ARGS(call); + uint32_t passed_args = ZEND_CALL_NUM_ARGS(call); + uint32_t num_args = call->func->op_array.num_args; + /* Usually we don't push more args than available, but often less (default parameter values) */ + if (UNEXPECTED(num_args < passed_args)) { + num_args = passed_args; + } if (EXPECTED(num_args > 0)) { - zval *end = ZEND_CALL_ARG(call, 1); - zval *p = end + num_args; + zval *p = ZEND_CALL_ARG(call, 0); + zval *end = p - num_args; do { p--; if (Z_REFCOUNTED_P(p)) { if (!Z_DELREF_P(p)) { zend_refcounted *r = Z_COUNTED_P(p); - ZVAL_NULL(p); + ZVAL_NULL(p); /* TODO: check if still necessary??? */ zval_dtor_func_for_ptr(r); + } else { + GC_ZVAL_CHECK_POSSIBLE_ROOT(p); } } } while (p != end); } } -static zend_always_inline void zend_vm_stack_free_call_frame_ex(uint32_t call_info, zend_execute_data *call) +static zend_always_inline void zend_vm_stack_free_call_frame(uint32_t call_info) { - ZEND_ASSERT_VM_STACK_GLOBAL; - if (UNEXPECTED(call_info & ZEND_CALL_ALLOCATED)) { - zend_vm_stack p = EG(vm_stack); + ZEND_ASSERT_VM_STACK_GLOBAL; + zend_vm_stack p = EG(vm_stack); zend_vm_stack prev = p->prev; - EG(vm_stack_top) = prev->top; EG(vm_stack_end) = prev->end; EG(vm_stack) = prev; efree(p); - } else { - EG(vm_stack_top) = (zval*)call; + ZEND_ASSERT_VM_STACK_GLOBAL; } - - ZEND_ASSERT_VM_STACK_GLOBAL; -} - -static zend_always_inline void zend_vm_stack_free_call_frame(zend_execute_data *call) -{ - zend_vm_stack_free_call_frame_ex(ZEND_CALL_INFO(call), call); } /* services */ diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index fdffed34b2757..7821a401e1522 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -688,6 +688,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / zend_fcall_info_cache fci_cache_local; zend_function *func; zend_class_entry *orig_scope; + zend_bool reverse = 0; ZVAL_UNDEF(fci->retval); @@ -722,11 +723,11 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL && EG(current_execute_data)->opline->opcode != ZEND_DO_ICALL && EG(current_execute_data)->opline->opcode != ZEND_DO_UCALL && + EG(current_execute_data)->opline->opcode != ZEND_DO_UNPACK_FCALL && EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL_BY_NAME) { /* Insert fake frame in case of include or magic calls */ dummy_execute_data = *EG(current_execute_data); dummy_execute_data.prev_execute_data = EG(current_execute_data); - dummy_execute_data.call = NULL; dummy_execute_data.opline = NULL; dummy_execute_data.func = NULL; EG(current_execute_data) = &dummy_execute_data; @@ -763,9 +764,20 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / zend_string_release(callable_name); } + reverse = (fci->param_count & 0x80000000) != 0; + if (reverse) { + fci->param_count = -fci->param_count; + } func = fci_cache->function_handler; - call = zend_vm_stack_push_call_frame(ZEND_CALL_TOP_FUNCTION, - func, fci->param_count, fci_cache->called_scope, fci_cache->object); + if (EG(current_execute_data) == &dummy_execute_data) { + EG(current_execute_data) = EG(current_execute_data)->prev_execute_data; + call = zend_push_top_call_frame(ZEND_CALL_TOP_FUNCTION, + func, fci->param_count, fci_cache->called_scope, fci_cache->object); + EG(current_execute_data) = &dummy_execute_data; + } else { + call = zend_push_top_call_frame(ZEND_CALL_TOP_FUNCTION, + func, fci->param_count, fci_cache->called_scope, fci_cache->object); + } calling_scope = fci_cache->calling_scope; fci->object = fci_cache->object; if (fci->object && @@ -790,20 +802,18 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / } } - for (i=0; iparam_count; i++) { + for (i = 0; i < fci->param_count; i++) { zval *param; - zval *arg = &fci->params[i]; + zval *arg = &fci->params[(int32_t) (reverse ? -i : i)]; if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { if (fci->no_separation && !ARG_MAY_BE_SENT_BY_REF(func, i + 1)) { if (i) { - /* hack to clean up the stack */ - ZEND_CALL_NUM_ARGS(call) = i; - zend_vm_stack_free_args(call); + zend_free_args_internal(call, i); } - zend_vm_stack_free_call_frame(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", i+1, @@ -856,6 +866,13 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / zend_generator_create_zval(call, &func->op_array, fci->retval); } if (call_via_handler) { + /* we can't check for ZEND_CALL_ALLOCATED as ZEND_CALL_TRAMPOLINE may have altered the location of execute_data! */ + zend_execute_data *prev = EG(current_execute_data); + if (prev == &dummy_execute_data) { + prev = dummy_execute_data.prev_execute_data; + } + ZEND_SET_CALL_INFO(call, (void *) prev > (void *) EG(vm_stack_end) || (void *) prev < (void *) EG(vm_stack) ? ZEND_CALL_ALLOCATED : 0); + /* We must re-initialize function again */ fci_cache->initialized = 0; } @@ -875,7 +892,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / zend_execute_internal(call, fci->retval); } EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); /* We shouldn't fix bad extensions here, because it can break proper ones (Bug #34045) @@ -905,7 +922,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / zend_throw_error(NULL, "Cannot call overloaded function for non-object"); } - zend_vm_stack_free_args(call); + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); if (func->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { zend_string_release(func->common.function_name); @@ -919,7 +936,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / } EG(scope) = orig_scope; - zend_vm_stack_free_call_frame(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); if (EG(current_execute_data) == &dummy_execute_data) { EG(current_execute_data) = dummy_execute_data.prev_execute_data; @@ -1465,44 +1482,55 @@ ZEND_API zend_array *zend_rebuild_symbol_table(void) /* {{{ */ { zend_execute_data *ex; zend_array *symbol_table; + zend_string **str; + uint32_t cvs; /* Search for last called user function */ ex = EG(current_execute_data); while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->common.type))) { ex = ex->prev_execute_data; } - if (!ex) { + if (UNEXPECTED(!ex)) { return NULL; } if (ex->symbol_table) { return ex->symbol_table; } - if (EG(symtable_cache_ptr) >= EG(symtable_cache)) { + cvs = ex->func->op_array.last_var + ex->func->op_array.num_args; + if (EXPECTED(EG(symtable_cache_ptr) >= EG(symtable_cache))) { /*printf("Cache hit! Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/ symbol_table = ex->symbol_table = *(EG(symtable_cache_ptr)--); - if (!ex->func->op_array.last_var) { + if (UNEXPECTED(cvs == 0)) { return symbol_table; } - zend_hash_extend(symbol_table, ex->func->op_array.last_var, 0); + zend_hash_extend(symbol_table, cvs, 0); } else { symbol_table = ex->symbol_table = emalloc(sizeof(zend_array)); - zend_hash_init(symbol_table, ex->func->op_array.last_var, NULL, ZVAL_PTR_DTOR, 0); - if (!ex->func->op_array.last_var) { + zend_hash_init(symbol_table, cvs, NULL, ZVAL_PTR_DTOR, 0); + if (UNEXPECTED(cvs == 0)) { return symbol_table; } zend_hash_real_init(symbol_table, 0); /*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/ } + + str = ex->func->op_array.vars; + + if (EXPECTED(ex->func->op_array.num_args)) { + zend_string **end = str + ex->func->op_array.num_args; + zval *var = ZEND_CALL_ARG(ex, 1); + + do { + _zend_hash_append_ind(symbol_table, *(str++), var--); + } while (str != end); + } if (EXPECTED(ex->func->op_array.last_var)) { - zend_string **str = ex->func->op_array.vars; zend_string **end = str + ex->func->op_array.last_var; zval *var = ZEND_CALL_VAR_NUM(ex, 0); do { - _zend_hash_append_ind(symbol_table, *str, var); - str++; - var++; + _zend_hash_append_ind(symbol_table, *(str++), var++); } while (str != end); } return symbol_table; @@ -1513,11 +1541,35 @@ ZEND_API void zend_attach_symbol_table(zend_execute_data *execute_data) /* {{{ * { zend_op_array *op_array = &execute_data->func->op_array; HashTable *ht = execute_data->symbol_table; + zend_string **str = op_array->vars; /* copy real values from symbol table into CV slots and create INDIRECT references to CV in symbol table */ + if (UNEXPECTED(op_array->num_args)) { + zend_string **end = str + op_array->num_args; + zval *var = ZEND_CALL_ARG(execute_data, 1); + + do { + zval *zv = zend_hash_find(ht, *str); + + if (zv) { + if (Z_TYPE_P(zv) == IS_INDIRECT) { + zval *val = Z_INDIRECT_P(zv); + + ZVAL_COPY_VALUE(var, val); + } else { + ZVAL_COPY_VALUE(var, zv); + } + } else { + ZVAL_UNDEF(var); + zv = zend_hash_add_new(ht, *str, var); + } + ZVAL_INDIRECT(zv, var); + str++; + var--; + } while (str != end); + } if (EXPECTED(op_array->last_var)) { - zend_string **str = op_array->vars; zend_string **end = str + op_array->last_var; zval *var = EX_VAR_NUM(0); diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 777adb56b0501..1d50118cfce12 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -47,16 +47,12 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato /* There may be calls to zend_vm_stack_free_call_frame(), which modifies the VM stack * globals, so need to load/restore those. */ zend_vm_stack original_stack = EG(vm_stack); - original_stack->top = EG(vm_stack_top); - EG(vm_stack_top) = generator->stack->top; EG(vm_stack_end) = generator->stack->end; EG(vm_stack) = generator->stack; zend_cleanup_unfinished_execution(execute_data, op_num, 0); generator->stack = EG(vm_stack); - generator->stack->top = EG(vm_stack_top); - EG(vm_stack_top) = original_stack->top; EG(vm_stack_end) = original_stack->end; EG(vm_stack) = original_stack; } @@ -90,7 +86,7 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished return; } - zend_vm_stack_free_extra_args(generator->execute_data); + zend_free_args_user(generator->execute_data); /* Some cleanups are only necessary if the generator was closed * before it could finish execution (reach a return statement). */ @@ -226,8 +222,6 @@ ZEND_API void zend_generator_create_zval(zend_execute_data *call, zend_op_array zend_execute_data *execute_data; zend_vm_stack current_stack = EG(vm_stack); - current_stack->top = EG(vm_stack_top); - /* Create new execution context. We have to back up and restore EG(current_execute_data) here. */ current_execute_data = EG(current_execute_data); execute_data = zend_create_generator_execute_data(call, op_array, return_value); @@ -243,8 +237,6 @@ ZEND_API void zend_generator_create_zval(zend_execute_data *call, zend_op_array generator = (zend_generator *) Z_OBJ_P(return_value); generator->execute_data = execute_data; generator->stack = EG(vm_stack); - generator->stack->top = EG(vm_stack_top); - EG(vm_stack_top) = current_stack->top; EG(vm_stack_end) = current_stack->end; EG(vm_stack) = current_stack; @@ -657,12 +649,10 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */ zend_execute_data *original_execute_data = EG(current_execute_data); zend_class_entry *original_scope = EG(scope); zend_vm_stack original_stack = EG(vm_stack); - original_stack->top = EG(vm_stack_top); /* Set executor globals */ EG(current_execute_data) = generator->execute_data; EG(scope) = generator->execute_data->func->common.scope; - EG(vm_stack_top) = generator->stack->top; EG(vm_stack_end) = generator->stack->end; EG(vm_stack) = generator->stack; @@ -683,16 +673,14 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */ zend_execute_ex(generator->execute_data); generator->flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING; - /* Unlink generator call_frame from the caller and backup vm_stack_top */ + /* Unlink generator call_frame from the caller and backup vm_stack */ if (EXPECTED(generator->execute_data)) { generator->stack = EG(vm_stack); - generator->stack->top = EG(vm_stack_top); } /* Restore executor globals */ EG(current_execute_data) = original_execute_data; EG(scope) = original_scope; - EG(vm_stack_top) = original_stack->top; EG(vm_stack_end) = original_stack->end; EG(vm_stack) = original_stack; diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 0ce6b85938734..fbe21c104ecd1 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -383,7 +383,7 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) efree_size(op_array->refcount, sizeof(*(op_array->refcount))); if (op_array->vars) { - i = op_array->last_var; + i = op_array->last_var + op_array->num_args; while (i > 0) { i--; zend_string_release(op_array->vars[i]); @@ -599,9 +599,110 @@ static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const ze return opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont; } +static uint32_t zend_resolve_fcall(zend_op_array *op_array, zend_op **opline, uint32_t offset) { + uint32_t lr_off = 0, end; + uint32_t fcall_Ts, max_fcall_Ts = 0; + zend_op *init = *opline; + uint32_t num_args = init->extended_value; + uint32_t *live_ranges; + + if (init->opcode == ZEND_INCLUDE_OR_EVAL) { + init->op1.var = offset; + init->op1_type = IS_TMP_VAR; + return ZEND_CALL_FRAME_SLOT; + } + + live_ranges = emalloc(sizeof(uint32_t) * num_args); + + if (init->opcode == ZEND_INIT_FCALL && init->result.num == 0) { + zend_function *fbc = zend_hash_find_ptr(CG(function_table), Z_STR_P(CT_CONSTANT_EX(op_array, init->op2.constant))); + ZEND_ASSERT(fbc); + if (ZEND_USER_CODE(fbc->type)) { + num_args = MAX(num_args, fbc->op_array.num_args); + } + } else { + num_args += ZEND_RESERVED_RECV_SLOTS; + } + + if (init->opcode != ZEND_NEW) { + /* only one result var per opcode ... can't set object *and* execute_data as result ... maybe find a better solution? */ + init->result.var = offset + num_args; + init->result_type = IS_TMP_VAR; + } + + while (1) { + switch ((++*opline)->opcode) { + case ZEND_NEW: + case ZEND_INIT_FCALL_BY_NAME: + case ZEND_INIT_FCALL: + case ZEND_INIT_NS_FCALL_BY_NAME: + case ZEND_INIT_METHOD_CALL: + case ZEND_INIT_STATIC_METHOD_CALL: + case ZEND_INIT_USER_CALL: + case ZEND_INIT_DYNAMIC_CALL: + case ZEND_INCLUDE_OR_EVAL: + fcall_Ts = zend_resolve_fcall(op_array, opline, offset + num_args + ZEND_CALL_FRAME_SLOT); + if (fcall_Ts > max_fcall_Ts) { + max_fcall_Ts = fcall_Ts; + } + break; + + case ZEND_DO_FCALL: + case ZEND_DO_ICALL: + case ZEND_DO_UCALL: + case ZEND_DO_FCALL_BY_NAME: + case ZEND_DO_UNPACK_FCALL: + end = *opline - op_array->opcodes; + while (lr_off--) { + zend_live_range *range = op_array->live_range + live_ranges[lr_off]; + if (range->start == end && live_ranges[lr_off] == op_array->last_live_range - 1) { + op_array->last_live_range--; + } else { + range->end = end; + } + } + zend_end_live_range(op_array, (*opline)->op1.num, *opline - op_array->opcodes, ZEND_LIVE_EXECUTE_DATA, offset + num_args); + (*opline)->op1_type = IS_TMP_VAR; + (*opline)->op1.var = offset + num_args; + + efree(live_ranges); + return ZEND_CALL_FRAME_SLOT + num_args + max_fcall_Ts; + + case ZEND_SEND_VAL: + case ZEND_SEND_VAR_EX: + case ZEND_SEND_REF: + case ZEND_SEND_VAR_NO_REF: + case ZEND_SEND_VAL_EX: + case ZEND_SEND_VAR: + case ZEND_SEND_USER: + live_ranges[lr_off] = (*opline)->result.num; + (*opline)->result.var = num_args - ((*opline)->extended_value & ZEND_ARG_SEND_MASK) + offset; + (*opline)->result_type = IS_VAR; + op_array->live_range[live_ranges[lr_off]].var = ((*opline)->result.var * sizeof(zval)) | ZEND_LIVE_TMPVAR; + lr_off++; + case ZEND_SEND_UNPACK: + case ZEND_FETCH_FUNC_ARG: + (*opline)->op2.var = offset + num_args; + (*opline)->op2_type = IS_TMP_VAR; + break; + + /* No operands left, using ZEND_OP_DATA here */ + case ZEND_FETCH_STATIC_PROP_FUNC_ARG: + case ZEND_FETCH_DIM_FUNC_ARG: + case ZEND_FETCH_OBJ_FUNC_ARG: + (*opline)++; + ZEND_ASSERT((*opline)->opcode == ZEND_OP_DATA); + (*opline)->op2.var = offset + num_args; + (*opline)->op2_type = IS_TMP_VAR; + break; + } + } +} + ZEND_API int pass_two(zend_op_array *op_array) { - zend_op *opline, *end; + zend_op *opline, *end, *fcall_end = NULL; + uint32_t max_fcall_Ts = 0; if (!ZEND_USER_CODE(op_array->type)) { return 0; @@ -616,8 +717,9 @@ ZEND_API int pass_two(zend_op_array *op_array) } if (CG(context).vars_size != op_array->last_var) { - op_array->vars = (zend_string**) erealloc(op_array->vars, sizeof(zend_string*)*op_array->last_var); - CG(context).vars_size = op_array->last_var; + uint32_t negative_vars = op_array->num_args + ((op_array->fn_flags & ZEND_ACC_VARIADIC) != 0); + CG(context).vars_size = op_array->last_var + negative_vars; + op_array->vars = (zend_string **) erealloc(op_array->vars, sizeof(zend_string *) * CG(context).vars_size); } if (CG(context).opcodes_size != op_array->last) { op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last); @@ -641,10 +743,6 @@ ZEND_API int pass_two(zend_op_array *op_array) break; case ZEND_DECLARE_ANON_INHERITED_CLASS: ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1); - /* break omitted intentionally */ - case ZEND_DECLARE_INHERITED_CLASS: - case ZEND_DECLARE_INHERITED_CLASS_DELAYED: - opline->extended_value = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->extended_value); break; case ZEND_BRK: case ZEND_CONT: @@ -684,7 +782,6 @@ ZEND_API int pass_two(zend_op_array *op_array) case ZEND_JMPNZ_EX: case ZEND_JMP_SET: case ZEND_COALESCE: - case ZEND_NEW: case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2); @@ -715,6 +812,25 @@ ZEND_API int pass_two(zend_op_array *op_array) opline->opcode = ZEND_GENERATOR_RETURN; } break; + case ZEND_NEW: + ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2); + case ZEND_INIT_FCALL_BY_NAME: + case ZEND_INIT_FCALL: + case ZEND_INIT_NS_FCALL_BY_NAME: + case ZEND_INIT_METHOD_CALL: + case ZEND_INIT_STATIC_METHOD_CALL: + case ZEND_INIT_USER_CALL: + case ZEND_INIT_DYNAMIC_CALL: + case ZEND_INCLUDE_OR_EVAL: + if (opline > fcall_end) { + uint32_t fcall_Ts; + fcall_end = opline; + fcall_Ts = zend_resolve_fcall(op_array, &fcall_end, op_array->T); + if (max_fcall_Ts < fcall_Ts) { + max_fcall_Ts = fcall_Ts; + } + } + break; } if (opline->op1_type == IS_CONST) { ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op1); @@ -729,10 +845,16 @@ ZEND_API int pass_two(zend_op_array *op_array) if (opline->result_type & (IS_VAR|IS_TMP_VAR)) { opline->result.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->result.var); } + if ((zend_get_opcode_flags(opline->opcode) & ZEND_VM_EXT_MASK) == ZEND_VM_EXT_VAR) { + opline->extended_value = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->extended_value); + } ZEND_VM_SET_OPCODE_HANDLER(opline); opline++; } + op_array->T += max_fcall_Ts; + op_array->stack_size = (uint32_t)(zend_intptr_t)(((zval *) NULL) + (ZEND_CALL_FRAME_SLOT + op_array->T + op_array->last_var)); + if (op_array->live_range) { uint32_t i; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index eccb65a3ae827..6f0f76bc2d078 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1470,7 +1470,7 @@ ZEND_VM_HANDLER(40, ZEND_ECHO, CONST|TMPVAR|CV, ANY) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HELPER(zend_fetch_var_address_helper, CONST|TMPVAR|CV, UNUSED, int type) +ZEND_VM_HELPER(zend_fetch_var_address_helper, CONST|TMPVAR|CV, ANY, int type) { USE_OPLINE zend_free_op free_op1; @@ -1579,11 +1579,11 @@ ZEND_VM_HANDLER(86, ZEND_FETCH_RW, CONST|TMPVAR|CV, UNUSED, VAR_FETCH) ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_var_address_helper, type, BP_VAR_RW); } -ZEND_VM_HANDLER(92, ZEND_FETCH_FUNC_ARG, CONST|TMPVAR|CV, UNUSED, VAR_FETCH|ARG_NUM) +ZEND_VM_HANDLER(92, ZEND_FETCH_FUNC_ARG, CONST|TMPVAR|CV, TMP, VAR_FETCH|ARG_NUM) { USE_OPLINE - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR(opline->op2.var))) { ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_var_address_helper, type, BP_VAR_W); } else { ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_var_address_helper, type, BP_VAR_R); @@ -1600,7 +1600,7 @@ ZEND_VM_HANDLER(89, ZEND_FETCH_IS, CONST|TMPVAR|CV, UNUSED, VAR_FETCH) ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_var_address_helper, type, BP_VAR_IS); } -ZEND_VM_HELPER(zend_fetch_static_prop_helper, CONST|TMPVAR|CV, UNUSED|CONST|VAR, int type) +ZEND_VM_HELPER(zend_fetch_static_prop_helper, CONST|TMPVAR|CV, UNUSED|CONST|VAR, int type, int skip) { USE_OPLINE zend_free_op free_op1; @@ -1702,43 +1702,43 @@ ZEND_VM_C_LABEL(fetch_static_prop_return): } else { ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); } ZEND_VM_HANDLER(173, ZEND_FETCH_STATIC_PROP_R, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) { - ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_R); + ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_R, skip, 1); } ZEND_VM_HANDLER(174, ZEND_FETCH_STATIC_PROP_W, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) { - ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_W); + ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_W, skip, 1); } ZEND_VM_HANDLER(175, ZEND_FETCH_STATIC_PROP_RW, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) { - ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_RW); + ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_RW, skip, 1); } ZEND_VM_HANDLER(177, ZEND_FETCH_STATIC_PROP_FUNC_ARG, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR, NUM) { USE_OPLINE - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { - ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_W); + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { + ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_W, skip, 2); } else { - ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_R); + ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_R, skip, 2); } } ZEND_VM_HANDLER(178, ZEND_FETCH_STATIC_PROP_UNSET, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) { - ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_UNSET); + ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_UNSET, skip, 1); } ZEND_VM_HANDLER(176, ZEND_FETCH_STATIC_PROP_IS, CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) { - ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_IS); + ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_IS, skip, 1); } ZEND_VM_HANDLER(81, ZEND_FETCH_DIM_R, CONST|TMPVAR|CV, CONST|TMPVAR|CV) @@ -1821,7 +1821,7 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUS SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); FREE_UNFETCHED_OP2(); @@ -1852,7 +1852,7 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUS FREE_OP2(); FREE_OP1(); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } ZEND_VM_HANDLER(96, ZEND_FETCH_DIM_UNSET, VAR|CV, CONST|TMPVAR|CV) @@ -1878,7 +1878,7 @@ ZEND_VM_HANDLER(96, ZEND_FETCH_DIM_UNSET, VAR|CV, CONST|TMPVAR|CV) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMP|VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV) +ZEND_VM_INLINE_HELPER(zend_fetch_obj_r_helper, CONST|TMP|VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, int skip) { USE_OPLINE zend_free_op free_op1; @@ -1948,7 +1948,12 @@ ZEND_VM_C_LABEL(fetch_obj_r_no_object): FREE_OP2(); FREE_OP1(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +ZEND_VM_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMP|VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV) +{ + ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_obj_r_helper, skip, 1); } ZEND_VM_HANDLER(85, ZEND_FETCH_OBJ_W, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV) @@ -2090,7 +2095,7 @@ ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, CONST|TMP|VAR|UNUSED|THIS|CV, CONST USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -2121,9 +2126,9 @@ ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, CONST|TMP|VAR|UNUSED|THIS|CV, CONST EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } FREE_OP1_VAR_PTR(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_DISPATCH_TO_HANDLER(ZEND_FETCH_OBJ_R); + ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_obj_r_helper, skip, 2); } } @@ -2438,7 +2443,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) if (UNEXPECTED(EX(symbol_table) != NULL)) { zend_clean_and_cache_symbol_table(EX(symbol_table)); } - zend_vm_stack_free_extra_args_ex(call_info, execute_data); + zend_free_args_user(execute_data); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { @@ -2463,7 +2468,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) } EG(scope) = EX(func)->op_array.scope; - zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); + zend_vm_stack_free_call_frame(call_info); if (UNEXPECTED(EG(exception) != NULL)) { const zend_op *old_opline = EX(opline); @@ -2483,7 +2488,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) efree_size(EX(func), sizeof(zend_op_array)); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); - zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); + zend_vm_stack_free_call_frame(call_info); zend_attach_symbol_table(execute_data); if (UNEXPECTED(EG(exception) != NULL)) { @@ -2499,7 +2504,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) if (UNEXPECTED(EX(symbol_table) != NULL)) { zend_clean_and_cache_symbol_table(EX(symbol_table)); } - zend_vm_stack_free_extra_args_ex(call_info, execute_data); + zend_free_args_user(execute_data); EG(current_execute_data) = EX(prev_execute_data); if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype); @@ -2983,7 +2988,6 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|THIS|CV, CONST|T zend_function *fbc; zend_class_entry *called_scope; zend_object *obj; - zend_execute_data *call; uint32_t call_info; SAVE_OPLINE(); @@ -3084,10 +3088,8 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|THIS|CV, CONST|T GC_REFCOUNT(obj)++; /* For $this pointer */ } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, obj); - call->prev_execute_data = EX(call); - EX(call) = call; FREE_OP2(); FREE_OP1(); @@ -3102,7 +3104,6 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, zend_class_entry *ce; zend_object *object; zend_function *fbc; - zend_execute_data *call; SAVE_OPLINE(); @@ -3228,10 +3229,8 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, } } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, ce, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -3241,7 +3240,6 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM) USE_OPLINE zend_function *fbc; zval *function_name, *func; - zend_execute_data *call; fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))); if (UNEXPECTED(fbc == NULL)) { @@ -3255,10 +3253,8 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM) fbc = Z_FUNC_P(func); CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc); } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL, NULL); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE(); } @@ -3272,7 +3268,6 @@ ZEND_VM_HANDLER(128, ZEND_INIT_DYNAMIC_CALL, ANY, CONST|TMPVAR|CV, NUM) zend_free_op free_op2; zend_class_entry *called_scope; zend_object *object; - zend_execute_data *call; uint32_t call_info = ZEND_CALL_NESTED_FUNCTION; SAVE_OPLINE(); @@ -3468,10 +3463,8 @@ ZEND_VM_C_LABEL(try_function_name): FREE_OP2(); HANDLE_EXCEPTION(); } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -3486,7 +3479,6 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM) zend_function *func; zend_class_entry *called_scope; zend_object *object; - zend_execute_data *call; uint32_t call_info = ZEND_CALL_NESTED_FUNCTION; SAVE_OPLINE(); @@ -3526,10 +3518,8 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM) object = NULL; } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, func, opline->extended_value, called_scope, object); - call->prev_execute_data = EX(call); - EX(call) = call; FREE_OP2(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -3541,7 +3531,6 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM) zval *func_name; zval *func; zend_function *fbc; - zend_execute_data *call; func_name = EX_CONSTANT(opline->op2) + 1; fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))); @@ -3560,10 +3549,8 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM) CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc); } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL, NULL); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE(); } @@ -3575,7 +3562,6 @@ ZEND_VM_HANDLER(61, ZEND_INIT_FCALL, ANY, CONST, NUM) zval *fname = GET_OP2_ZVAL_PTR(BP_VAR_R); zval *func; zend_function *fbc; - zend_execute_data *call; fbc = CACHED_PTR(Z_CACHE_SLOT_P(fname)); if (UNEXPECTED(fbc == NULL)) { @@ -3589,24 +3575,20 @@ ZEND_VM_HANDLER(61, ZEND_INIT_FCALL, ANY, CONST, NUM) CACHE_PTR(Z_CACHE_SLOT_P(fname), fbc); } - call = zend_vm_stack_push_call_frame_ex( - opline->op1.num, ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL, NULL); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(129, ZEND_DO_ICALL, ANY, ANY) +ZEND_VM_HANDLER(129, ZEND_DO_ICALL, TMP, ANY) { USE_OPLINE - zend_execute_data *call = EX(call); + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op1.var); zend_function *fbc = call->func; zval *ret; SAVE_OPLINE(); - EX(call) = call->prev_execute_data; call->prev_execute_data = execute_data; EG(current_execute_data) = call; @@ -3625,8 +3607,7 @@ ZEND_VM_HANDLER(129, ZEND_DO_ICALL, ANY, ANY) #endif EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); - zend_vm_stack_free_call_frame(call); + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); if (!RETURN_VALUE_USED(opline)) { zval_ptr_dtor(EX_VAR(opline->result.var)); @@ -3644,15 +3625,14 @@ ZEND_VM_HANDLER(129, ZEND_DO_ICALL, ANY, ANY) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(130, ZEND_DO_UCALL, ANY, ANY) +ZEND_VM_HANDLER(130, ZEND_DO_UCALL, TMP, NUM) { USE_OPLINE - zend_execute_data *call = EX(call); + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op1.var); zend_function *fbc = call->func; zval *ret; SAVE_OPLINE(); - EX(call) = call->prev_execute_data; EG(scope) = NULL; ret = NULL; @@ -3663,21 +3643,24 @@ ZEND_VM_HANDLER(130, ZEND_DO_UCALL, ANY, ANY) Z_VAR_FLAGS_P(ret) = 0; } + if (UNEXPECTED(((zval *) call) + opline->op2.num >= EG(vm_stack_end))) { + call = zend_vm_stack_copy_call_frame(call, ZEND_CALL_NUM_ARGS(call), 0); + } + call->prev_execute_data = execute_data; i_init_func_execute_data(call, &fbc->op_array, ret, 0); ZEND_VM_ENTER(); } -ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY) +ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, TMP, ANY) { USE_OPLINE - zend_execute_data *call = EX(call); + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op1.var); zend_function *fbc = call->func; zval *ret; SAVE_OPLINE(); - EX(call) = call->prev_execute_data; if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { EG(scope) = NULL; @@ -3687,11 +3670,11 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY) zend_generator_create_zval(call, &fbc->op_array, ret); Z_VAR_FLAGS_P(ret) = 0; } else { - zend_vm_stack_free_args(call); + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); } - - zend_vm_stack_free_call_frame(call); } else { + zend_op_array *op_array = &fbc->op_array; + ret = NULL; call->symbol_table = NULL; if (RETURN_VALUE_USED(opline)) { @@ -3700,8 +3683,14 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY) Z_VAR_FLAGS_P(ret) = 0; } + if (UNEXPECTED(((zval *)(((void *) call) + zend_vm_calc_used_stack(0, fbc))) >= EG(vm_stack_end))) { + call = zend_vm_stack_copy_call_frame(call, ZEND_CALL_NUM_ARGS(call), 0); + } else if (UNEXPECTED(ZEND_CALL_NUM_ARGS(call) + ZEND_RESERVED_RECV_SLOTS < op_array->num_args)) { + call = zend_vm_stack_extend_call_frame(call, ZEND_CALL_NUM_ARGS(call), op_array->num_args - ZEND_CALL_NUM_ARGS(call)); + } + call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret, 0); + i_init_func_execute_data(call, op_array, ret, 0); ZEND_VM_ENTER(); } @@ -3730,12 +3719,12 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY) for (i = 0; i < num_args; ++i) { if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) { EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); - zend_vm_stack_free_call_frame(call); + zend_free_args_internal(call, ZEND_CALL_INFO(call)); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); zend_throw_exception_internal(NULL); HANDLE_EXCEPTION(); } - p++; + p--; } } @@ -3753,8 +3742,7 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY) #endif EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); - zend_vm_stack_free_call_frame(call); + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); if (!RETURN_VALUE_USED(opline)) { zval_ptr_dtor(EX_VAR(opline->result.var)); @@ -3772,34 +3760,13 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) +ZEND_VM_INLINE_HELPER(zend_do_fcall_helper, TMP, ANY, zend_execute_data *call, zend_function *fbc, zend_bool extra_call_frame) { USE_OPLINE - zend_execute_data *call = EX(call); - zend_function *fbc = call->func; zend_object *object; zval *ret; - SAVE_OPLINE(); - EX(call) = call->prev_execute_data; - if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { - zend_throw_error(NULL, "Cannot call abstract method %s::%s()", ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name)); - HANDLE_EXCEPTION(); - } - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { - zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", - fbc->common.scope ? ZSTR_VAL(fbc->common.scope->name) : "", - fbc->common.scope ? "::" : "", - ZSTR_VAL(fbc->common.function_name)); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); - } - } - } - LOAD_OPLINE(); - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { EG(scope) = fbc->common.scope; if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) { @@ -3811,8 +3778,13 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) { OBJ_RELEASE((zend_object*)fbc->op_array.prototype); } - zend_vm_stack_free_args(call); + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); } + cleanup_this_object_call(call, UNEXPECTED(EG(exception) != NULL)); + if (UNEXPECTED(extra_call_frame != 0)) { + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + } + EG(scope) = EX(func)->op_array.scope; } else { ret = NULL; call->symbol_table = NULL; @@ -3822,14 +3794,30 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) Z_VAR_FLAGS_P(ret) = 0; } + if (EXPECTED(extra_call_frame == 0)) { + zend_op_array *op_array = &fbc->op_array; + if (UNEXPECTED(((zval *)(((void *) call) + zend_vm_calc_used_stack(0, fbc))) >= EG(vm_stack_end))) { + call = zend_vm_stack_copy_call_frame(call, ZEND_CALL_NUM_ARGS(call), 0); + } else if (UNEXPECTED(ZEND_CALL_NUM_ARGS(call) + ZEND_RESERVED_RECV_SLOTS < op_array->num_args)) { + call = zend_vm_stack_extend_call_frame(call, ZEND_CALL_NUM_ARGS(call), op_array->num_args - ZEND_CALL_NUM_ARGS(call)); + } + } + call->prev_execute_data = execute_data; i_init_func_execute_data(call, &fbc->op_array, ret, 1); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { + zval this = call->This; ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); zend_execute_ex(call); + /* unable to rely on initial call value, ... use backup for this freeing */ + call->This = this; + cleanup_this_object_call(call, UNEXPECTED(EG(exception) != NULL)); + /* we can't check for ZEND_CALL_ALLOCATED as ZEND_CALL_TRAMPOLINE may have altered the location of execute_data! */ + zend_vm_stack_free_call_frame((void *) execute_data > (void *) EG(vm_stack_end) || (void *) execute_data < (void *) EG(vm_stack) ? ZEND_CALL_ALLOCATED : 0); + EG(scope) = EX(func)->op_array.scope; } } } else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) { @@ -3850,18 +3838,10 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) for (i = 0; i < num_args; ++i) { if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) { - EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); - if (RETURN_VALUE_USED(opline)) { - ZVAL_UNDEF(EX_VAR(opline->result.var)); - } - if (UNEXPECTED(should_change_scope)) { - ZEND_VM_C_GOTO(fcall_end_change_scope); - } else { - ZEND_VM_C_GOTO(fcall_end); - } + ZVAL_UNDEF(EX_VAR(opline->result.var)); + ZEND_VM_C_GOTO(icall_end); } - p++; + p--; } } @@ -3875,7 +3855,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) } else { zend_execute_internal(call, ret); } - + #if ZEND_DEBUG ZEND_ASSERT( !call->func || @@ -3883,28 +3863,31 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var))); #endif +ZEND_VM_C_LABEL(icall_end): EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); if (!RETURN_VALUE_USED(opline)) { zval_ptr_dtor(EX_VAR(opline->result.var)); } if (UNEXPECTED(should_change_scope)) { - ZEND_VM_C_GOTO(fcall_end_change_scope); - } else { - ZEND_VM_C_GOTO(fcall_end); + cleanup_this_object_call(call, UNEXPECTED(EG(exception) != NULL)); + EG(scope) = EX(func)->op_array.scope; + } + if (UNEXPECTED(extra_call_frame != 0)) { + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); } } else { /* ZEND_OVERLOADED_FUNCTION */ /* Not sure what should be done here if it's a static method */ object = Z_OBJ(call->This); if (UNEXPECTED(object == NULL)) { - zend_vm_stack_free_args(call); + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { zend_string_release(fbc->common.function_name); } efree(fbc); - zend_vm_stack_free_call_frame(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); zend_throw_error(NULL, "Cannot call overloaded function for non-object"); HANDLE_EXCEPTION(); @@ -3919,7 +3902,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) object->handlers->call_method(fbc->common.function_name, object, call, EX_VAR(opline->result.var)); EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { zend_string_release(fbc->common.function_name); @@ -3931,30 +3914,15 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) } else { Z_VAR_FLAGS_P(EX_VAR(opline->result.var)) = 0; } - } -ZEND_VM_C_LABEL(fcall_end_change_scope): - if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) { - object = Z_OBJ(call->This); -#if 0 - if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) { - if (!(opline->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) { -#else - if (UNEXPECTED(EG(exception) != NULL) && (ZEND_CALL_INFO(call) & ZEND_CALL_CTOR)) { - if (!(ZEND_CALL_INFO(call) & ZEND_CALL_CTOR_RESULT_UNUSED)) { -#endif - GC_REFCOUNT(object)--; - } - if (GC_REFCOUNT(object) == 1) { - zend_object_store_ctor_failed(object); - } + cleanup_this_object_call(call, UNEXPECTED(EG(exception) != NULL)); + EG(scope) = EX(func)->op_array.scope; + + if (UNEXPECTED(extra_call_frame != 0)) { + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); } - OBJ_RELEASE(object); } - EG(scope) = EX(func)->op_array.scope; -ZEND_VM_C_LABEL(fcall_end): - zend_vm_stack_free_call_frame(call); if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL); if (RETURN_VALUE_USED(opline)) { @@ -3967,6 +3935,22 @@ ZEND_VM_C_LABEL(fcall_end): ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HANDLER(60, ZEND_DO_FCALL, TMP, ANY) +{ + USE_OPLINE + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op1.var); + zend_function *fbc = call->func; + + if (UNEXPECTED(zend_check_abstract_or_deprecated(fbc) == 1)) { + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + + SAVE_OPLINE(); + + ZEND_VM_DISPATCH_TO_HELPER(zend_do_fcall_helper, call, call, fbc, fbc, extra_call_frame, 0); +} + ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED) { USE_OPLINE @@ -4269,14 +4253,13 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV, JMP_ADDR) } } -ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, NUM) +ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, TMP, NUM) { USE_OPLINE - zval *value, *arg; + zval *value, *arg = EX_VAR(opline->result.var); zend_free_op free_op1; value = GET_OP1_ZVAL_PTR(BP_VAR_R); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); ZVAL_COPY_VALUE(arg, value); if (OP1_TYPE == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { @@ -4286,28 +4269,28 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, NUM) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(116, ZEND_SEND_VAL_EX, CONST|TMP, NUM) +ZEND_VM_HANDLER(116, ZEND_SEND_VAL_EX, CONST|TMP, TMP, NUM) { USE_OPLINE zval *value, *arg; zend_free_op free_op1; - uint32_t arg_num = opline->op2.num; + uint32_t arg_num = opline->extended_value; + zend_function *fbc = ((zend_execute_data *) EX_VAR(opline->op2.var))->func; if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) { - if (QUICK_ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (QUICK_ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) { ZEND_VM_C_GOTO(send_val_by_ref); } - } else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + } else if (ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) { ZEND_VM_C_LABEL(send_val_by_ref): SAVE_OPLINE(); zend_throw_error(NULL, "Cannot pass parameter %d by reference", arg_num); FREE_UNFETCHED_OP1(); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_UNDEF(arg); + ZVAL_UNDEF(EX_VAR(opline->result.var)); HANDLE_EXCEPTION(); } value = GET_OP1_ZVAL_PTR(BP_VAR_R); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); + arg = EX_VAR(opline->result.var); ZVAL_COPY_VALUE(arg, value); if (OP1_TYPE == IS_CONST) { if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { @@ -4317,7 +4300,7 @@ ZEND_VM_C_LABEL(send_val_by_ref): ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(117, ZEND_SEND_VAR, VAR|CV, NUM) +ZEND_VM_HANDLER(117, ZEND_SEND_VAR, VAR|CV, TMP, NUM) { USE_OPLINE zval *varptr, *arg; @@ -4327,13 +4310,11 @@ ZEND_VM_HANDLER(117, ZEND_SEND_VAR, VAR|CV, NUM) if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(varptr) == IS_UNDEF)) { SAVE_OPLINE(); GET_OP1_UNDEF_CV(varptr, BP_VAR_R); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_NULL(arg); + ZVAL_NULL(EX_VAR(opline->result.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - + arg = EX_VAR(opline->result.var); if (OP1_TYPE == IS_CV) { ZVAL_OPT_DEREF(varptr); ZVAL_COPY(arg, varptr); @@ -4356,14 +4337,14 @@ ZEND_VM_HANDLER(117, ZEND_SEND_VAR, VAR|CV, NUM) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR, NUM, SEND) +ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR, TMP, NUM) { USE_OPLINE zend_free_op free_op1; - zval *varptr, *arg; + zval *varptr; if (!(opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND)) { - if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { + if (!ARG_SHOULD_BE_SENT_BY_REF(((zend_execute_data *) EX_VAR(opline->op2.var))->func, opline->extended_value & ZEND_ARG_SEND_MASK)) { ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_VAR); } } @@ -4378,38 +4359,34 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR, NUM, SEND) } else { if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : - !ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { + !ARG_MAY_BE_SENT_BY_REF(((zend_execute_data *) EX_VAR(opline->op2.var))->func, opline->extended_value & ZEND_ARG_SEND_MASK)) { SAVE_OPLINE(); zend_error(E_NOTICE, "Only variables should be passed by reference"); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_COPY_VALUE(arg, varptr); + ZVAL_COPY_VALUE(EX_VAR(opline->result.var), varptr); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } } - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_COPY_VALUE(arg, varptr); + ZVAL_COPY_VALUE(EX_VAR(opline->result.var), varptr); ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, NUM) +ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, TMP, NUM) { USE_OPLINE zend_free_op free_op1; - zval *varptr, *arg; + zval *varptr, *arg = EX_VAR(opline->result.var); SAVE_OPLINE(); varptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); if (OP1_TYPE == IS_VAR && UNEXPECTED(varptr == NULL)) { zend_throw_error(NULL, "Only variables can be passed by reference"); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); ZVAL_UNDEF(arg); HANDLE_EXCEPTION(); } - arg = ZEND_CALL_VAR(EX(call), opline->result.var); if (OP1_TYPE == IS_VAR && UNEXPECTED(varptr == &EG(error_zval))) { ZVAL_NEW_REF(arg, &EG(uninitialized_zval)); ZEND_VM_NEXT_OPCODE(); @@ -4428,18 +4405,19 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, NUM) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(66, ZEND_SEND_VAR_EX, VAR|CV, NUM) +ZEND_VM_HANDLER(66, ZEND_SEND_VAR_EX, VAR|CV, TMP, NUM) { USE_OPLINE zval *varptr, *arg; zend_free_op free_op1; - uint32_t arg_num = opline->op2.num; + uint32_t arg_num = opline->extended_value; + zend_function *fbc = ((zend_execute_data *) EX_VAR(opline->op2.var))->func; if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) { - if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num)) { ZEND_VM_C_GOTO(send_var_by_ref); } - } else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + } else if (ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num)) { ZEND_VM_C_LABEL(send_var_by_ref): ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF); } @@ -4448,13 +4426,11 @@ ZEND_VM_C_LABEL(send_var_by_ref): if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(varptr) == IS_UNDEF)) { SAVE_OPLINE(); GET_OP1_UNDEF_CV(varptr, BP_VAR_R); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_NULL(arg); + ZVAL_NULL(EX_VAR(opline->result.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - + arg = EX_VAR(opline->result.var); if (OP1_TYPE == IS_CV) { ZVAL_OPT_DEREF(varptr); ZVAL_COPY(arg, varptr); @@ -4477,152 +4453,72 @@ ZEND_VM_C_LABEL(send_var_by_ref): ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(165, ZEND_SEND_UNPACK, ANY, ANY) +ZEND_VM_HANDLER(165, ZEND_SEND_UNPACK, CONST|TMP|VAR|CV, TMP, NUM) { USE_OPLINE zend_free_op free_op1; zval *args; - int arg_num; + int arg_num = opline->extended_value & ZEND_ARG_SEND_MASK; + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op2.var); + HashTable *ht; SAVE_OPLINE(); + if (UNEXPECTED(!(opline->extended_value & ZEND_ARG_IS_UNPACKED))) { + array_init(EX_VAR(opline->result.var)); + } + ht = Z_ARRVAL_P(EX_VAR(opline->result.var)); args = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); - arg_num = ZEND_CALL_NUM_ARGS(EX(call)) + 1; ZEND_VM_C_LABEL(send_again): if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { - HashTable *ht = Z_ARRVAL_P(args); - zval *arg, *top; zend_string *name; + zval *arg; + HashTable *arg_ht = Z_ARRVAL_P(args); + arg_num += zend_hash_num_elements(ht); + unpack_array_separate(args, &arg_ht, call, arg_num, OP1_TYPE); - zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, zend_hash_num_elements(ht)); - - if (OP1_TYPE != IS_CONST && OP1_TYPE != IS_TMP_VAR && Z_IMMUTABLE_P(args)) { - uint32_t i; - int separate = 0; - - /* check if any of arguments are going to be passed by reference */ - for (i = 0; i < zend_hash_num_elements(ht); i++) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num + i)) { - separate = 1; - break; - } - } - if (separate) { - zval_copy_ctor(args); - ht = Z_ARRVAL_P(args); - } - } - - ZEND_HASH_FOREACH_STR_KEY_VAL(ht, name, arg) { - if (name) { + ZEND_HASH_FOREACH_STR_KEY_VAL(arg_ht, name, arg) { + if (UNEXPECTED(name != NULL)) { zend_throw_error(NULL, "Cannot unpack array with string keys"); FREE_OP1(); HANDLE_EXCEPTION(); } - top = ZEND_CALL_ARG(EX(call), arg_num); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num++)) { if (!Z_IMMUTABLE_P(args)) { ZVAL_MAKE_REF(arg); Z_ADDREF_P(arg); - ZVAL_REF(top, Z_REF_P(arg)); + zend_hash_next_index_insert(ht, arg); } else { - ZVAL_DUP(top, arg); + zval copy; + ZVAL_DUP(©, arg); + zend_hash_next_index_insert(ht, ©); } - } else if (Z_ISREF_P(arg)) { - ZVAL_COPY(top, Z_REFVAL_P(arg)); } else { - ZVAL_COPY(top, arg); + /* don't separate references for __call */ + if (UNEXPECTED(Z_ISREF_P(arg)) && EXPECTED((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) == 0)) { + arg = Z_REFVAL_P(arg); + } + Z_TRY_ADDREF_P(arg); + zend_hash_next_index_insert(ht, arg); } - - ZEND_CALL_NUM_ARGS(EX(call))++; - arg_num++; } ZEND_HASH_FOREACH_END(); - } else if (EXPECTED(Z_TYPE_P(args) == IS_OBJECT)) { zend_class_entry *ce = Z_OBJCE_P(args); zend_object_iterator *iter; if (!ce || !ce->get_iterator) { - zend_error(E_WARNING, "Only arrays and Traversables can be unpacked"); + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, object%s%s given", opline->extended_value & ZEND_ARG_SEND_MASK, ce ? " of type " : "", ce ? ZSTR_VAL(ce->name) : ""); } else { - iter = ce->get_iterator(ce, args, 0); if (UNEXPECTED(!iter)) { FREE_OP1(); if (!EG(exception)) { - zend_throw_exception_ex( - NULL, 0, "Object of type %s did not create an Iterator", ZSTR_VAL(ce->name) - ); + zend_throw_exception_ex(NULL, 0, "Object of type %s unpacked at parameter %d did not create an Iterator", ZSTR_VAL(ce->name), opline->extended_value & ZEND_ARG_SEND_MASK); } HANDLE_EXCEPTION(); } - - if (iter->funcs->rewind) { - iter->funcs->rewind(iter); - if (UNEXPECTED(EG(exception) != NULL)) { - ZEND_VM_C_GOTO(unpack_iter_dtor); - } - } - - for (; iter->funcs->valid(iter) == SUCCESS; ++arg_num) { - zval *arg, *top; - - if (UNEXPECTED(EG(exception) != NULL)) { - ZEND_VM_C_GOTO(unpack_iter_dtor); - } - - arg = iter->funcs->get_current_data(iter); - if (UNEXPECTED(EG(exception) != NULL)) { - ZEND_VM_C_GOTO(unpack_iter_dtor); - } - - if (iter->funcs->get_current_key) { - zval key; - iter->funcs->get_current_key(iter, &key); - if (UNEXPECTED(EG(exception) != NULL)) { - ZEND_VM_C_GOTO(unpack_iter_dtor); - } - - if (Z_TYPE(key) == IS_STRING) { - zend_throw_error(NULL, - "Cannot unpack Traversable with string keys"); - zend_string_release(Z_STR(key)); - ZEND_VM_C_GOTO(unpack_iter_dtor); - } - - zval_dtor(&key); - } - - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { - zend_error( - E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" - " by unpacking a Traversable, passing by-value instead", arg_num, - EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", - EX(call)->func->common.scope ? "::" : "", - ZSTR_VAL(EX(call)->func->common.function_name) - ); - } - - if (Z_ISREF_P(arg)) { - ZVAL_DUP(arg, Z_REFVAL_P(arg)); - } else { - if (Z_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); - } - - zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1); - top = ZEND_CALL_ARG(EX(call), arg_num); - ZVAL_COPY_VALUE(top, arg); - ZEND_CALL_NUM_ARGS(EX(call))++; - - iter->funcs->move_forward(iter); - if (UNEXPECTED(EG(exception) != NULL)) { - ZEND_VM_C_GOTO(unpack_iter_dtor); - } - } - -ZEND_VM_C_LABEL(unpack_iter_dtor): - zend_iterator_dtor(iter); + unpack_iterator_to_array(iter, ht, call, arg_num + zend_hash_num_elements(ht)); } } else if (EXPECTED(Z_ISREF_P(args))) { args = Z_REFVAL_P(args); @@ -4631,145 +4527,230 @@ ZEND_VM_C_LABEL(unpack_iter_dtor): if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(args) == IS_UNDEF)) { GET_OP1_UNDEF_CV(args, BP_VAR_R); } - zend_error(E_WARNING, "Only arrays and Traversables can be unpacked"); + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, %s given", opline->extended_value & ZEND_ARG_SEND_MASK, zend_get_type_by_const(Z_TYPE_P(args))); } FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY) +ZEND_VM_HANDLER(41, ZEND_DO_UNPACK_FCALL, TMP, CONST|TMP|VAR|CV, NUM) { USE_OPLINE - zend_free_op free_op1; + + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op1.var); + zend_function *fbc = call->func; + uint32_t arg_num = opline->extended_value & ZEND_ARG_SEND_MASK; + uint32_t new_args; + HashTable *ht, local_ht; + + zend_free_op free_op2; zval *args; - SAVE_OPLINE(); SAVE_OPLINE(); - args = GET_OP1_ZVAL_PTR(BP_VAR_R); + args = GET_OP2_ZVAL_PTR(BP_VAR_R); - if (UNEXPECTED(Z_TYPE_P(args) != IS_ARRAY)) { - if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(args)) { - args = Z_REFVAL_P(args); - if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { - ZEND_VM_C_GOTO(send_array); +ZEND_VM_C_LABEL(send_again): + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { + ht = Z_ARRVAL_P(args); + } else if (EXPECTED(Z_TYPE_P(args) == IS_OBJECT)) { + zend_class_entry *ce = Z_OBJCE_P(args); + zend_object_iterator *iter; + + if (UNEXPECTED(!ce) || UNEXPECTED(!ce->get_iterator)) { + if (opline->extended_value & ZEND_ARG_IS_CUFA) { + zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array or Traversable, object%s%s given", ce ? " of type " : "", ce ? ZSTR_VAL(ce->name) : ""); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, object%s%s given", opline->extended_value & ZEND_ARG_SEND_MASK, ce ? " of type " : "", ce ? ZSTR_VAL(ce->name) : ""); } + FREE_OP2(); + if (UNEXPECTED(EG(exception) != NULL)) { + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + ZEND_VM_DISPATCH_TO_HANDLER(ZEND_DO_FCALL); } - zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array, %s given", zend_get_type_by_const(Z_TYPE_P(args))); - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); + + iter = ce->get_iterator(ce, args, 0); + if (UNEXPECTED(!iter)) { + FREE_OP2(); + if (!EG(exception)) { + zend_throw_exception_ex(NULL, 0, "Object of type %s unpacked at parameter %d did not create an Iterator", ZSTR_VAL(ce->name), opline->extended_value & ZEND_ARG_SEND_MASK); + } + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); } - if (Z_OBJ(EX(call)->This)) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); + + ht = &local_ht; + zend_hash_init(ht, 8, pHashFunction should be killed, ZVAL_PTR_DTOR, 0); + + unpack_iterator_to_array(iter, ht, call, arg_num); + + FREE_OP2(); + if (UNEXPECTED(EG(exception) != NULL)) { + zend_hash_destroy(ht); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); } - EX(call)->func = (zend_function*)&zend_pass_function; - EX(call)->called_scope = NULL; - Z_OBJ(EX(call)->This) = NULL; } else { - uint32_t arg_num; - HashTable *ht; - zval *arg, *param; + if ((OP2_TYPE & (IS_VAR|IS_CV)) && EXPECTED(Z_ISREF_P(args))) { + args = Z_REFVAL_P(args); + ZEND_VM_C_GOTO(send_again); + } + if (opline->extended_value & ZEND_ARG_IS_CUFA) { + zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array or Traversable, %s given", zend_get_type_by_const(Z_TYPE_P(args))); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, %s given", opline->extended_value & ZEND_ARG_SEND_MASK, zend_get_type_by_const(Z_TYPE_P(args))); + } + FREE_OP2(); + if (EG(exception)) { + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + ZEND_VM_DISPATCH_TO_HANDLER(ZEND_DO_FCALL); + } -ZEND_VM_C_LABEL(send_array): - ht = Z_ARRVAL_P(args); - zend_vm_stack_extend_call_frame(&EX(call), 0, zend_hash_num_elements(ht)); + if (UNEXPECTED(zend_check_abstract_or_deprecated(fbc) == 1)) { + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY) && (OP2_TYPE != IS_TMP_VAR || EXPECTED((opline->extended_value & ZEND_ARG_IS_UNPACKED) == 0))) { + FREE_OP2(); + } else { + zend_hash_destroy(ht); + if (opline->extended_value & ZEND_ARG_IS_UNPACKED) { + efree(ht); + } + } + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } - if (OP1_TYPE != IS_CONST && OP1_TYPE != IS_TMP_VAR && Z_IMMUTABLE_P(args)) { - int separate = 0; + LOAD_OPLINE(); - /* check if any of arguments are going to be passed by reference */ - for (arg_num = 0; arg_num < zend_hash_num_elements(ht); arg_num++) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num + 1)) { - separate = 1; - break; - } - } - if (separate) { - zval_copy_ctor(args); - ht = Z_ARRVAL_P(args); - } + new_args = zend_hash_num_elements(ht); + + if (fbc->type == ZEND_USER_FUNCTION) { + if (UNEXPECTED(((zval *)(((void *) call) + zend_vm_calc_used_stack(0, fbc))) >= EG(vm_stack_end))) { + call = zend_vm_stack_copy_call_frame(call, ZEND_CALL_NUM_ARGS(call), new_args); + } else if (new_args > ZEND_RESERVED_RECV_SLOTS || ZEND_CALL_NUM_ARGS(call) + ZEND_RESERVED_RECV_SLOTS < fbc->op_array.num_args) { + call = zend_vm_stack_extend_call_frame(call, ZEND_CALL_NUM_ARGS(call), new_args); } + } else if (new_args > ZEND_RESERVED_RECV_SLOTS) { + call = zend_vm_stack_extend_call_frame(call, ZEND_CALL_NUM_ARGS(call), new_args); + } - arg_num = 1; - param = ZEND_CALL_ARG(EX(call), 1); - ZEND_HASH_FOREACH_VAL(ht, arg) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { - if (UNEXPECTED(!Z_ISREF_P(arg))) { - if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + ZEND_CALL_NUM_ARGS(call) = arg_num + new_args - 1; - zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", - arg_num, - EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", - EX(call)->func->common.scope ? "::" : "", - ZSTR_VAL(EX(call)->func->common.function_name)); + /* if no previous unpack: optimization to not always duplicate the array, only for more than 1 unpack (or iterators) */ + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY) && (OP2_TYPE != IS_TMP_VAR || EXPECTED((opline->extended_value & ZEND_ARG_IS_UNPACKED) == 0))) { + zend_string *name; + zval *arg; - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); - } - if (Z_OBJ(EX(call)->This)) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); - } - EX(call)->func = (zend_function*)&zend_pass_function; - EX(call)->called_scope = NULL; - Z_OBJ(EX(call)->This) = NULL; + zend_bool cufa = (opline->extended_value & ZEND_ARG_IS_CUFA) != 0; - break; - } + unpack_array_separate(args, &ht, call, arg_num, OP2_TYPE); - ZVAL_NEW_REF(arg, arg); + ZEND_HASH_FOREACH_STR_KEY_VAL(ht, name, arg) { + if (UNEXPECTED(name != NULL)) { + zend_throw_error(NULL, "Cannot unpack array with string keys"); + FREE_OP2(); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + HANDLE_EXCEPTION(); + } + if (UNEXPECTED(ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num))) { + if (cufa && !Z_ISREF_P(arg)) { + if (UNEXPECTED(!ARG_MAY_BE_SENT_BY_REF(call->func, arg_num))) { + zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", + arg_num, + call->func->common.scope ? ZSTR_VAL(call->func->common.scope->name) : "", + call->func->common.scope ? "::" : "", + ZSTR_VAL(call->func->common.function_name) + ); + FREE_OP2(); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + } else if (EXPECTED(!Z_IMMUTABLE_P(args))) { + ZVAL_MAKE_REF(arg); + Z_ADDREF_P(arg); + ZVAL_COPY_VALUE(ZEND_CALL_ARG(call, arg_num++), arg); + continue; } - Z_ADDREF_P(arg); - } else{ - if (Z_ISREF_P(arg) && - !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { - /* don't separate references for __call */ + + ZVAL_DUP(ZEND_CALL_ARG(call, arg_num++), arg); + } else { + /* don't separate references for __call */ + if (UNEXPECTED(Z_ISREF_P(arg)) && EXPECTED((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) == 0)) { arg = Z_REFVAL_P(arg); } - if (Z_OPT_REFCOUNTED_P(arg)) { - Z_ADDREF_P(arg); - } + Z_TRY_ADDREF_P(arg); + ZVAL_COPY_VALUE(ZEND_CALL_ARG(call, arg_num++), arg); } - ZVAL_COPY_VALUE(param, arg); - ZEND_CALL_NUM_ARGS(EX(call))++; - arg_num++; - param++; } ZEND_HASH_FOREACH_END(); + + FREE_OP2(); + } else { + ZEND_HASH_FOREACH_VAL(ht, args) { + zval *top = ZEND_CALL_ARG(call, arg_num++); + ZVAL_COPY_VALUE(top, args); + } ZEND_HASH_FOREACH_END(); + + ZEND_ASSERT(GC_REFCOUNT(ht) == 1); + ht->pDestructor = NULL; // do not free the zvals... + zend_hash_destroy(ht); // just free the array memory + if (opline->extended_value & ZEND_ARG_IS_UNPACKED) { + efree(ht); + } } - FREE_OP1(); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + + ZEND_VM_DISPATCH_TO_HELPER(zend_do_fcall_helper, call, call, fbc, fbc, extra_call_frame, 1); } -ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, NUM) +ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, TMP, NUM) { USE_OPLINE - zval *arg, *param; + zval *arg, *param = EX_VAR(opline->result.var); + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op2.var); zend_free_op free_op1; SAVE_OPLINE(); arg = GET_OP1_ZVAL_PTR(BP_VAR_R); - param = ZEND_CALL_VAR(EX(call), opline->result.var); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { + if (ARG_SHOULD_BE_SENT_BY_REF(call->func, opline->extended_value)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { - - if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { - + if (!ARG_MAY_BE_SENT_BY_REF(call->func, opline->extended_value)) { zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", - opline->op2.num, - EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", - EX(call)->func->common.scope ? "::" : "", - ZSTR_VAL(EX(call)->func->common.function_name)); + opline->extended_value, + call->func->common.scope ? ZSTR_VAL(call->func->common.scope->name) : "", + call->func->common.scope ? "::" : "", + ZSTR_VAL(call->func->common.function_name)); - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); + if (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE) { + OBJ_RELEASE((zend_object *) call->func->common.prototype); } - if (Z_OBJ(EX(call)->This)) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); + if (Z_OBJ(call->This)) { + OBJ_RELEASE(Z_OBJ(call->This)); } ZVAL_UNDEF(param); - EX(call)->func = (zend_function*)&zend_pass_function; - EX(call)->called_scope = NULL; - Z_OBJ(EX(call)->This) = NULL; + call->func = (zend_function*)&zend_pass_function; + call->called_scope = NULL; + Z_OBJ(call->This) = NULL; FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -4780,7 +4761,7 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, NUM) Z_ADDREF_P(arg); } else { if (Z_ISREF_P(arg) && - !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + !(call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { /* don't separate references for __call */ arg = Z_REFVAL_P(arg); } @@ -4871,19 +4852,19 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, NUM, ANY) array_init_size(params, arg_count - arg_num + 1); zend_hash_real_init(Z_ARRVAL_P(params), 1); ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(params)) { - param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); + param = ZEND_CALL_ARG(execute_data, arg_num); if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { do { zend_verify_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)); if (Z_OPT_REFCOUNTED_P(param)) Z_ADDREF_P(param); ZEND_HASH_FILL_ADD(param); - param++; + param--; } while (++arg_num <= arg_count); } else { do { if (Z_OPT_REFCOUNTED_P(param)) Z_ADDREF_P(param); ZEND_HASH_FILL_ADD(param); - param++; + param--; } while (++arg_num <= arg_count); } } ZEND_HASH_FILL_END(); @@ -5025,15 +5006,12 @@ ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, JMP_ADDR, NUM) ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } else { /* We are not handling overloaded classes right now */ - zend_execute_data *call = zend_vm_stack_push_call_frame( - ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR | - (EXPECTED(RETURN_VALUE_USED(opline)) ? 0 : ZEND_CALL_CTOR_RESULT_UNUSED), + zend_init_call_frame((zend_execute_data *) EX_VAR((OP_JMP_ADDR(opline, opline->op2) - 1)->op1.var), /* maybe find a better way to access this, but we only have 3 uint32_t's for each opcode ... */ + ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR | (EXPECTED(RETURN_VALUE_USED(opline)) ? 0 : ZEND_CALL_CTOR_RESULT_UNUSED), constructor, opline->extended_value, ce, Z_OBJ(object_zval)); - call->prev_execute_data = EX(call); - EX(call) = call; if (EXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), &object_zval); @@ -5477,22 +5455,22 @@ ZEND_VM_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY, EVAL) +ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, TMP, CONST|TMPVAR|CV, EVAL) { USE_OPLINE zend_op_array *new_op_array=NULL; - zend_free_op free_op1; + zend_free_op free_op2; zval *inc_filename; zval tmp_inc_filename; zend_bool failure_retval=0; SAVE_OPLINE(); - inc_filename = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + inc_filename = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); ZVAL_UNDEF(&tmp_inc_filename); if (Z_TYPE_P(inc_filename) != IS_STRING) { if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(inc_filename) == IS_UNDEF)) { - inc_filename = GET_OP1_UNDEF_CV(inc_filename, BP_VAR_R); + inc_filename = GET_OP2_UNDEF_CV(inc_filename, BP_VAR_R); } ZVAL_STR(&tmp_inc_filename, zval_get_string(inc_filename)); inc_filename = &tmp_inc_filename; @@ -5560,12 +5538,13 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY, EVAL) if (Z_TYPE(tmp_inc_filename) != IS_UNDEF) { zend_string_release(Z_STR(tmp_inc_filename)); } - FREE_OP1(); + FREE_OP2(); if (UNEXPECTED(EG(exception) != NULL)) { HANDLE_EXCEPTION(); } else if (EXPECTED(new_op_array != NULL)) { zval *return_value = NULL; - zend_execute_data *call; + zend_execute_data *call = zend_push_call_frame((zend_execute_data *) EX_VAR(opline->op1.var), ZEND_CALL_NESTED_CODE, + (zend_function *) new_op_array, 0, EX(called_scope), Z_OBJ(EX(This))); if (RETURN_VALUE_USED(opline)) { return_value = EX_VAR(opline->result.var); @@ -5573,9 +5552,6 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY, EVAL) new_op_array->scope = EG(scope); - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_CODE, - (zend_function*)new_op_array, 0, EX(called_scope), Z_OBJ(EX(This))); - if (EX(symbol_table)) { call->symbol_table = EX(symbol_table); } else { @@ -5589,7 +5565,7 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY, EVAL) } else { ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); zend_execute_ex(call); - zend_vm_stack_free_call_frame(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); } destroy_op_array(new_op_array); @@ -7310,8 +7286,6 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } } - cleanup_unfinished_calls(execute_data, op_num); - if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) { zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var); @@ -8028,13 +8002,13 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY) zend_hash_init(args, num_args, NULL, ZVAL_PTR_DTOR, 0); if (num_args) { zval *p = ZEND_CALL_ARG(execute_data, 1); - zval *end = p + num_args; + zval *end = p - num_args; zend_hash_real_init(args, 1); ZEND_HASH_FILL_PACKED(args) { do { ZEND_HASH_FILL_ADD(p); - p++; + p--; } while (p != end); } ZEND_HASH_FILL_END(); } @@ -8042,8 +8016,8 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY) SAVE_OPLINE(); call = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); - zend_vm_stack_free_call_frame(call); - call = zend_vm_stack_push_call_frame(call_info, fbc->common.prototype, 2, scope, object); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + call = zend_push_top_call_frame(call_info, fbc->common.prototype, 2, scope, object); call->prev_execute_data = execute_data; ZVAL_STR(ZEND_CALL_ARG(call, 1), fbc->common.function_name); @@ -8082,14 +8056,14 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY) for (i = 0; i < num_args; ++i) { if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) { EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); - zend_vm_stack_free_call_frame(call); + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); if (ret) { ZVAL_UNDEF(ret); } ZEND_VM_C_GOTO(call_trampoline_end); } - p++; + p--; } } @@ -8115,7 +8089,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY) EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); if (ret == &retval) { zval_ptr_dtor(ret); @@ -8136,7 +8110,7 @@ ZEND_VM_C_LABEL(call_trampoline_end): OBJ_RELEASE(object); } EG(scope) = EX(func)->op_array.scope; - zend_vm_stack_free_call_frame(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 71438dd01d4e7..b4d500e8a0b97 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -446,7 +446,7 @@ ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value) return; } - execute_data = zend_vm_stack_push_call_frame(ZEND_CALL_TOP_CODE, + execute_data = zend_push_top_call_frame(ZEND_CALL_TOP_CODE, (zend_function*)op_array, 0, zend_get_called_scope(EG(current_execute_data)), zend_get_this_object(EG(current_execute_data))); if (EG(current_execute_data)) { execute_data->symbol_table = zend_rebuild_symbol_table(); @@ -456,7 +456,7 @@ ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value) EX(prev_execute_data) = EG(current_execute_data); i_init_execute_data(execute_data, op_array, return_value); zend_execute_ex(execute_data); - zend_vm_stack_free_call_frame(execute_data); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(execute_data)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) @@ -471,7 +471,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_ if (UNEXPECTED(EX(symbol_table) != NULL)) { zend_clean_and_cache_symbol_table(EX(symbol_table)); } - zend_vm_stack_free_extra_args_ex(call_info, execute_data); + zend_free_args_user(execute_data); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { @@ -496,7 +496,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_ } EG(scope) = EX(func)->op_array.scope; - zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); + zend_vm_stack_free_call_frame(call_info); if (UNEXPECTED(EG(exception) != NULL)) { const zend_op *old_opline = EX(opline); @@ -516,7 +516,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_ efree_size(EX(func), sizeof(zend_op_array)); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); - zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); + zend_vm_stack_free_call_frame(call_info); zend_attach_symbol_table(execute_data); if (UNEXPECTED(EG(exception) != NULL)) { @@ -532,7 +532,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_ if (UNEXPECTED(EX(symbol_table) != NULL)) { zend_clean_and_cache_symbol_table(EX(symbol_table)); } - zend_vm_stack_free_extra_args_ex(call_info, execute_data); + zend_free_args_user(execute_data); EG(current_execute_data) = EX(prev_execute_data); if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype); @@ -566,637 +566,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_H ZEND_VM_CONTINUE(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_execute_data *call = EX(call); - zend_function *fbc = call->func; - zval *ret; - - SAVE_OPLINE(); - EX(call) = call->prev_execute_data; - - call->prev_execute_data = execute_data; - EG(current_execute_data) = call; - - ret = EX_VAR(opline->result.var); - ZVAL_NULL(ret); - Z_VAR_FLAGS_P(ret) = 0; - - fbc->internal_function.handler(call, ret); - -#if ZEND_DEBUG - ZEND_ASSERT( - !call->func || - !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || - zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var))); -#endif - - EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); - zend_vm_stack_free_call_frame(call); - - if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(EX_VAR(opline->result.var)); - } - - if (UNEXPECTED(EG(exception) != NULL)) { - zend_throw_exception_internal(NULL); - if (RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(EX_VAR(opline->result.var)); - } - HANDLE_EXCEPTION(); - } - - ZEND_VM_INTERRUPT_CHECK(); - ZEND_VM_NEXT_OPCODE(); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_execute_data *call = EX(call); - zend_function *fbc = call->func; - zval *ret; - - SAVE_OPLINE(); - EX(call) = call->prev_execute_data; - - EG(scope) = NULL; - ret = NULL; - call->symbol_table = NULL; - if (RETURN_VALUE_USED(opline)) { - ret = EX_VAR(opline->result.var); - ZVAL_NULL(ret); - Z_VAR_FLAGS_P(ret) = 0; - } - - call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret, 0); - - ZEND_VM_ENTER(); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_execute_data *call = EX(call); - zend_function *fbc = call->func; - zval *ret; - - SAVE_OPLINE(); - EX(call) = call->prev_execute_data; - - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { - EG(scope) = NULL; - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) { - if (EXPECTED(RETURN_VALUE_USED(opline))) { - ret = EX_VAR(opline->result.var); - zend_generator_create_zval(call, &fbc->op_array, ret); - Z_VAR_FLAGS_P(ret) = 0; - } else { - zend_vm_stack_free_args(call); - } - - zend_vm_stack_free_call_frame(call); - } else { - ret = NULL; - call->symbol_table = NULL; - if (RETURN_VALUE_USED(opline)) { - ret = EX_VAR(opline->result.var); - ZVAL_NULL(ret); - Z_VAR_FLAGS_P(ret) = 0; - } - - call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret, 0); - - ZEND_VM_ENTER(); - } - EG(scope) = EX(func)->op_array.scope; - } else { - ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); - - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { - zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", - fbc->common.scope ? ZSTR_VAL(fbc->common.scope->name) : "", - fbc->common.scope ? "::" : "", - ZSTR_VAL(fbc->common.function_name)); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); - } - } - - call->prev_execute_data = execute_data; - EG(current_execute_data) = call; - - if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { - uint32_t i; - uint32_t num_args = ZEND_CALL_NUM_ARGS(call); - zval *p = ZEND_CALL_ARG(call, 1); - - for (i = 0; i < num_args; ++i) { - if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) { - EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); - zend_vm_stack_free_call_frame(call); - zend_throw_exception_internal(NULL); - HANDLE_EXCEPTION(); - } - p++; - } - } - - ret = EX_VAR(opline->result.var); - ZVAL_NULL(ret); - Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; - - fbc->internal_function.handler(call, ret); - -#if ZEND_DEBUG - ZEND_ASSERT( - !call->func || - !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || - zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var))); -#endif - - EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); - zend_vm_stack_free_call_frame(call); - - if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(EX_VAR(opline->result.var)); - } - } - - if (UNEXPECTED(EG(exception) != NULL)) { - zend_throw_exception_internal(NULL); - if (RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(EX_VAR(opline->result.var)); - } - HANDLE_EXCEPTION(); - } - ZEND_VM_INTERRUPT_CHECK(); - ZEND_VM_NEXT_OPCODE(); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_execute_data *call = EX(call); - zend_function *fbc = call->func; - zend_object *object; - zval *ret; - - SAVE_OPLINE(); - EX(call) = call->prev_execute_data; - if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { - zend_throw_error(NULL, "Cannot call abstract method %s::%s()", ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name)); - HANDLE_EXCEPTION(); - } - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { - zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", - fbc->common.scope ? ZSTR_VAL(fbc->common.scope->name) : "", - fbc->common.scope ? "::" : "", - ZSTR_VAL(fbc->common.function_name)); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); - } - } - } - - LOAD_OPLINE(); - - if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { - EG(scope) = fbc->common.scope; - if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) { - if (EXPECTED(RETURN_VALUE_USED(opline))) { - ret = EX_VAR(opline->result.var); - zend_generator_create_zval(call, &fbc->op_array, ret); - Z_VAR_FLAGS_P(ret) = 0; - } else { - if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) { - OBJ_RELEASE((zend_object*)fbc->op_array.prototype); - } - zend_vm_stack_free_args(call); - } - } else { - ret = NULL; - call->symbol_table = NULL; - if (RETURN_VALUE_USED(opline)) { - ret = EX_VAR(opline->result.var); - ZVAL_NULL(ret); - Z_VAR_FLAGS_P(ret) = 0; - } - - call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret, 1); - - if (EXPECTED(zend_execute_ex == execute_ex)) { - ZEND_VM_ENTER(); - } else { - ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); - zend_execute_ex(call); - } - } - } else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) { - int should_change_scope = 0; - - if (fbc->common.scope) { - should_change_scope = 1; - EG(scope) = fbc->common.scope; - } - - call->prev_execute_data = execute_data; - EG(current_execute_data) = call; - - if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { - uint32_t i; - uint32_t num_args = ZEND_CALL_NUM_ARGS(call); - zval *p = ZEND_CALL_ARG(call, 1); - - for (i = 0; i < num_args; ++i) { - if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) { - EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); - if (RETURN_VALUE_USED(opline)) { - ZVAL_UNDEF(EX_VAR(opline->result.var)); - } - if (UNEXPECTED(should_change_scope)) { - goto fcall_end_change_scope; - } else { - goto fcall_end; - } - } - p++; - } - } - - ret = EX_VAR(opline->result.var); - ZVAL_NULL(ret); - Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; - - if (!zend_execute_internal) { - /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(call, ret); - } else { - zend_execute_internal(call, ret); - } - -#if ZEND_DEBUG - ZEND_ASSERT( - !call->func || - !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || - zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var))); -#endif - - EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); - - if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(EX_VAR(opline->result.var)); - } - - if (UNEXPECTED(should_change_scope)) { - goto fcall_end_change_scope; - } else { - goto fcall_end; - } - } else { /* ZEND_OVERLOADED_FUNCTION */ - /* Not sure what should be done here if it's a static method */ - object = Z_OBJ(call->This); - if (UNEXPECTED(object == NULL)) { - zend_vm_stack_free_args(call); - if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { - zend_string_release(fbc->common.function_name); - } - efree(fbc); - zend_vm_stack_free_call_frame(call); - - zend_throw_error(NULL, "Cannot call overloaded function for non-object"); - HANDLE_EXCEPTION(); - } - - EG(scope) = fbc->common.scope; - - ZVAL_NULL(EX_VAR(opline->result.var)); - - call->prev_execute_data = execute_data; - EG(current_execute_data) = call; - object->handlers->call_method(fbc->common.function_name, object, call, EX_VAR(opline->result.var)); - EG(current_execute_data) = call->prev_execute_data; - - zend_vm_stack_free_args(call); - - if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { - zend_string_release(fbc->common.function_name); - } - efree(fbc); - - if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(EX_VAR(opline->result.var)); - } else { - Z_VAR_FLAGS_P(EX_VAR(opline->result.var)) = 0; - } - } - -fcall_end_change_scope: - if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) { - object = Z_OBJ(call->This); -#if 0 - if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) { - if (!(opline->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) { -#else - if (UNEXPECTED(EG(exception) != NULL) && (ZEND_CALL_INFO(call) & ZEND_CALL_CTOR)) { - if (!(ZEND_CALL_INFO(call) & ZEND_CALL_CTOR_RESULT_UNUSED)) { -#endif - GC_REFCOUNT(object)--; - } - if (GC_REFCOUNT(object) == 1) { - zend_object_store_ctor_failed(object); - } - } - OBJ_RELEASE(object); - } - EG(scope) = EX(func)->op_array.scope; - -fcall_end: - zend_vm_stack_free_call_frame(call); - if (UNEXPECTED(EG(exception) != NULL)) { - zend_throw_exception_internal(NULL); - if (RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(EX_VAR(opline->result.var)); - } - HANDLE_EXCEPTION(); - } - - ZEND_VM_INTERRUPT_CHECK(); - ZEND_VM_NEXT_OPCODE(); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_free_op free_op1; - zval *args; - int arg_num; - - SAVE_OPLINE(); - args = get_zval_ptr_undef(opline->op1_type, opline->op1, execute_data, &free_op1, BP_VAR_R); - arg_num = ZEND_CALL_NUM_ARGS(EX(call)) + 1; - -send_again: - if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { - HashTable *ht = Z_ARRVAL_P(args); - zval *arg, *top; - zend_string *name; - - zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, zend_hash_num_elements(ht)); - - if (opline->op1_type != IS_CONST && opline->op1_type != IS_TMP_VAR && Z_IMMUTABLE_P(args)) { - uint32_t i; - int separate = 0; - - /* check if any of arguments are going to be passed by reference */ - for (i = 0; i < zend_hash_num_elements(ht); i++) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num + i)) { - separate = 1; - break; - } - } - if (separate) { - zval_copy_ctor(args); - ht = Z_ARRVAL_P(args); - } - } - - ZEND_HASH_FOREACH_STR_KEY_VAL(ht, name, arg) { - if (name) { - zend_throw_error(NULL, "Cannot unpack array with string keys"); - FREE_OP(free_op1); - HANDLE_EXCEPTION(); - } - - top = ZEND_CALL_ARG(EX(call), arg_num); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { - if (!Z_IMMUTABLE_P(args)) { - ZVAL_MAKE_REF(arg); - Z_ADDREF_P(arg); - ZVAL_REF(top, Z_REF_P(arg)); - } else { - ZVAL_DUP(top, arg); - } - } else if (Z_ISREF_P(arg)) { - ZVAL_COPY(top, Z_REFVAL_P(arg)); - } else { - ZVAL_COPY(top, arg); - } - - ZEND_CALL_NUM_ARGS(EX(call))++; - arg_num++; - } ZEND_HASH_FOREACH_END(); - - } else if (EXPECTED(Z_TYPE_P(args) == IS_OBJECT)) { - zend_class_entry *ce = Z_OBJCE_P(args); - zend_object_iterator *iter; - - if (!ce || !ce->get_iterator) { - zend_error(E_WARNING, "Only arrays and Traversables can be unpacked"); - } else { - - iter = ce->get_iterator(ce, args, 0); - if (UNEXPECTED(!iter)) { - FREE_OP(free_op1); - if (!EG(exception)) { - zend_throw_exception_ex( - NULL, 0, "Object of type %s did not create an Iterator", ZSTR_VAL(ce->name) - ); - } - HANDLE_EXCEPTION(); - } - - if (iter->funcs->rewind) { - iter->funcs->rewind(iter); - if (UNEXPECTED(EG(exception) != NULL)) { - goto unpack_iter_dtor; - } - } - - for (; iter->funcs->valid(iter) == SUCCESS; ++arg_num) { - zval *arg, *top; - - if (UNEXPECTED(EG(exception) != NULL)) { - goto unpack_iter_dtor; - } - - arg = iter->funcs->get_current_data(iter); - if (UNEXPECTED(EG(exception) != NULL)) { - goto unpack_iter_dtor; - } - - if (iter->funcs->get_current_key) { - zval key; - iter->funcs->get_current_key(iter, &key); - if (UNEXPECTED(EG(exception) != NULL)) { - goto unpack_iter_dtor; - } - - if (Z_TYPE(key) == IS_STRING) { - zend_throw_error(NULL, - "Cannot unpack Traversable with string keys"); - zend_string_release(Z_STR(key)); - goto unpack_iter_dtor; - } - - zval_dtor(&key); - } - - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { - zend_error( - E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()" - " by unpacking a Traversable, passing by-value instead", arg_num, - EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", - EX(call)->func->common.scope ? "::" : "", - ZSTR_VAL(EX(call)->func->common.function_name) - ); - } - - if (Z_ISREF_P(arg)) { - ZVAL_DUP(arg, Z_REFVAL_P(arg)); - } else { - if (Z_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); - } - - zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1); - top = ZEND_CALL_ARG(EX(call), arg_num); - ZVAL_COPY_VALUE(top, arg); - ZEND_CALL_NUM_ARGS(EX(call))++; - - iter->funcs->move_forward(iter); - if (UNEXPECTED(EG(exception) != NULL)) { - goto unpack_iter_dtor; - } - } - -unpack_iter_dtor: - zend_iterator_dtor(iter); - } - } else if (EXPECTED(Z_ISREF_P(args))) { - args = Z_REFVAL_P(args); - goto send_again; - } else { - if (opline->op1_type == IS_CV && UNEXPECTED(Z_TYPE_P(args) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(args, BP_VAR_R); - } - zend_error(E_WARNING, "Only arrays and Traversables can be unpacked"); - } - - FREE_OP(free_op1); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_free_op free_op1; - zval *args; - SAVE_OPLINE(); - - SAVE_OPLINE(); - args = get_zval_ptr(opline->op1_type, opline->op1, execute_data, &free_op1, BP_VAR_R); - - if (UNEXPECTED(Z_TYPE_P(args) != IS_ARRAY)) { - if ((opline->op1_type & (IS_VAR|IS_CV)) && Z_ISREF_P(args)) { - args = Z_REFVAL_P(args); - if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { - goto send_array; - } - } - zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array, %s given", zend_get_type_by_const(Z_TYPE_P(args))); - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); - } - if (Z_OBJ(EX(call)->This)) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); - } - EX(call)->func = (zend_function*)&zend_pass_function; - EX(call)->called_scope = NULL; - Z_OBJ(EX(call)->This) = NULL; - } else { - uint32_t arg_num; - HashTable *ht; - zval *arg, *param; - -send_array: - ht = Z_ARRVAL_P(args); - zend_vm_stack_extend_call_frame(&EX(call), 0, zend_hash_num_elements(ht)); - - if (opline->op1_type != IS_CONST && opline->op1_type != IS_TMP_VAR && Z_IMMUTABLE_P(args)) { - int separate = 0; - - /* check if any of arguments are going to be passed by reference */ - for (arg_num = 0; arg_num < zend_hash_num_elements(ht); arg_num++) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num + 1)) { - separate = 1; - break; - } - } - if (separate) { - zval_copy_ctor(args); - ht = Z_ARRVAL_P(args); - } - } - - arg_num = 1; - param = ZEND_CALL_ARG(EX(call), 1); - ZEND_HASH_FOREACH_VAL(ht, arg) { - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { - if (UNEXPECTED(!Z_ISREF_P(arg))) { - if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { - - zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", - arg_num, - EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", - EX(call)->func->common.scope ? "::" : "", - ZSTR_VAL(EX(call)->func->common.function_name)); - - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); - } - if (Z_OBJ(EX(call)->This)) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); - } - EX(call)->func = (zend_function*)&zend_pass_function; - EX(call)->called_scope = NULL; - Z_OBJ(EX(call)->This) = NULL; - - break; - } - - ZVAL_NEW_REF(arg, arg); - } - Z_ADDREF_P(arg); - } else{ - if (Z_ISREF_P(arg) && - !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { - /* don't separate references for __call */ - arg = Z_REFVAL_P(arg); - } - if (Z_OPT_REFCOUNTED_P(arg)) { - Z_ADDREF_P(arg); - } - } - ZVAL_COPY_VALUE(param, arg); - ZEND_CALL_NUM_ARGS(EX(call))++; - arg_num++; - param++; - } ZEND_HASH_FOREACH_END(); - } - FREE_OP(free_op1); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -1235,19 +604,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEN array_init_size(params, arg_count - arg_num + 1); zend_hash_real_init(Z_ARRVAL_P(params), 1); ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(params)) { - param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); + param = ZEND_CALL_ARG(execute_data, arg_num); if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { do { zend_verify_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)); if (Z_OPT_REFCOUNTED_P(param)) Z_ADDREF_P(param); ZEND_HASH_FILL_ADD(param); - param++; + param--; } while (++arg_num <= arg_count); } else { do { if (Z_OPT_REFCOUNTED_P(param)) Z_ADDREF_P(param); ZEND_HASH_FILL_ADD(param); - param++; + param--; } while (++arg_num <= arg_count); } } ZEND_HASH_FILL_END(); @@ -1514,8 +883,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER( } } - cleanup_unfinished_calls(execute_data, op_num); - if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) { zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[finally_op_end].op1.var); @@ -1735,13 +1102,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z zend_hash_init(args, num_args, NULL, ZVAL_PTR_DTOR, 0); if (num_args) { zval *p = ZEND_CALL_ARG(execute_data, 1); - zval *end = p + num_args; + zval *end = p - num_args; zend_hash_real_init(args, 1); ZEND_HASH_FILL_PACKED(args) { do { ZEND_HASH_FILL_ADD(p); - p++; + p--; } while (p != end); } ZEND_HASH_FILL_END(); } @@ -1749,8 +1116,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z SAVE_OPLINE(); call = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); - zend_vm_stack_free_call_frame(call); - call = zend_vm_stack_push_call_frame(call_info, fbc->common.prototype, 2, scope, object); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + call = zend_push_top_call_frame(call_info, fbc->common.prototype, 2, scope, object); call->prev_execute_data = execute_data; ZVAL_STR(ZEND_CALL_ARG(call, 1), fbc->common.function_name); @@ -1789,14 +1156,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z for (i = 0; i < num_args; ++i) { if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) { EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); - zend_vm_stack_free_call_frame(call); + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); if (ret) { ZVAL_UNDEF(ret); } goto call_trampoline_end; } - p++; + p--; } } @@ -1822,7 +1189,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z EG(current_execute_data) = call->prev_execute_data; - zend_vm_stack_free_args(call); + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); if (ret == &retval) { zval_ptr_dtor(ret); @@ -1843,7 +1210,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z OBJ_RELEASE(object); } EG(scope) = EX(func)->op_array.scope; - zend_vm_stack_free_call_frame(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL); @@ -1904,7 +1271,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_ USE_OPLINE zend_function *fbc; zval *function_name, *func; - zend_execute_data *call; fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))); if (UNEXPECTED(fbc == NULL)) { @@ -1918,10 +1284,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_ fbc = Z_FUNC_P(func); CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc); } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL, NULL); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE(); } @@ -1935,7 +1299,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CONST_H zend_class_entry *called_scope; zend_object *object; - zend_execute_data *call; uint32_t call_info = ZEND_CALL_NESTED_FUNCTION; SAVE_OPLINE(); @@ -2131,10 +1494,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CONST_H HANDLE_EXCEPTION(); } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -2145,7 +1506,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CON zval *func_name; zval *func; zend_function *fbc; - zend_execute_data *call; func_name = EX_CONSTANT(opline->op2) + 1; fbc = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2))); @@ -2164,10 +1524,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CON CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op2)), fbc); } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL, NULL); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE(); } @@ -2179,7 +1537,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_FCALL_SPEC_CONST_HANDLER( zval *fname = EX_CONSTANT(opline->op2); zval *func; zend_function *fbc; - zend_execute_data *call; fbc = CACHED_PTR(Z_CACHE_SLOT_P(fname)); if (UNEXPECTED(fbc == NULL)) { @@ -2193,11 +1550,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_FCALL_SPEC_CONST_HANDLER( CACHE_PTR(Z_CACHE_SLOT_P(fname), fbc); } - call = zend_vm_stack_push_call_frame_ex( - opline->op1.num, ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL, NULL); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE(); } @@ -2358,7 +1712,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HAND zend_class_entry *called_scope; zend_object *object; - zend_execute_data *call; uint32_t call_info = ZEND_CALL_NESTED_FUNCTION; SAVE_OPLINE(); @@ -2554,10 +1907,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HAND HANDLE_EXCEPTION(); } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -2614,7 +1965,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_ zend_free_op free_op2; zend_class_entry *called_scope; zend_object *object; - zend_execute_data *call; uint32_t call_info = ZEND_CALL_NESTED_FUNCTION; SAVE_OPLINE(); @@ -2810,10 +2160,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_ zval_ptr_dtor_nogc(free_op2); HANDLE_EXCEPTION(); } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -2884,6 +2232,100 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ECHO_SPEC_CONST_HANDLER(ZEND_O ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST(int type ZEND_OPCODE_HANDLER_ARGS_DC) +{ + USE_OPLINE + + zval *varname; + zval *retval; + zend_string *name; + HashTable *target_symbol_table; + + SAVE_OPLINE(); + varname = EX_CONSTANT(opline->op1); + + if (IS_CONST == IS_CONST) { + name = Z_STR_P(varname); + } else if (EXPECTED(Z_TYPE_P(varname) == IS_STRING)) { + name = Z_STR_P(varname); + zend_string_addref(name); + } else { + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) { + GET_OP1_UNDEF_CV(varname, BP_VAR_R); + } + name = zval_get_string(varname); + } + + target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK); + retval = zend_hash_find(target_symbol_table, name); + if (retval == NULL) { + switch (type) { + case BP_VAR_R: + case BP_VAR_UNSET: + zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); + /* break missing intentionally */ + case BP_VAR_IS: + retval = &EG(uninitialized_zval); + break; + case BP_VAR_RW: + zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); + retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval)); + break; + case BP_VAR_W: + retval = zend_hash_add_new(target_symbol_table, name, &EG(uninitialized_zval)); + break; + EMPTY_SWITCH_DEFAULT_CASE() + } + /* GLOBAL or $$name variable may be an INDIRECT pointer to CV */ + } else if (Z_TYPE_P(retval) == IS_INDIRECT) { + retval = Z_INDIRECT_P(retval); + if (Z_TYPE_P(retval) == IS_UNDEF) { + switch (type) { + case BP_VAR_R: + case BP_VAR_UNSET: + zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); + /* break missing intentionally */ + case BP_VAR_IS: + retval = &EG(uninitialized_zval); + break; + case BP_VAR_RW: + zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); + /* break missing intentionally */ + case BP_VAR_W: + ZVAL_NULL(retval); + break; + EMPTY_SWITCH_DEFAULT_CASE() + } + } + } + + 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 (IS_CONST != IS_CONST) { + zend_string_release(name); + } + + ZEND_ASSERT(retval != NULL); + if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } else { + ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMPZ_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -3269,54 +2711,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_THROW_SPEC_CONST_HANDLER(ZEND_ HANDLE_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval *value, *arg; - - - value = EX_CONSTANT(opline->op1); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_COPY_VALUE(arg, value); - if (IS_CONST == IS_CONST) { - if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { - zval_copy_ctor_func(arg); - } - } - ZEND_VM_NEXT_OPCODE(); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval *value, *arg; - - uint32_t arg_num = opline->op2.num; - - if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) { - if (QUICK_ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { - goto send_val_by_ref; - } - } else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { -send_val_by_ref: - SAVE_OPLINE(); - zend_throw_error(NULL, "Cannot pass parameter %d by reference", arg_num); - - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_UNDEF(arg); - HANDLE_EXCEPTION(); - } - value = EX_CONSTANT(opline->op1); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_COPY_VALUE(arg, value); - if (IS_CONST == IS_CONST) { - if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { - zval_copy_ctor_func(arg); - } - } - ZEND_VM_NEXT_OPCODE(); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BOOL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -3382,15 +2776,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_CONST_HANDLER(ZEND_OP ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } else { /* We are not handling overloaded classes right now */ - zend_execute_data *call = zend_vm_stack_push_call_frame( - ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR | - (EXPECTED(RETURN_VALUE_USED(opline)) ? 0 : ZEND_CALL_CTOR_RESULT_UNUSED), + zend_init_call_frame((zend_execute_data *) EX_VAR((OP_JMP_ADDR(opline, opline->op2) - 1)->op1.var), /* maybe find a better way to access this, but we only have 3 uint32_t's for each opcode ... */ + ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR | (EXPECTED(RETURN_VALUE_USED(opline)) ? 0 : ZEND_CALL_CTOR_RESULT_UNUSED), constructor, opline->extended_value, ce, Z_OBJ(object_zval)); - call->prev_execute_data = EX(call); - EX(call) = call; if (EXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), &object_zval); @@ -3575,135 +2966,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_HANDLER(ZEND_O ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_op_array *new_op_array=NULL; - - zval *inc_filename; - zval tmp_inc_filename; - zend_bool failure_retval=0; - - SAVE_OPLINE(); - inc_filename = EX_CONSTANT(opline->op1); - - ZVAL_UNDEF(&tmp_inc_filename); - if (Z_TYPE_P(inc_filename) != IS_STRING) { - if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(inc_filename) == IS_UNDEF)) { - inc_filename = GET_OP1_UNDEF_CV(inc_filename, BP_VAR_R); - } - ZVAL_STR(&tmp_inc_filename, zval_get_string(inc_filename)); - inc_filename = &tmp_inc_filename; - } - - if (opline->extended_value != ZEND_EVAL && strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename)) { - if (opline->extended_value == ZEND_INCLUDE_ONCE || opline->extended_value == ZEND_INCLUDE) { - zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename)); - } else { - zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename)); - } - } else { - switch (opline->extended_value) { - case ZEND_INCLUDE_ONCE: - case ZEND_REQUIRE_ONCE: { - zend_file_handle file_handle; - zend_string *resolved_path; - - resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), (int)Z_STRLEN_P(inc_filename)); - if (resolved_path) { - failure_retval = zend_hash_exists(&EG(included_files), resolved_path); - } else { - resolved_path = zend_string_copy(Z_STR_P(inc_filename)); - } - - if (failure_retval) { - /* do nothing, file already included */ - } else if (SUCCESS == zend_stream_open(ZSTR_VAL(resolved_path), &file_handle)) { - - if (!file_handle.opened_path) { - file_handle.opened_path = zend_string_copy(resolved_path); - } - - if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path)) { - new_op_array = zend_compile_file(&file_handle, (opline->extended_value==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE)); - zend_destroy_file_handle(&file_handle); - } else { - zend_file_handle_dtor(&file_handle); - failure_retval=1; - } - } else { - if (opline->extended_value == ZEND_INCLUDE_ONCE) { - zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename)); - } else { - zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename)); - } - } - zend_string_release(resolved_path); - } - break; - case ZEND_INCLUDE: - case ZEND_REQUIRE: - new_op_array = compile_filename(opline->extended_value, inc_filename); - break; - case ZEND_EVAL: { - char *eval_desc = zend_make_compiled_string_description("eval()'d code"); - - new_op_array = zend_compile_string(inc_filename, eval_desc); - efree(eval_desc); - } - break; - EMPTY_SWITCH_DEFAULT_CASE() - } - } - if (Z_TYPE(tmp_inc_filename) != IS_UNDEF) { - zend_string_release(Z_STR(tmp_inc_filename)); - } - - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); - } else if (EXPECTED(new_op_array != NULL)) { - zval *return_value = NULL; - zend_execute_data *call; - - if (RETURN_VALUE_USED(opline)) { - return_value = EX_VAR(opline->result.var); - } - - new_op_array->scope = EG(scope); - - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_CODE, - (zend_function*)new_op_array, 0, EX(called_scope), Z_OBJ(EX(This))); - - if (EX(symbol_table)) { - call->symbol_table = EX(symbol_table); - } else { - call->symbol_table = zend_rebuild_symbol_table(); - } - - call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value); - if (EXPECTED(zend_execute_ex == execute_ex)) { - ZEND_VM_ENTER(); - } else { - ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); - zend_execute_ex(call); - zend_vm_stack_free_call_frame(call); - } - - destroy_op_array(new_op_array); - efree_size(new_op_array, sizeof(zend_op_array)); - if (UNEXPECTED(EG(exception) != NULL)) { - zend_throw_exception_internal(NULL); - HANDLE_EXCEPTION(); - } - - } else if (RETURN_VALUE_USED(opline)) { - ZVAL_BOOL(EX_VAR(opline->result.var), failure_retval); - } - ZEND_VM_INTERRUPT_CHECK(); - ZEND_VM_NEXT_OPCODE(); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -4930,7 +4192,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BOOL_XOR_SPEC_CONST_CONST_HAND ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_CONST_CONST(int type ZEND_OPCODE_HANDLER_ARGS_DC) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_CONST_CONST(int type, int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -5030,43 +4292,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_ } else { ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_R_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_CONST(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_CONST(BP_VAR_R, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_W_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_CONST(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_CONST(BP_VAR_W, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_RW_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_CONST(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_CONST(BP_VAR_RW, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_FUNC_ARG_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_CONST(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_CONST(BP_VAR_W, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_CONST(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_CONST(BP_VAR_R, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_UNSET_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_CONST(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_CONST(BP_VAR_UNSET, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_IS_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_CONST(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_CONST(BP_VAR_IS, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -5105,7 +4367,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_ SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); @@ -5136,10 +4398,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_ } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_obj_r_helper_SPEC_CONST_CONST(int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -5208,7 +4470,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_CONST_H } while (0); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_CONST_CONST(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -5288,7 +4555,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_ USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -5319,9 +4586,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_ EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_TAIL_CALL(ZEND_FETCH_OBJ_R_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_CONST_CONST(2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } @@ -5445,7 +4712,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_CO zend_function *fbc; zend_class_entry *called_scope; zend_object *obj; - zend_execute_data *call; uint32_t call_info; SAVE_OPLINE(); @@ -5546,10 +4812,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_CO GC_REFCOUNT(obj)++; /* For $this pointer */ } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, obj); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -5562,7 +4826,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C zend_class_entry *ce; zend_object *object; zend_function *fbc; - zend_execute_data *call; SAVE_OPLINE(); @@ -5688,10 +4951,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C } } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, ce, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -5706,7 +4967,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS zend_function *func; zend_class_entry *called_scope; zend_object *object; - zend_execute_data *call; uint32_t call_info = ZEND_CALL_NESTED_FUNCTION; SAVE_OPLINE(); @@ -5746,10 +5006,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS object = NULL; } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, func, opline->extended_value, called_scope, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -6569,6 +5827,144 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_SPEC_CONST_TM ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR(opline->op2.var))) { + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + } else { + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + } +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *value, *arg = EX_VAR(opline->result.var); + + + value = EX_CONSTANT(opline->op1); + ZVAL_COPY_VALUE(arg, value); + if (IS_CONST == IS_CONST) { + if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { + zval_copy_ctor_func(arg); + } + } + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *value, *arg; + + uint32_t arg_num = opline->extended_value; + zend_function *fbc = ((zend_execute_data *) EX_VAR(opline->op2.var))->func; + + if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) { + if (QUICK_ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) { + goto send_val_by_ref; + } + } else if (ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) { +send_val_by_ref: + SAVE_OPLINE(); + zend_throw_error(NULL, "Cannot pass parameter %d by reference", arg_num); + + ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); + } + value = EX_CONSTANT(opline->op1); + arg = EX_VAR(opline->result.var); + ZVAL_COPY_VALUE(arg, value); + if (IS_CONST == IS_CONST) { + if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { + zval_copy_ctor_func(arg); + } + } + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *args; + int arg_num = opline->extended_value & ZEND_ARG_SEND_MASK; + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op2.var); + HashTable *ht; + + SAVE_OPLINE(); + if (UNEXPECTED(!(opline->extended_value & ZEND_ARG_IS_UNPACKED))) { + array_init(EX_VAR(opline->result.var)); + } + ht = Z_ARRVAL_P(EX_VAR(opline->result.var)); + args = EX_CONSTANT(opline->op1); + +send_again: + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { + zend_string *name; + zval *arg; + HashTable *arg_ht = Z_ARRVAL_P(args); + arg_num += zend_hash_num_elements(ht); + unpack_array_separate(args, &arg_ht, call, arg_num, IS_CONST); + + ZEND_HASH_FOREACH_STR_KEY_VAL(arg_ht, name, arg) { + if (UNEXPECTED(name != NULL)) { + zend_throw_error(NULL, "Cannot unpack array with string keys"); + + HANDLE_EXCEPTION(); + } + + if (ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num++)) { + if (!Z_IMMUTABLE_P(args)) { + ZVAL_MAKE_REF(arg); + Z_ADDREF_P(arg); + zend_hash_next_index_insert(ht, arg); + } else { + zval copy; + ZVAL_DUP(©, arg); + zend_hash_next_index_insert(ht, ©); + } + } else { + /* don't separate references for __call */ + if (UNEXPECTED(Z_ISREF_P(arg)) && EXPECTED((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) == 0)) { + arg = Z_REFVAL_P(arg); + } + Z_TRY_ADDREF_P(arg); + zend_hash_next_index_insert(ht, arg); + } + } ZEND_HASH_FOREACH_END(); + } else if (EXPECTED(Z_TYPE_P(args) == IS_OBJECT)) { + zend_class_entry *ce = Z_OBJCE_P(args); + zend_object_iterator *iter; + + if (!ce || !ce->get_iterator) { + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, object%s%s given", opline->extended_value & ZEND_ARG_SEND_MASK, ce ? " of type " : "", ce ? ZSTR_VAL(ce->name) : ""); + } else { + iter = ce->get_iterator(ce, args, 0); + if (UNEXPECTED(!iter)) { + + if (!EG(exception)) { + zend_throw_exception_ex(NULL, 0, "Object of type %s unpacked at parameter %d did not create an Iterator", ZSTR_VAL(ce->name), opline->extended_value & ZEND_ARG_SEND_MASK); + } + HANDLE_EXCEPTION(); + } + unpack_iterator_to_array(iter, ht, call, arg_num + zend_hash_num_elements(ht)); + } + } else if (EXPECTED(Z_ISREF_P(args))) { + args = Z_REFVAL_P(args); + goto send_again; + } else { + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(args) == IS_UNDEF)) { + GET_OP1_UNDEF_CV(args, BP_VAR_R); + } + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, %s given", opline->extended_value & ZEND_ARG_SEND_MASK, zend_get_type_by_const(Z_TYPE_P(args))); + } + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -6746,7 +6142,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_SPEC_CONST_VA ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_CONST_VAR(int type ZEND_OPCODE_HANDLER_ARGS_DC) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_CONST_VAR(int type, int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -6846,43 +6242,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_ } else { ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_R_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_VAR(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_VAR(BP_VAR_R, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_W_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_VAR(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_VAR(BP_VAR_W, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_RW_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_VAR(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_VAR(BP_VAR_RW, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_FUNC_ARG_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_VAR(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_VAR(BP_VAR_W, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_VAR(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_VAR(BP_VAR_R, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_UNSET_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_VAR(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_VAR(BP_VAR_UNSET, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_IS_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_VAR(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_VAR(BP_VAR_IS, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_STATIC_PROP_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -7167,137 +6563,32 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(Z ZEND_VM_RETURN(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST_UNUSED(int type ZEND_OPCODE_HANDLER_ARGS_DC) -{ - USE_OPLINE - - zval *varname; - zval *retval; - zend_string *name; - HashTable *target_symbol_table; - - SAVE_OPLINE(); - varname = EX_CONSTANT(opline->op1); - - if (IS_CONST == IS_CONST) { - name = Z_STR_P(varname); - } else if (EXPECTED(Z_TYPE_P(varname) == IS_STRING)) { - name = Z_STR_P(varname); - zend_string_addref(name); - } else { - if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(varname, BP_VAR_R); - } - name = zval_get_string(varname); - } - - target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK); - retval = zend_hash_find(target_symbol_table, name); - if (retval == NULL) { - switch (type) { - case BP_VAR_R: - case BP_VAR_UNSET: - zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); - /* break missing intentionally */ - case BP_VAR_IS: - retval = &EG(uninitialized_zval); - break; - case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); - retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval)); - break; - case BP_VAR_W: - retval = zend_hash_add_new(target_symbol_table, name, &EG(uninitialized_zval)); - break; - EMPTY_SWITCH_DEFAULT_CASE() - } - /* GLOBAL or $$name variable may be an INDIRECT pointer to CV */ - } else if (Z_TYPE_P(retval) == IS_INDIRECT) { - retval = Z_INDIRECT_P(retval); - if (Z_TYPE_P(retval) == IS_UNDEF) { - switch (type) { - case BP_VAR_R: - case BP_VAR_UNSET: - zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); - /* break missing intentionally */ - case BP_VAR_IS: - retval = &EG(uninitialized_zval); - break; - case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); - /* break missing intentionally */ - case BP_VAR_W: - ZVAL_NULL(retval); - break; - EMPTY_SWITCH_DEFAULT_CASE() - } - } - } - - 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 (IS_CONST != IS_CONST) { - zend_string_release(name); - } - - ZEND_ASSERT(retval != NULL); - if (type == BP_VAR_R || type == BP_VAR_IS) { - if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { - ZVAL_UNREF(retval); - } - ZVAL_COPY(EX_VAR(opline->result.var), retval); - } else { - ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); - } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_R_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_W_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_RW_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); - } else { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); - } + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_IS_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST_UNUSED(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CONST(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(int type ZEND_OPCODE_HANDLER_ARGS_DC) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(int type, int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -7397,43 +6688,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_ } else { ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_R_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(BP_VAR_R, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_W_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(BP_VAR_W, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_RW_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(BP_VAR_RW, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_FUNC_ARG_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(BP_VAR_W, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(BP_VAR_R, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_UNSET_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(BP_VAR_UNSET, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_IS_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CONST_UNUSED(BP_VAR_IS, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -7444,7 +6735,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_ SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); @@ -7475,7 +6766,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_ } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -7485,7 +6776,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C zend_class_entry *ce; zend_object *object; zend_function *fbc; - zend_execute_data *call; SAVE_OPLINE(); @@ -7611,10 +6901,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C } } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, ce, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -8893,7 +8181,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_ SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); @@ -8924,10 +8212,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_ } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_obj_r_helper_SPEC_CONST_CV(int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -8996,7 +8284,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_CV_HAND } while (0); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_CONST_CV(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -9076,7 +8369,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_ USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -9107,9 +8400,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_ EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_TAIL_CALL(ZEND_FETCH_OBJ_R_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_CONST_CV(2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } @@ -9189,7 +8482,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_CV zend_function *fbc; zend_class_entry *called_scope; zend_object *obj; - zend_execute_data *call; uint32_t call_info; SAVE_OPLINE(); @@ -9290,10 +8582,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_CV GC_REFCOUNT(obj)++; /* For $this pointer */ } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, obj); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -9306,7 +8596,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C zend_class_entry *ce; zend_object *object; zend_function *fbc; - zend_execute_data *call; SAVE_OPLINE(); @@ -9432,10 +8721,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C } } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, ce, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -9450,7 +8737,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H zend_function *func; zend_class_entry *called_scope; zend_object *object; - zend_execute_data *call; uint32_t call_info = ZEND_CALL_NESTED_FUNCTION; SAVE_OPLINE(); @@ -9490,10 +8776,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H object = NULL; } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, func, opline->extended_value, called_scope, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -10705,7 +9989,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_ SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); @@ -10736,10 +10020,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_ zval_ptr_dtor_nogc(free_op2); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_obj_r_helper_SPEC_CONST_TMPVAR(int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -10809,7 +10093,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_TMPVAR_ zval_ptr_dtor_nogc(free_op2); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_CONST_TMPVAR(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -10890,7 +10179,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_ USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -10921,9 +10210,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_ EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_TAIL_CALL(ZEND_FETCH_OBJ_R_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_CONST_TMPVAR(2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } @@ -11003,7 +10292,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_TM zend_function *fbc; zend_class_entry *called_scope; zend_object *obj; - zend_execute_data *call; uint32_t call_info; SAVE_OPLINE(); @@ -11104,10 +10392,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_TM GC_REFCOUNT(obj)++; /* For $this pointer */ } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, obj); - call->prev_execute_data = EX(call); - EX(call) = call; zval_ptr_dtor_nogc(free_op2); @@ -11121,7 +10407,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C zend_class_entry *ce; zend_object *object; zend_function *fbc; - zend_execute_data *call; SAVE_OPLINE(); @@ -11247,10 +10532,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C } } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, ce, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -11265,7 +10548,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV zend_function *func; zend_class_entry *called_scope; zend_object *object; - zend_execute_data *call; uint32_t call_info = ZEND_CALL_NESTED_FUNCTION; SAVE_OPLINE(); @@ -11305,10 +10587,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV object = NULL; } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, func, opline->extended_value, called_scope, object); - call->prev_execute_data = EX(call); - EX(call) = call; zval_ptr_dtor_nogc(free_op2); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -11694,6 +10974,376 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_CO ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op1.var); + zend_function *fbc = call->func; + zval *ret; + + SAVE_OPLINE(); + + call->prev_execute_data = execute_data; + EG(current_execute_data) = call; + + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = 0; + + fbc->internal_function.handler(call, ret); + +#if ZEND_DEBUG + ZEND_ASSERT( + !call->func || + !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || + zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var))); +#endif + + EG(current_execute_data) = call->prev_execute_data; + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); + + if (!RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL); + if (RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + HANDLE_EXCEPTION(); + } + + ZEND_VM_INTERRUPT_CHECK(); + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op1.var); + zend_function *fbc = call->func; + zval *ret; + + SAVE_OPLINE(); + + EG(scope) = NULL; + ret = NULL; + call->symbol_table = NULL; + if (RETURN_VALUE_USED(opline)) { + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = 0; + } + + if (UNEXPECTED(((zval *) call) + opline->op2.num >= EG(vm_stack_end))) { + call = zend_vm_stack_copy_call_frame(call, ZEND_CALL_NUM_ARGS(call), 0); + } + + call->prev_execute_data = execute_data; + i_init_func_execute_data(call, &fbc->op_array, ret, 0); + + ZEND_VM_ENTER(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op1.var); + zend_function *fbc = call->func; + zval *ret; + + SAVE_OPLINE(); + + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { + EG(scope) = NULL; + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (EXPECTED(RETURN_VALUE_USED(opline))) { + ret = EX_VAR(opline->result.var); + zend_generator_create_zval(call, &fbc->op_array, ret); + Z_VAR_FLAGS_P(ret) = 0; + } else { + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); + } + } else { + zend_op_array *op_array = &fbc->op_array; + + ret = NULL; + call->symbol_table = NULL; + if (RETURN_VALUE_USED(opline)) { + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = 0; + } + + if (UNEXPECTED(((zval *)(((void *) call) + zend_vm_calc_used_stack(0, fbc))) >= EG(vm_stack_end))) { + call = zend_vm_stack_copy_call_frame(call, ZEND_CALL_NUM_ARGS(call), 0); + } else if (UNEXPECTED(ZEND_CALL_NUM_ARGS(call) + ZEND_RESERVED_RECV_SLOTS < op_array->num_args)) { + call = zend_vm_stack_extend_call_frame(call, ZEND_CALL_NUM_ARGS(call), op_array->num_args - ZEND_CALL_NUM_ARGS(call)); + } + + call->prev_execute_data = execute_data; + i_init_func_execute_data(call, op_array, ret, 0); + + ZEND_VM_ENTER(); + } + EG(scope) = EX(func)->op_array.scope; + } else { + ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION); + + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { + zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", + fbc->common.scope ? ZSTR_VAL(fbc->common.scope->name) : "", + fbc->common.scope ? "::" : "", + ZSTR_VAL(fbc->common.function_name)); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } + } + + call->prev_execute_data = execute_data; + EG(current_execute_data) = call; + + if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { + uint32_t i; + uint32_t num_args = ZEND_CALL_NUM_ARGS(call); + zval *p = ZEND_CALL_ARG(call, 1); + + for (i = 0; i < num_args; ++i) { + if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) { + EG(current_execute_data) = call->prev_execute_data; + zend_free_args_internal(call, ZEND_CALL_INFO(call)); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + zend_throw_exception_internal(NULL); + HANDLE_EXCEPTION(); + } + p--; + } + } + + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; + + fbc->internal_function.handler(call, ret); + +#if ZEND_DEBUG + ZEND_ASSERT( + !call->func || + !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || + zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var))); +#endif + + EG(current_execute_data) = call->prev_execute_data; + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); + + if (!RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + } + + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL); + if (RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + HANDLE_EXCEPTION(); + } + ZEND_VM_INTERRUPT_CHECK(); + ZEND_VM_NEXT_OPCODE(); +} + +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_do_fcall_helper_SPEC_TMP(zend_execute_data *call, zend_function *fbc, zend_bool extra_call_frame ZEND_OPCODE_HANDLER_ARGS_DC) +{ + USE_OPLINE + zend_object *object; + zval *ret; + + LOAD_OPLINE(); + if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) { + EG(scope) = fbc->common.scope; + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) { + if (EXPECTED(RETURN_VALUE_USED(opline))) { + ret = EX_VAR(opline->result.var); + zend_generator_create_zval(call, &fbc->op_array, ret); + Z_VAR_FLAGS_P(ret) = 0; + } else { + if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) { + OBJ_RELEASE((zend_object*)fbc->op_array.prototype); + } + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); + } + cleanup_this_object_call(call, UNEXPECTED(EG(exception) != NULL)); + if (UNEXPECTED(extra_call_frame != 0)) { + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + } + EG(scope) = EX(func)->op_array.scope; + } else { + ret = NULL; + call->symbol_table = NULL; + if (RETURN_VALUE_USED(opline)) { + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = 0; + } + + if (EXPECTED(extra_call_frame == 0)) { + zend_op_array *op_array = &fbc->op_array; + if (UNEXPECTED(((zval *)(((void *) call) + zend_vm_calc_used_stack(0, fbc))) >= EG(vm_stack_end))) { + call = zend_vm_stack_copy_call_frame(call, ZEND_CALL_NUM_ARGS(call), 0); + } else if (UNEXPECTED(ZEND_CALL_NUM_ARGS(call) + ZEND_RESERVED_RECV_SLOTS < op_array->num_args)) { + call = zend_vm_stack_extend_call_frame(call, ZEND_CALL_NUM_ARGS(call), op_array->num_args - ZEND_CALL_NUM_ARGS(call)); + } + } + + call->prev_execute_data = execute_data; + i_init_func_execute_data(call, &fbc->op_array, ret, 1); + + if (EXPECTED(zend_execute_ex == execute_ex)) { + ZEND_VM_ENTER(); + } else { + zval this = call->This; + ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); + zend_execute_ex(call); + /* unable to rely on initial call value, ... use backup for this freeing */ + call->This = this; + cleanup_this_object_call(call, UNEXPECTED(EG(exception) != NULL)); + /* we can't check for ZEND_CALL_ALLOCATED as ZEND_CALL_TRAMPOLINE may have altered the location of execute_data! */ + zend_vm_stack_free_call_frame((void *) execute_data > (void *) EG(vm_stack_end) || (void *) execute_data < (void *) EG(vm_stack) ? ZEND_CALL_ALLOCATED : 0); + EG(scope) = EX(func)->op_array.scope; + } + } + } else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) { + int should_change_scope = 0; + + if (fbc->common.scope) { + should_change_scope = 1; + EG(scope) = fbc->common.scope; + } + + call->prev_execute_data = execute_data; + EG(current_execute_data) = call; + + if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { + uint32_t i; + uint32_t num_args = ZEND_CALL_NUM_ARGS(call); + zval *p = ZEND_CALL_ARG(call, 1); + + for (i = 0; i < num_args; ++i) { + if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + goto icall_end; + } + p--; + } + } + + ret = EX_VAR(opline->result.var); + ZVAL_NULL(ret); + Z_VAR_FLAGS_P(ret) = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0 ? IS_VAR_RET_REF : 0; + + if (!zend_execute_internal) { + /* saves one function call if zend_execute_internal is not used */ + fbc->internal_function.handler(call, ret); + } else { + zend_execute_internal(call, ret); + } + +#if ZEND_DEBUG + ZEND_ASSERT( + !call->func || + !(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || + zend_verify_internal_return_type(call->func, EX_VAR(opline->result.var))); +#endif + +icall_end: + EG(current_execute_data) = call->prev_execute_data; + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); + + if (!RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + + if (UNEXPECTED(should_change_scope)) { + cleanup_this_object_call(call, UNEXPECTED(EG(exception) != NULL)); + EG(scope) = EX(func)->op_array.scope; + } + if (UNEXPECTED(extra_call_frame != 0)) { + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + } + } else { /* ZEND_OVERLOADED_FUNCTION */ + /* Not sure what should be done here if it's a static method */ + object = Z_OBJ(call->This); + if (UNEXPECTED(object == NULL)) { + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); + if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { + zend_string_release(fbc->common.function_name); + } + efree(fbc); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + + zend_throw_error(NULL, "Cannot call overloaded function for non-object"); + HANDLE_EXCEPTION(); + } + + EG(scope) = fbc->common.scope; + + ZVAL_NULL(EX_VAR(opline->result.var)); + + call->prev_execute_data = execute_data; + EG(current_execute_data) = call; + object->handlers->call_method(fbc->common.function_name, object, call, EX_VAR(opline->result.var)); + EG(current_execute_data) = call->prev_execute_data; + + zend_free_args_internal(call, ZEND_CALL_NUM_ARGS(call)); + + if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { + zend_string_release(fbc->common.function_name); + } + efree(fbc); + + if (!RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } else { + Z_VAR_FLAGS_P(EX_VAR(opline->result.var)) = 0; + } + + cleanup_this_object_call(call, UNEXPECTED(EG(exception) != NULL)); + EG(scope) = EX(func)->op_array.scope; + + if (UNEXPECTED(extra_call_frame != 0)) { + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + } + } + + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL); + if (RETURN_VALUE_USED(opline)) { + zval_ptr_dtor(EX_VAR(opline->result.var)); + } + HANDLE_EXCEPTION(); + } + + ZEND_VM_INTERRUPT_CHECK(); + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op1.var); + zend_function *fbc = call->func; + + if (UNEXPECTED(zend_check_abstract_or_deprecated(fbc) == 1)) { + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + + SAVE_OPLINE(); + + ZEND_VM_TAIL_CALL(zend_do_fcall_helper_SPEC_TMP(call, fbc, 0 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -11890,54 +11540,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_THROW_SPEC_TMP_HANDLER(ZEND_OP HANDLE_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval *value, *arg; - zend_free_op free_op1; - - value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_COPY_VALUE(arg, value); - if (IS_TMP_VAR == IS_CONST) { - if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { - zval_copy_ctor_func(arg); - } - } - ZEND_VM_NEXT_OPCODE(); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval *value, *arg; - zend_free_op free_op1; - uint32_t arg_num = opline->op2.num; - - if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) { - if (QUICK_ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { - goto send_val_by_ref; - } - } else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { -send_val_by_ref: - SAVE_OPLINE(); - zend_throw_error(NULL, "Cannot pass parameter %d by reference", arg_num); - zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_UNDEF(arg); - HANDLE_EXCEPTION(); - } - value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_COPY_VALUE(arg, value); - if (IS_TMP_VAR == IS_CONST) { - if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { - zval_copy_ctor_func(arg); - } - } - ZEND_VM_NEXT_OPCODE(); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -12595,7 +12197,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_CO SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); @@ -12626,10 +12228,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_CO zval_ptr_dtor_nogc(free_op1); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_obj_r_helper_SPEC_TMP_CONST(int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE zend_free_op free_op1; @@ -12698,7 +12300,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_CONST_HAN } while (0); zval_ptr_dtor_nogc(free_op1); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_TMP_CONST(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -12706,7 +12313,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_CO USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -12737,9 +12344,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_CO EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_TAIL_CALL(ZEND_FETCH_OBJ_R_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_TMP_CONST(2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } @@ -12829,6 +12436,192 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_END_SPEC_TMP_CONST_HANDLE ZEND_VM_NEXT_OPCODE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UNPACK_FCALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op1.var); + zend_function *fbc = call->func; + uint32_t arg_num = opline->extended_value & ZEND_ARG_SEND_MASK; + uint32_t new_args; + HashTable *ht, local_ht; + + + zval *args; + + SAVE_OPLINE(); + args = EX_CONSTANT(opline->op2); + +send_again: + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { + ht = Z_ARRVAL_P(args); + } else if (EXPECTED(Z_TYPE_P(args) == IS_OBJECT)) { + zend_class_entry *ce = Z_OBJCE_P(args); + zend_object_iterator *iter; + + if (UNEXPECTED(!ce) || UNEXPECTED(!ce->get_iterator)) { + if (opline->extended_value & ZEND_ARG_IS_CUFA) { + zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array or Traversable, object%s%s given", ce ? " of type " : "", ce ? ZSTR_VAL(ce->name) : ""); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, object%s%s given", opline->extended_value & ZEND_ARG_SEND_MASK, ce ? " of type " : "", ce ? ZSTR_VAL(ce->name) : ""); + } + + if (UNEXPECTED(EG(exception) != NULL)) { + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + ZEND_VM_TAIL_CALL(ZEND_DO_FCALL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + } + + iter = ce->get_iterator(ce, args, 0); + if (UNEXPECTED(!iter)) { + + if (!EG(exception)) { + zend_throw_exception_ex(NULL, 0, "Object of type %s unpacked at parameter %d did not create an Iterator", ZSTR_VAL(ce->name), opline->extended_value & ZEND_ARG_SEND_MASK); + } + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + + ht = &local_ht; + zend_hash_init(ht, 8, pHashFunction should be killed, ZVAL_PTR_DTOR, 0); + + unpack_iterator_to_array(iter, ht, call, arg_num); + + if (UNEXPECTED(EG(exception) != NULL)) { + zend_hash_destroy(ht); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + } else { + if ((IS_CONST & (IS_VAR|IS_CV)) && EXPECTED(Z_ISREF_P(args))) { + args = Z_REFVAL_P(args); + goto send_again; + } + if (opline->extended_value & ZEND_ARG_IS_CUFA) { + zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array or Traversable, %s given", zend_get_type_by_const(Z_TYPE_P(args))); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, %s given", opline->extended_value & ZEND_ARG_SEND_MASK, zend_get_type_by_const(Z_TYPE_P(args))); + } + + if (EG(exception)) { + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + ZEND_VM_TAIL_CALL(ZEND_DO_FCALL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + } + + if (UNEXPECTED(zend_check_abstract_or_deprecated(fbc) == 1)) { + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY) && (IS_CONST != IS_TMP_VAR || EXPECTED((opline->extended_value & ZEND_ARG_IS_UNPACKED) == 0))) { + + } else { + zend_hash_destroy(ht); + if (opline->extended_value & ZEND_ARG_IS_UNPACKED) { + efree(ht); + } + } + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + + LOAD_OPLINE(); + + new_args = zend_hash_num_elements(ht); + + if (fbc->type == ZEND_USER_FUNCTION) { + if (UNEXPECTED(((zval *)(((void *) call) + zend_vm_calc_used_stack(0, fbc))) >= EG(vm_stack_end))) { + call = zend_vm_stack_copy_call_frame(call, ZEND_CALL_NUM_ARGS(call), new_args); + } else if (new_args > ZEND_RESERVED_RECV_SLOTS || ZEND_CALL_NUM_ARGS(call) + ZEND_RESERVED_RECV_SLOTS < fbc->op_array.num_args) { + call = zend_vm_stack_extend_call_frame(call, ZEND_CALL_NUM_ARGS(call), new_args); + } + } else if (new_args > ZEND_RESERVED_RECV_SLOTS) { + call = zend_vm_stack_extend_call_frame(call, ZEND_CALL_NUM_ARGS(call), new_args); + } + + ZEND_CALL_NUM_ARGS(call) = arg_num + new_args - 1; + + /* if no previous unpack: optimization to not always duplicate the array, only for more than 1 unpack (or iterators) */ + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY) && (IS_CONST != IS_TMP_VAR || EXPECTED((opline->extended_value & ZEND_ARG_IS_UNPACKED) == 0))) { + zend_string *name; + zval *arg; + + zend_bool cufa = (opline->extended_value & ZEND_ARG_IS_CUFA) != 0; + + unpack_array_separate(args, &ht, call, arg_num, IS_CONST); + + ZEND_HASH_FOREACH_STR_KEY_VAL(ht, name, arg) { + if (UNEXPECTED(name != NULL)) { + zend_throw_error(NULL, "Cannot unpack array with string keys"); + + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + HANDLE_EXCEPTION(); + } + if (UNEXPECTED(ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num))) { + if (cufa && !Z_ISREF_P(arg)) { + if (UNEXPECTED(!ARG_MAY_BE_SENT_BY_REF(call->func, arg_num))) { + zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", + arg_num, + call->func->common.scope ? ZSTR_VAL(call->func->common.scope->name) : "", + call->func->common.scope ? "::" : "", + ZSTR_VAL(call->func->common.function_name) + ); + + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + } else if (EXPECTED(!Z_IMMUTABLE_P(args))) { + ZVAL_MAKE_REF(arg); + Z_ADDREF_P(arg); + ZVAL_COPY_VALUE(ZEND_CALL_ARG(call, arg_num++), arg); + continue; + } + + ZVAL_DUP(ZEND_CALL_ARG(call, arg_num++), arg); + } else { + /* don't separate references for __call */ + if (UNEXPECTED(Z_ISREF_P(arg)) && EXPECTED((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) == 0)) { + arg = Z_REFVAL_P(arg); + } + Z_TRY_ADDREF_P(arg); + ZVAL_COPY_VALUE(ZEND_CALL_ARG(call, arg_num++), arg); + } + } ZEND_HASH_FOREACH_END(); + + } else { + ZEND_HASH_FOREACH_VAL(ht, args) { + zval *top = ZEND_CALL_ARG(call, arg_num++); + ZVAL_COPY_VALUE(top, args); + } ZEND_HASH_FOREACH_END(); + + ZEND_ASSERT(GC_REFCOUNT(ht) == 1); + ht->pDestructor = NULL; // do not free the zvals... + zend_hash_destroy(ht); // just free the array memory + if (opline->extended_value & ZEND_ARG_IS_UNPACKED) { + efree(ht); + } + } + + ZEND_VM_TAIL_CALL(zend_do_fcall_helper_SPEC_TMP(call, fbc, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -12959,6 +12752,133 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_TMP_CONST_HAND } } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_op_array *new_op_array=NULL; + + zval *inc_filename; + zval tmp_inc_filename; + zend_bool failure_retval=0; + + SAVE_OPLINE(); + inc_filename = EX_CONSTANT(opline->op2); + + ZVAL_UNDEF(&tmp_inc_filename); + if (Z_TYPE_P(inc_filename) != IS_STRING) { + if (IS_TMP_VAR == IS_CV && UNEXPECTED(Z_TYPE_P(inc_filename) == IS_UNDEF)) { + inc_filename = GET_OP2_UNDEF_CV(inc_filename, BP_VAR_R); + } + ZVAL_STR(&tmp_inc_filename, zval_get_string(inc_filename)); + inc_filename = &tmp_inc_filename; + } + + if (opline->extended_value != ZEND_EVAL && strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename)) { + if (opline->extended_value == ZEND_INCLUDE_ONCE || opline->extended_value == ZEND_INCLUDE) { + zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename)); + } else { + zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename)); + } + } else { + switch (opline->extended_value) { + case ZEND_INCLUDE_ONCE: + case ZEND_REQUIRE_ONCE: { + zend_file_handle file_handle; + zend_string *resolved_path; + + resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), (int)Z_STRLEN_P(inc_filename)); + if (resolved_path) { + failure_retval = zend_hash_exists(&EG(included_files), resolved_path); + } else { + resolved_path = zend_string_copy(Z_STR_P(inc_filename)); + } + + if (failure_retval) { + /* do nothing, file already included */ + } else if (SUCCESS == zend_stream_open(ZSTR_VAL(resolved_path), &file_handle)) { + + if (!file_handle.opened_path) { + file_handle.opened_path = zend_string_copy(resolved_path); + } + + if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path)) { + new_op_array = zend_compile_file(&file_handle, (opline->extended_value==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE)); + zend_destroy_file_handle(&file_handle); + } else { + zend_file_handle_dtor(&file_handle); + failure_retval=1; + } + } else { + if (opline->extended_value == ZEND_INCLUDE_ONCE) { + zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename)); + } else { + zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename)); + } + } + zend_string_release(resolved_path); + } + break; + case ZEND_INCLUDE: + case ZEND_REQUIRE: + new_op_array = compile_filename(opline->extended_value, inc_filename); + break; + case ZEND_EVAL: { + char *eval_desc = zend_make_compiled_string_description("eval()'d code"); + + new_op_array = zend_compile_string(inc_filename, eval_desc); + efree(eval_desc); + } + break; + EMPTY_SWITCH_DEFAULT_CASE() + } + } + if (Z_TYPE(tmp_inc_filename) != IS_UNDEF) { + zend_string_release(Z_STR(tmp_inc_filename)); + } + + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } else if (EXPECTED(new_op_array != NULL)) { + zval *return_value = NULL; + zend_execute_data *call = zend_push_call_frame((zend_execute_data *) EX_VAR(opline->op1.var), ZEND_CALL_NESTED_CODE, + (zend_function *) new_op_array, 0, EX(called_scope), Z_OBJ(EX(This))); + + if (RETURN_VALUE_USED(opline)) { + return_value = EX_VAR(opline->result.var); + } + + new_op_array->scope = EG(scope); + + if (EX(symbol_table)) { + call->symbol_table = EX(symbol_table); + } else { + call->symbol_table = zend_rebuild_symbol_table(); + } + + call->prev_execute_data = execute_data; + i_init_code_execute_data(call, new_op_array, return_value); + if (EXPECTED(zend_execute_ex == execute_ex)) { + ZEND_VM_ENTER(); + } else { + ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); + zend_execute_ex(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + } + + destroy_op_array(new_op_array); + efree_size(new_op_array, sizeof(zend_op_array)); + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL); + HANDLE_EXCEPTION(); + } + + } else if (RETURN_VALUE_USED(opline)) { + ZVAL_BOOL(EX_VAR(opline->result.var), failure_retval); + } + ZEND_VM_INTERRUPT_CHECK(); + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -13136,6 +13056,322 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_SPEC_TMP_TMP_ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *value, *arg = EX_VAR(opline->result.var); + zend_free_op free_op1; + + value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1); + ZVAL_COPY_VALUE(arg, value); + if (IS_TMP_VAR == IS_CONST) { + if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { + zval_copy_ctor_func(arg); + } + } + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *value, *arg; + zend_free_op free_op1; + uint32_t arg_num = opline->extended_value; + zend_function *fbc = ((zend_execute_data *) EX_VAR(opline->op2.var))->func; + + if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) { + if (QUICK_ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) { + goto send_val_by_ref; + } + } else if (ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) { +send_val_by_ref: + SAVE_OPLINE(); + zend_throw_error(NULL, "Cannot pass parameter %d by reference", arg_num); + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + ZVAL_UNDEF(EX_VAR(opline->result.var)); + HANDLE_EXCEPTION(); + } + value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1); + arg = EX_VAR(opline->result.var); + ZVAL_COPY_VALUE(arg, value); + if (IS_TMP_VAR == IS_CONST) { + if (UNEXPECTED(Z_OPT_COPYABLE_P(arg))) { + zval_copy_ctor_func(arg); + } + } + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *args; + int arg_num = opline->extended_value & ZEND_ARG_SEND_MASK; + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op2.var); + HashTable *ht; + + SAVE_OPLINE(); + if (UNEXPECTED(!(opline->extended_value & ZEND_ARG_IS_UNPACKED))) { + array_init(EX_VAR(opline->result.var)); + } + ht = Z_ARRVAL_P(EX_VAR(opline->result.var)); + args = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1); + +send_again: + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { + zend_string *name; + zval *arg; + HashTable *arg_ht = Z_ARRVAL_P(args); + arg_num += zend_hash_num_elements(ht); + unpack_array_separate(args, &arg_ht, call, arg_num, IS_TMP_VAR); + + ZEND_HASH_FOREACH_STR_KEY_VAL(arg_ht, name, arg) { + if (UNEXPECTED(name != NULL)) { + zend_throw_error(NULL, "Cannot unpack array with string keys"); + zval_ptr_dtor_nogc(free_op1); + HANDLE_EXCEPTION(); + } + + if (ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num++)) { + if (!Z_IMMUTABLE_P(args)) { + ZVAL_MAKE_REF(arg); + Z_ADDREF_P(arg); + zend_hash_next_index_insert(ht, arg); + } else { + zval copy; + ZVAL_DUP(©, arg); + zend_hash_next_index_insert(ht, ©); + } + } else { + /* don't separate references for __call */ + if (UNEXPECTED(Z_ISREF_P(arg)) && EXPECTED((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) == 0)) { + arg = Z_REFVAL_P(arg); + } + Z_TRY_ADDREF_P(arg); + zend_hash_next_index_insert(ht, arg); + } + } ZEND_HASH_FOREACH_END(); + } else if (EXPECTED(Z_TYPE_P(args) == IS_OBJECT)) { + zend_class_entry *ce = Z_OBJCE_P(args); + zend_object_iterator *iter; + + if (!ce || !ce->get_iterator) { + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, object%s%s given", opline->extended_value & ZEND_ARG_SEND_MASK, ce ? " of type " : "", ce ? ZSTR_VAL(ce->name) : ""); + } else { + iter = ce->get_iterator(ce, args, 0); + if (UNEXPECTED(!iter)) { + zval_ptr_dtor_nogc(free_op1); + if (!EG(exception)) { + zend_throw_exception_ex(NULL, 0, "Object of type %s unpacked at parameter %d did not create an Iterator", ZSTR_VAL(ce->name), opline->extended_value & ZEND_ARG_SEND_MASK); + } + HANDLE_EXCEPTION(); + } + unpack_iterator_to_array(iter, ht, call, arg_num + zend_hash_num_elements(ht)); + } + } else if (EXPECTED(Z_ISREF_P(args))) { + args = Z_REFVAL_P(args); + goto send_again; + } else { + if (IS_TMP_VAR == IS_CV && UNEXPECTED(Z_TYPE_P(args) == IS_UNDEF)) { + GET_OP1_UNDEF_CV(args, BP_VAR_R); + } + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, %s given", opline->extended_value & ZEND_ARG_SEND_MASK, zend_get_type_by_const(Z_TYPE_P(args))); + } + + zval_ptr_dtor_nogc(free_op1); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UNPACK_FCALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op1.var); + zend_function *fbc = call->func; + uint32_t arg_num = opline->extended_value & ZEND_ARG_SEND_MASK; + uint32_t new_args; + HashTable *ht, local_ht; + + zend_free_op free_op2; + zval *args; + + SAVE_OPLINE(); + args = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2); + +send_again: + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { + ht = Z_ARRVAL_P(args); + } else if (EXPECTED(Z_TYPE_P(args) == IS_OBJECT)) { + zend_class_entry *ce = Z_OBJCE_P(args); + zend_object_iterator *iter; + + if (UNEXPECTED(!ce) || UNEXPECTED(!ce->get_iterator)) { + if (opline->extended_value & ZEND_ARG_IS_CUFA) { + zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array or Traversable, object%s%s given", ce ? " of type " : "", ce ? ZSTR_VAL(ce->name) : ""); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, object%s%s given", opline->extended_value & ZEND_ARG_SEND_MASK, ce ? " of type " : "", ce ? ZSTR_VAL(ce->name) : ""); + } + zval_ptr_dtor_nogc(free_op2); + if (UNEXPECTED(EG(exception) != NULL)) { + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + ZEND_VM_TAIL_CALL(ZEND_DO_FCALL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + } + + iter = ce->get_iterator(ce, args, 0); + if (UNEXPECTED(!iter)) { + zval_ptr_dtor_nogc(free_op2); + if (!EG(exception)) { + zend_throw_exception_ex(NULL, 0, "Object of type %s unpacked at parameter %d did not create an Iterator", ZSTR_VAL(ce->name), opline->extended_value & ZEND_ARG_SEND_MASK); + } + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + + ht = &local_ht; + zend_hash_init(ht, 8, pHashFunction should be killed, ZVAL_PTR_DTOR, 0); + + unpack_iterator_to_array(iter, ht, call, arg_num); + + zval_ptr_dtor_nogc(free_op2); + if (UNEXPECTED(EG(exception) != NULL)) { + zend_hash_destroy(ht); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + } else { + if ((IS_TMP_VAR & (IS_VAR|IS_CV)) && EXPECTED(Z_ISREF_P(args))) { + args = Z_REFVAL_P(args); + goto send_again; + } + if (opline->extended_value & ZEND_ARG_IS_CUFA) { + zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array or Traversable, %s given", zend_get_type_by_const(Z_TYPE_P(args))); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, %s given", opline->extended_value & ZEND_ARG_SEND_MASK, zend_get_type_by_const(Z_TYPE_P(args))); + } + zval_ptr_dtor_nogc(free_op2); + if (EG(exception)) { + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + ZEND_VM_TAIL_CALL(ZEND_DO_FCALL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + } + + if (UNEXPECTED(zend_check_abstract_or_deprecated(fbc) == 1)) { + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY) && (IS_TMP_VAR != IS_TMP_VAR || EXPECTED((opline->extended_value & ZEND_ARG_IS_UNPACKED) == 0))) { + zval_ptr_dtor_nogc(free_op2); + } else { + zend_hash_destroy(ht); + if (opline->extended_value & ZEND_ARG_IS_UNPACKED) { + efree(ht); + } + } + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + + LOAD_OPLINE(); + + new_args = zend_hash_num_elements(ht); + + if (fbc->type == ZEND_USER_FUNCTION) { + if (UNEXPECTED(((zval *)(((void *) call) + zend_vm_calc_used_stack(0, fbc))) >= EG(vm_stack_end))) { + call = zend_vm_stack_copy_call_frame(call, ZEND_CALL_NUM_ARGS(call), new_args); + } else if (new_args > ZEND_RESERVED_RECV_SLOTS || ZEND_CALL_NUM_ARGS(call) + ZEND_RESERVED_RECV_SLOTS < fbc->op_array.num_args) { + call = zend_vm_stack_extend_call_frame(call, ZEND_CALL_NUM_ARGS(call), new_args); + } + } else if (new_args > ZEND_RESERVED_RECV_SLOTS) { + call = zend_vm_stack_extend_call_frame(call, ZEND_CALL_NUM_ARGS(call), new_args); + } + + ZEND_CALL_NUM_ARGS(call) = arg_num + new_args - 1; + + /* if no previous unpack: optimization to not always duplicate the array, only for more than 1 unpack (or iterators) */ + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY) && (IS_TMP_VAR != IS_TMP_VAR || EXPECTED((opline->extended_value & ZEND_ARG_IS_UNPACKED) == 0))) { + zend_string *name; + zval *arg; + + zend_bool cufa = (opline->extended_value & ZEND_ARG_IS_CUFA) != 0; + + unpack_array_separate(args, &ht, call, arg_num, IS_TMP_VAR); + + ZEND_HASH_FOREACH_STR_KEY_VAL(ht, name, arg) { + if (UNEXPECTED(name != NULL)) { + zend_throw_error(NULL, "Cannot unpack array with string keys"); + zval_ptr_dtor_nogc(free_op2); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + HANDLE_EXCEPTION(); + } + if (UNEXPECTED(ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num))) { + if (cufa && !Z_ISREF_P(arg)) { + if (UNEXPECTED(!ARG_MAY_BE_SENT_BY_REF(call->func, arg_num))) { + zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", + arg_num, + call->func->common.scope ? ZSTR_VAL(call->func->common.scope->name) : "", + call->func->common.scope ? "::" : "", + ZSTR_VAL(call->func->common.function_name) + ); + zval_ptr_dtor_nogc(free_op2); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + } else if (EXPECTED(!Z_IMMUTABLE_P(args))) { + ZVAL_MAKE_REF(arg); + Z_ADDREF_P(arg); + ZVAL_COPY_VALUE(ZEND_CALL_ARG(call, arg_num++), arg); + continue; + } + + ZVAL_DUP(ZEND_CALL_ARG(call, arg_num++), arg); + } else { + /* don't separate references for __call */ + if (UNEXPECTED(Z_ISREF_P(arg)) && EXPECTED((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) == 0)) { + arg = Z_REFVAL_P(arg); + } + Z_TRY_ADDREF_P(arg); + ZVAL_COPY_VALUE(ZEND_CALL_ARG(call, arg_num++), arg); + } + } ZEND_HASH_FOREACH_END(); + + zval_ptr_dtor_nogc(free_op2); + } else { + ZEND_HASH_FOREACH_VAL(ht, args) { + zval *top = ZEND_CALL_ARG(call, arg_num++); + ZVAL_COPY_VALUE(top, args); + } ZEND_HASH_FOREACH_END(); + + ZEND_ASSERT(GC_REFCOUNT(ht) == 1); + ht->pDestructor = NULL; // do not free the zvals... + zend_hash_destroy(ht); // just free the array memory + if (opline->extended_value & ZEND_ARG_IS_UNPACKED) { + efree(ht); + } + } + + ZEND_VM_TAIL_CALL(zend_do_fcall_helper_SPEC_TMP(call, fbc, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -13313,6 +13549,194 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_SPEC_TMP_VAR_ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UNPACK_FCALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op1.var); + zend_function *fbc = call->func; + uint32_t arg_num = opline->extended_value & ZEND_ARG_SEND_MASK; + uint32_t new_args; + HashTable *ht, local_ht; + + zend_free_op free_op2; + zval *args; + + SAVE_OPLINE(); + args = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + +send_again: + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { + ht = Z_ARRVAL_P(args); + } else if (EXPECTED(Z_TYPE_P(args) == IS_OBJECT)) { + zend_class_entry *ce = Z_OBJCE_P(args); + zend_object_iterator *iter; + + if (UNEXPECTED(!ce) || UNEXPECTED(!ce->get_iterator)) { + if (opline->extended_value & ZEND_ARG_IS_CUFA) { + zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array or Traversable, object%s%s given", ce ? " of type " : "", ce ? ZSTR_VAL(ce->name) : ""); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, object%s%s given", opline->extended_value & ZEND_ARG_SEND_MASK, ce ? " of type " : "", ce ? ZSTR_VAL(ce->name) : ""); + } + zval_ptr_dtor_nogc(free_op2); + if (UNEXPECTED(EG(exception) != NULL)) { + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + ZEND_VM_TAIL_CALL(ZEND_DO_FCALL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + } + + iter = ce->get_iterator(ce, args, 0); + if (UNEXPECTED(!iter)) { + zval_ptr_dtor_nogc(free_op2); + if (!EG(exception)) { + zend_throw_exception_ex(NULL, 0, "Object of type %s unpacked at parameter %d did not create an Iterator", ZSTR_VAL(ce->name), opline->extended_value & ZEND_ARG_SEND_MASK); + } + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + + ht = &local_ht; + zend_hash_init(ht, 8, pHashFunction should be killed, ZVAL_PTR_DTOR, 0); + + unpack_iterator_to_array(iter, ht, call, arg_num); + + zval_ptr_dtor_nogc(free_op2); + if (UNEXPECTED(EG(exception) != NULL)) { + zend_hash_destroy(ht); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + } else { + if ((IS_VAR & (IS_VAR|IS_CV)) && EXPECTED(Z_ISREF_P(args))) { + args = Z_REFVAL_P(args); + goto send_again; + } + if (opline->extended_value & ZEND_ARG_IS_CUFA) { + zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array or Traversable, %s given", zend_get_type_by_const(Z_TYPE_P(args))); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, %s given", opline->extended_value & ZEND_ARG_SEND_MASK, zend_get_type_by_const(Z_TYPE_P(args))); + } + zval_ptr_dtor_nogc(free_op2); + if (EG(exception)) { + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + ZEND_VM_TAIL_CALL(ZEND_DO_FCALL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + } + + if (UNEXPECTED(zend_check_abstract_or_deprecated(fbc) == 1)) { + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY) && (IS_VAR != IS_TMP_VAR || EXPECTED((opline->extended_value & ZEND_ARG_IS_UNPACKED) == 0))) { + zval_ptr_dtor_nogc(free_op2); + } else { + zend_hash_destroy(ht); + if (opline->extended_value & ZEND_ARG_IS_UNPACKED) { + efree(ht); + } + } + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + + LOAD_OPLINE(); + + new_args = zend_hash_num_elements(ht); + + if (fbc->type == ZEND_USER_FUNCTION) { + if (UNEXPECTED(((zval *)(((void *) call) + zend_vm_calc_used_stack(0, fbc))) >= EG(vm_stack_end))) { + call = zend_vm_stack_copy_call_frame(call, ZEND_CALL_NUM_ARGS(call), new_args); + } else if (new_args > ZEND_RESERVED_RECV_SLOTS || ZEND_CALL_NUM_ARGS(call) + ZEND_RESERVED_RECV_SLOTS < fbc->op_array.num_args) { + call = zend_vm_stack_extend_call_frame(call, ZEND_CALL_NUM_ARGS(call), new_args); + } + } else if (new_args > ZEND_RESERVED_RECV_SLOTS) { + call = zend_vm_stack_extend_call_frame(call, ZEND_CALL_NUM_ARGS(call), new_args); + } + + ZEND_CALL_NUM_ARGS(call) = arg_num + new_args - 1; + + /* if no previous unpack: optimization to not always duplicate the array, only for more than 1 unpack (or iterators) */ + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY) && (IS_VAR != IS_TMP_VAR || EXPECTED((opline->extended_value & ZEND_ARG_IS_UNPACKED) == 0))) { + zend_string *name; + zval *arg; + + zend_bool cufa = (opline->extended_value & ZEND_ARG_IS_CUFA) != 0; + + unpack_array_separate(args, &ht, call, arg_num, IS_VAR); + + ZEND_HASH_FOREACH_STR_KEY_VAL(ht, name, arg) { + if (UNEXPECTED(name != NULL)) { + zend_throw_error(NULL, "Cannot unpack array with string keys"); + zval_ptr_dtor_nogc(free_op2); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + HANDLE_EXCEPTION(); + } + if (UNEXPECTED(ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num))) { + if (cufa && !Z_ISREF_P(arg)) { + if (UNEXPECTED(!ARG_MAY_BE_SENT_BY_REF(call->func, arg_num))) { + zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", + arg_num, + call->func->common.scope ? ZSTR_VAL(call->func->common.scope->name) : "", + call->func->common.scope ? "::" : "", + ZSTR_VAL(call->func->common.function_name) + ); + zval_ptr_dtor_nogc(free_op2); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + } else if (EXPECTED(!Z_IMMUTABLE_P(args))) { + ZVAL_MAKE_REF(arg); + Z_ADDREF_P(arg); + ZVAL_COPY_VALUE(ZEND_CALL_ARG(call, arg_num++), arg); + continue; + } + + ZVAL_DUP(ZEND_CALL_ARG(call, arg_num++), arg); + } else { + /* don't separate references for __call */ + if (UNEXPECTED(Z_ISREF_P(arg)) && EXPECTED((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) == 0)) { + arg = Z_REFVAL_P(arg); + } + Z_TRY_ADDREF_P(arg); + ZVAL_COPY_VALUE(ZEND_CALL_ARG(call, arg_num++), arg); + } + } ZEND_HASH_FOREACH_END(); + + zval_ptr_dtor_nogc(free_op2); + } else { + ZEND_HASH_FOREACH_VAL(ht, args) { + zval *top = ZEND_CALL_ARG(call, arg_num++); + ZVAL_COPY_VALUE(top, args); + } ZEND_HASH_FOREACH_END(); + + ZEND_ASSERT(GC_REFCOUNT(ht) == 1); + ht->pDestructor = NULL; // do not free the zvals... + zend_hash_destroy(ht); // just free the array memory + if (opline->extended_value & ZEND_ARG_IS_UNPACKED) { + efree(ht); + } + } + + ZEND_VM_TAIL_CALL(zend_do_fcall_helper_SPEC_TMP(call, fbc, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -13462,7 +13886,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_UN SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); @@ -13493,7 +13917,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_UN zval_ptr_dtor_nogc(free_op1); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13866,7 +14290,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_CV SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); @@ -13897,10 +14321,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_CV zval_ptr_dtor_nogc(free_op1); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_obj_r_helper_SPEC_TMP_CV(int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE zend_free_op free_op1; @@ -13969,7 +14393,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_CV_HANDLE } while (0); zval_ptr_dtor_nogc(free_op1); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_TMP_CV(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -13977,7 +14406,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_CV USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -14008,9 +14437,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_CV EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_TAIL_CALL(ZEND_FETCH_OBJ_R_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_TMP_CV(2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } @@ -14100,6 +14529,192 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_END_SPEC_TMP_CV_HANDLER(Z ZEND_VM_NEXT_OPCODE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UNPACK_FCALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op1.var); + zend_function *fbc = call->func; + uint32_t arg_num = opline->extended_value & ZEND_ARG_SEND_MASK; + uint32_t new_args; + HashTable *ht, local_ht; + + + zval *args; + + SAVE_OPLINE(); + args = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var); + +send_again: + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { + ht = Z_ARRVAL_P(args); + } else if (EXPECTED(Z_TYPE_P(args) == IS_OBJECT)) { + zend_class_entry *ce = Z_OBJCE_P(args); + zend_object_iterator *iter; + + if (UNEXPECTED(!ce) || UNEXPECTED(!ce->get_iterator)) { + if (opline->extended_value & ZEND_ARG_IS_CUFA) { + zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array or Traversable, object%s%s given", ce ? " of type " : "", ce ? ZSTR_VAL(ce->name) : ""); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, object%s%s given", opline->extended_value & ZEND_ARG_SEND_MASK, ce ? " of type " : "", ce ? ZSTR_VAL(ce->name) : ""); + } + + if (UNEXPECTED(EG(exception) != NULL)) { + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + ZEND_VM_TAIL_CALL(ZEND_DO_FCALL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + } + + iter = ce->get_iterator(ce, args, 0); + if (UNEXPECTED(!iter)) { + + if (!EG(exception)) { + zend_throw_exception_ex(NULL, 0, "Object of type %s unpacked at parameter %d did not create an Iterator", ZSTR_VAL(ce->name), opline->extended_value & ZEND_ARG_SEND_MASK); + } + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + + ht = &local_ht; + zend_hash_init(ht, 8, pHashFunction should be killed, ZVAL_PTR_DTOR, 0); + + unpack_iterator_to_array(iter, ht, call, arg_num); + + if (UNEXPECTED(EG(exception) != NULL)) { + zend_hash_destroy(ht); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + } else { + if ((IS_CV & (IS_VAR|IS_CV)) && EXPECTED(Z_ISREF_P(args))) { + args = Z_REFVAL_P(args); + goto send_again; + } + if (opline->extended_value & ZEND_ARG_IS_CUFA) { + zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array or Traversable, %s given", zend_get_type_by_const(Z_TYPE_P(args))); + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } else { + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, %s given", opline->extended_value & ZEND_ARG_SEND_MASK, zend_get_type_by_const(Z_TYPE_P(args))); + } + + if (EG(exception)) { + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + ZEND_VM_TAIL_CALL(ZEND_DO_FCALL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + } + + if (UNEXPECTED(zend_check_abstract_or_deprecated(fbc) == 1)) { + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY) && (IS_CV != IS_TMP_VAR || EXPECTED((opline->extended_value & ZEND_ARG_IS_UNPACKED) == 0))) { + + } else { + zend_hash_destroy(ht); + if (opline->extended_value & ZEND_ARG_IS_UNPACKED) { + efree(ht); + } + } + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + HANDLE_EXCEPTION(); + } + + LOAD_OPLINE(); + + new_args = zend_hash_num_elements(ht); + + if (fbc->type == ZEND_USER_FUNCTION) { + if (UNEXPECTED(((zval *)(((void *) call) + zend_vm_calc_used_stack(0, fbc))) >= EG(vm_stack_end))) { + call = zend_vm_stack_copy_call_frame(call, ZEND_CALL_NUM_ARGS(call), new_args); + } else if (new_args > ZEND_RESERVED_RECV_SLOTS || ZEND_CALL_NUM_ARGS(call) + ZEND_RESERVED_RECV_SLOTS < fbc->op_array.num_args) { + call = zend_vm_stack_extend_call_frame(call, ZEND_CALL_NUM_ARGS(call), new_args); + } + } else if (new_args > ZEND_RESERVED_RECV_SLOTS) { + call = zend_vm_stack_extend_call_frame(call, ZEND_CALL_NUM_ARGS(call), new_args); + } + + ZEND_CALL_NUM_ARGS(call) = arg_num + new_args - 1; + + /* if no previous unpack: optimization to not always duplicate the array, only for more than 1 unpack (or iterators) */ + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY) && (IS_CV != IS_TMP_VAR || EXPECTED((opline->extended_value & ZEND_ARG_IS_UNPACKED) == 0))) { + zend_string *name; + zval *arg; + + zend_bool cufa = (opline->extended_value & ZEND_ARG_IS_CUFA) != 0; + + unpack_array_separate(args, &ht, call, arg_num, IS_CV); + + ZEND_HASH_FOREACH_STR_KEY_VAL(ht, name, arg) { + if (UNEXPECTED(name != NULL)) { + zend_throw_error(NULL, "Cannot unpack array with string keys"); + + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + HANDLE_EXCEPTION(); + } + if (UNEXPECTED(ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num))) { + if (cufa && !Z_ISREF_P(arg)) { + if (UNEXPECTED(!ARG_MAY_BE_SENT_BY_REF(call->func, arg_num))) { + zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", + arg_num, + call->func->common.scope ? ZSTR_VAL(call->func->common.scope->name) : "", + call->func->common.scope ? "::" : "", + ZSTR_VAL(call->func->common.function_name) + ); + + zend_free_args_internal(call, arg_num - 1); + cleanup_uncalled_execute_data(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + } else if (EXPECTED(!Z_IMMUTABLE_P(args))) { + ZVAL_MAKE_REF(arg); + Z_ADDREF_P(arg); + ZVAL_COPY_VALUE(ZEND_CALL_ARG(call, arg_num++), arg); + continue; + } + + ZVAL_DUP(ZEND_CALL_ARG(call, arg_num++), arg); + } else { + /* don't separate references for __call */ + if (UNEXPECTED(Z_ISREF_P(arg)) && EXPECTED((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) == 0)) { + arg = Z_REFVAL_P(arg); + } + Z_TRY_ADDREF_P(arg); + ZVAL_COPY_VALUE(ZEND_CALL_ARG(call, arg_num++), arg); + } + } ZEND_HASH_FOREACH_END(); + + } else { + ZEND_HASH_FOREACH_VAL(ht, args) { + zval *top = ZEND_CALL_ARG(call, arg_num++); + ZVAL_COPY_VALUE(top, args); + } ZEND_HASH_FOREACH_END(); + + ZEND_ASSERT(GC_REFCOUNT(ht) == 1); + ht->pDestructor = NULL; // do not free the zvals... + zend_hash_destroy(ht); // just free the array memory + if (opline->extended_value & ZEND_ARG_IS_UNPACKED) { + efree(ht); + } + } + + ZEND_VM_TAIL_CALL(zend_do_fcall_helper_SPEC_TMP(call, fbc, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -14230,6 +14845,133 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_TMP_CV_HANDLER } } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_op_array *new_op_array=NULL; + + zval *inc_filename; + zval tmp_inc_filename; + zend_bool failure_retval=0; + + SAVE_OPLINE(); + inc_filename = _get_zval_ptr_cv_undef(execute_data, opline->op2.var); + + ZVAL_UNDEF(&tmp_inc_filename); + if (Z_TYPE_P(inc_filename) != IS_STRING) { + if (IS_TMP_VAR == IS_CV && UNEXPECTED(Z_TYPE_P(inc_filename) == IS_UNDEF)) { + inc_filename = GET_OP2_UNDEF_CV(inc_filename, BP_VAR_R); + } + ZVAL_STR(&tmp_inc_filename, zval_get_string(inc_filename)); + inc_filename = &tmp_inc_filename; + } + + if (opline->extended_value != ZEND_EVAL && strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename)) { + if (opline->extended_value == ZEND_INCLUDE_ONCE || opline->extended_value == ZEND_INCLUDE) { + zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename)); + } else { + zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename)); + } + } else { + switch (opline->extended_value) { + case ZEND_INCLUDE_ONCE: + case ZEND_REQUIRE_ONCE: { + zend_file_handle file_handle; + zend_string *resolved_path; + + resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), (int)Z_STRLEN_P(inc_filename)); + if (resolved_path) { + failure_retval = zend_hash_exists(&EG(included_files), resolved_path); + } else { + resolved_path = zend_string_copy(Z_STR_P(inc_filename)); + } + + if (failure_retval) { + /* do nothing, file already included */ + } else if (SUCCESS == zend_stream_open(ZSTR_VAL(resolved_path), &file_handle)) { + + if (!file_handle.opened_path) { + file_handle.opened_path = zend_string_copy(resolved_path); + } + + if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path)) { + new_op_array = zend_compile_file(&file_handle, (opline->extended_value==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE)); + zend_destroy_file_handle(&file_handle); + } else { + zend_file_handle_dtor(&file_handle); + failure_retval=1; + } + } else { + if (opline->extended_value == ZEND_INCLUDE_ONCE) { + zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename)); + } else { + zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename)); + } + } + zend_string_release(resolved_path); + } + break; + case ZEND_INCLUDE: + case ZEND_REQUIRE: + new_op_array = compile_filename(opline->extended_value, inc_filename); + break; + case ZEND_EVAL: { + char *eval_desc = zend_make_compiled_string_description("eval()'d code"); + + new_op_array = zend_compile_string(inc_filename, eval_desc); + efree(eval_desc); + } + break; + EMPTY_SWITCH_DEFAULT_CASE() + } + } + if (Z_TYPE(tmp_inc_filename) != IS_UNDEF) { + zend_string_release(Z_STR(tmp_inc_filename)); + } + + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } else if (EXPECTED(new_op_array != NULL)) { + zval *return_value = NULL; + zend_execute_data *call = zend_push_call_frame((zend_execute_data *) EX_VAR(opline->op1.var), ZEND_CALL_NESTED_CODE, + (zend_function *) new_op_array, 0, EX(called_scope), Z_OBJ(EX(This))); + + if (RETURN_VALUE_USED(opline)) { + return_value = EX_VAR(opline->result.var); + } + + new_op_array->scope = EG(scope); + + if (EX(symbol_table)) { + call->symbol_table = EX(symbol_table); + } else { + call->symbol_table = zend_rebuild_symbol_table(); + } + + call->prev_execute_data = execute_data; + i_init_code_execute_data(call, new_op_array, return_value); + if (EXPECTED(zend_execute_ex == execute_ex)) { + ZEND_VM_ENTER(); + } else { + ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); + zend_execute_ex(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + } + + destroy_op_array(new_op_array); + efree_size(new_op_array, sizeof(zend_op_array)); + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL); + HANDLE_EXCEPTION(); + } + + } else if (RETURN_VALUE_USED(opline)) { + ZVAL_BOOL(EX_VAR(opline->result.var), failure_retval); + } + ZEND_VM_INTERRUPT_CHECK(); + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -14379,7 +15121,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_TM SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); @@ -14410,10 +15152,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_TMP_TM zval_ptr_dtor_nogc(free_op2); zval_ptr_dtor_nogc(free_op1); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_obj_r_helper_SPEC_TMP_TMPVAR(int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE zend_free_op free_op1; @@ -14483,7 +15225,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_TMPVAR_HA zval_ptr_dtor_nogc(free_op2); zval_ptr_dtor_nogc(free_op1); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_TMP_TMPVAR(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14491,7 +15238,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_TM USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -14522,9 +15269,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_TM EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_TAIL_CALL(ZEND_FETCH_OBJ_R_SPEC_TMP_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_TMP_TMPVAR(2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } @@ -14744,6 +15491,133 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_TMP_TMPVAR_HAN } } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMP_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_op_array *new_op_array=NULL; + zend_free_op free_op2; + zval *inc_filename; + zval tmp_inc_filename; + zend_bool failure_retval=0; + + SAVE_OPLINE(); + inc_filename = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + + ZVAL_UNDEF(&tmp_inc_filename); + if (Z_TYPE_P(inc_filename) != IS_STRING) { + if (IS_TMP_VAR == IS_CV && UNEXPECTED(Z_TYPE_P(inc_filename) == IS_UNDEF)) { + inc_filename = GET_OP2_UNDEF_CV(inc_filename, BP_VAR_R); + } + ZVAL_STR(&tmp_inc_filename, zval_get_string(inc_filename)); + inc_filename = &tmp_inc_filename; + } + + if (opline->extended_value != ZEND_EVAL && strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename)) { + if (opline->extended_value == ZEND_INCLUDE_ONCE || opline->extended_value == ZEND_INCLUDE) { + zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename)); + } else { + zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename)); + } + } else { + switch (opline->extended_value) { + case ZEND_INCLUDE_ONCE: + case ZEND_REQUIRE_ONCE: { + zend_file_handle file_handle; + zend_string *resolved_path; + + resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), (int)Z_STRLEN_P(inc_filename)); + if (resolved_path) { + failure_retval = zend_hash_exists(&EG(included_files), resolved_path); + } else { + resolved_path = zend_string_copy(Z_STR_P(inc_filename)); + } + + if (failure_retval) { + /* do nothing, file already included */ + } else if (SUCCESS == zend_stream_open(ZSTR_VAL(resolved_path), &file_handle)) { + + if (!file_handle.opened_path) { + file_handle.opened_path = zend_string_copy(resolved_path); + } + + if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path)) { + new_op_array = zend_compile_file(&file_handle, (opline->extended_value==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE)); + zend_destroy_file_handle(&file_handle); + } else { + zend_file_handle_dtor(&file_handle); + failure_retval=1; + } + } else { + if (opline->extended_value == ZEND_INCLUDE_ONCE) { + zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename)); + } else { + zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename)); + } + } + zend_string_release(resolved_path); + } + break; + case ZEND_INCLUDE: + case ZEND_REQUIRE: + new_op_array = compile_filename(opline->extended_value, inc_filename); + break; + case ZEND_EVAL: { + char *eval_desc = zend_make_compiled_string_description("eval()'d code"); + + new_op_array = zend_compile_string(inc_filename, eval_desc); + efree(eval_desc); + } + break; + EMPTY_SWITCH_DEFAULT_CASE() + } + } + if (Z_TYPE(tmp_inc_filename) != IS_UNDEF) { + zend_string_release(Z_STR(tmp_inc_filename)); + } + zval_ptr_dtor_nogc(free_op2); + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } else if (EXPECTED(new_op_array != NULL)) { + zval *return_value = NULL; + zend_execute_data *call = zend_push_call_frame((zend_execute_data *) EX_VAR(opline->op1.var), ZEND_CALL_NESTED_CODE, + (zend_function *) new_op_array, 0, EX(called_scope), Z_OBJ(EX(This))); + + if (RETURN_VALUE_USED(opline)) { + return_value = EX_VAR(opline->result.var); + } + + new_op_array->scope = EG(scope); + + if (EX(symbol_table)) { + call->symbol_table = EX(symbol_table); + } else { + call->symbol_table = zend_rebuild_symbol_table(); + } + + call->prev_execute_data = execute_data; + i_init_code_execute_data(call, new_op_array, return_value); + if (EXPECTED(zend_execute_ex == execute_ex)) { + ZEND_VM_ENTER(); + } else { + ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); + zend_execute_ex(call); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(call)); + } + + destroy_op_array(new_op_array); + efree_size(new_op_array, sizeof(zend_op_array)); + if (UNEXPECTED(EG(exception) != NULL)) { + zend_throw_exception_internal(NULL); + HANDLE_EXCEPTION(); + } + + } else if (RETURN_VALUE_USED(opline)) { + ZVAL_BOOL(EX_VAR(opline->result.var), failure_retval); + } + ZEND_VM_INTERRUPT_CHECK(); + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -15111,221 +15985,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_THROW_SPEC_VAR_HANDLER(ZEND_OP HANDLE_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval *varptr, *arg; - zend_free_op free_op1; - - varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); - if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(varptr) == IS_UNDEF)) { - SAVE_OPLINE(); - GET_OP1_UNDEF_CV(varptr, BP_VAR_R); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_NULL(arg); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); - } - - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - - if (IS_VAR == IS_CV) { - ZVAL_OPT_DEREF(varptr); - ZVAL_COPY(arg, varptr); - } else /* if (IS_VAR == IS_VAR) */ { - if (UNEXPECTED(Z_ISREF_P(varptr))) { - zend_refcounted *ref = Z_COUNTED_P(varptr); - - varptr = Z_REFVAL_P(varptr); - ZVAL_COPY_VALUE(arg, varptr); - if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { - efree_size(ref, sizeof(zend_reference)); - } else if (Z_OPT_REFCOUNTED_P(arg)) { - Z_ADDREF_P(arg); - } - } else { - ZVAL_COPY_VALUE(arg, varptr); - } - } - - ZEND_VM_NEXT_OPCODE(); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_free_op free_op1; - zval *varptr, *arg; - - if (!(opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND)) { - if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { - ZEND_VM_TAIL_CALL(ZEND_SEND_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); - } - } - - varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); - - if ((!(opline->extended_value & ZEND_ARG_SEND_FUNCTION) || - (Z_VAR_FLAGS_P(varptr) & IS_VAR_RET_REF)) && - (Z_ISREF_P(varptr) || Z_TYPE_P(varptr) == IS_OBJECT)) { - - ZVAL_MAKE_REF(varptr); - } else { - if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? - !(opline->extended_value & ZEND_ARG_SEND_SILENT) : - !ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { - SAVE_OPLINE(); - zend_error(E_NOTICE, "Only variables should be passed by reference"); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_COPY_VALUE(arg, varptr); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); - } - } - - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_COPY_VALUE(arg, varptr); - - ZEND_VM_NEXT_OPCODE(); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_free_op free_op1; - zval *varptr, *arg; - - SAVE_OPLINE(); - varptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1); - - if (IS_VAR == IS_VAR && UNEXPECTED(varptr == NULL)) { - zend_throw_error(NULL, "Only variables can be passed by reference"); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_UNDEF(arg); - HANDLE_EXCEPTION(); - } - - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - if (IS_VAR == IS_VAR && UNEXPECTED(varptr == &EG(error_zval))) { - ZVAL_NEW_REF(arg, &EG(uninitialized_zval)); - ZEND_VM_NEXT_OPCODE(); - } - - if (Z_ISREF_P(varptr)) { - Z_ADDREF_P(varptr); - ZVAL_COPY_VALUE(arg, varptr); - } else { - ZVAL_NEW_REF(arg, varptr); - Z_ADDREF_P(arg); - ZVAL_REF(varptr, Z_REF_P(arg)); - } - - if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);}; - ZEND_VM_NEXT_OPCODE(); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval *varptr, *arg; - zend_free_op free_op1; - uint32_t arg_num = opline->op2.num; - - if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) { - if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { - goto send_var_by_ref; - } - } else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { -send_var_by_ref: - ZEND_VM_TAIL_CALL(ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); - } - - varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); - if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(varptr) == IS_UNDEF)) { - SAVE_OPLINE(); - GET_OP1_UNDEF_CV(varptr, BP_VAR_R); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_NULL(arg); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); - } - - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - - if (IS_VAR == IS_CV) { - ZVAL_OPT_DEREF(varptr); - ZVAL_COPY(arg, varptr); - } else /* if (IS_VAR == IS_VAR) */ { - if (UNEXPECTED(Z_ISREF_P(varptr))) { - zend_refcounted *ref = Z_COUNTED_P(varptr); - - varptr = Z_REFVAL_P(varptr); - ZVAL_COPY_VALUE(arg, varptr); - if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { - efree_size(ref, sizeof(zend_reference)); - } else if (Z_OPT_REFCOUNTED_P(arg)) { - Z_ADDREF_P(arg); - } - } else { - ZVAL_COPY_VALUE(arg, varptr); - } - } - - ZEND_VM_NEXT_OPCODE(); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval *arg, *param; - zend_free_op free_op1; - - SAVE_OPLINE(); - arg = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); - param = ZEND_CALL_VAR(EX(call), opline->result.var); - - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { - if (UNEXPECTED(!Z_ISREF_P(arg))) { - - if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { - - zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", - opline->op2.num, - EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", - EX(call)->func->common.scope ? "::" : "", - ZSTR_VAL(EX(call)->func->common.function_name)); - - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); - } - if (Z_OBJ(EX(call)->This)) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); - } - ZVAL_UNDEF(param); - EX(call)->func = (zend_function*)&zend_pass_function; - EX(call)->called_scope = NULL; - Z_OBJ(EX(call)->This) = NULL; - - zval_ptr_dtor_nogc(free_op1); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); - } - - ZVAL_NEW_REF(arg, arg); - } - Z_ADDREF_P(arg); - } else { - if (Z_ISREF_P(arg) && - !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { - /* don't separate references for __call */ - arg = Z_REFVAL_P(arg); - } - if (Z_OPT_REFCOUNTED_P(arg)) { - Z_ADDREF_P(arg); - } - } - ZVAL_COPY_VALUE(param, arg); - - zval_ptr_dtor_nogc(free_op1); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -15366,15 +16025,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_VAR_HANDLER(ZEND_OPCO ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } else { /* We are not handling overloaded classes right now */ - zend_execute_data *call = zend_vm_stack_push_call_frame( - ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR | - (EXPECTED(RETURN_VALUE_USED(opline)) ? 0 : ZEND_CALL_CTOR_RESULT_UNUSED), + zend_init_call_frame((zend_execute_data *) EX_VAR((OP_JMP_ADDR(opline, opline->op2) - 1)->op1.var), /* maybe find a better way to access this, but we only have 3 uint32_t's for each opcode ... */ + ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR | (EXPECTED(RETURN_VALUE_USED(opline)) ? 0 : ZEND_CALL_CTOR_RESULT_UNUSED), constructor, opline->extended_value, ce, Z_OBJ(object_zval)); - call->prev_execute_data = EX(call); - EX(call) = call; if (EXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), &object_zval); @@ -17019,7 +17675,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_CO SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); @@ -17050,7 +17706,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_CO zval_ptr_dtor_nogc(free_op1); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -17076,7 +17732,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_VAR_CONST ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_obj_r_helper_SPEC_VAR_CONST(int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE zend_free_op free_op1; @@ -17145,7 +17801,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_VAR_CONST_HAN } while (0); zval_ptr_dtor_nogc(free_op1); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_VAR_CONST(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -17214,7 +17875,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_CO USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -17245,9 +17906,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_CO EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);}; - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_TAIL_CALL(ZEND_FETCH_OBJ_R_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_VAR_CONST(2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } @@ -17453,7 +18114,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V zend_class_entry *ce; zend_object *object; zend_function *fbc; - zend_execute_data *call; SAVE_OPLINE(); @@ -17579,10 +18239,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V } } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, ce, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -18146,6 +18804,293 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_TMP_HANDLER(ZE ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *varptr, *arg; + zend_free_op free_op1; + + varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(varptr) == IS_UNDEF)) { + SAVE_OPLINE(); + GET_OP1_UNDEF_CV(varptr, BP_VAR_R); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + + arg = EX_VAR(opline->result.var); + if (IS_VAR == IS_CV) { + ZVAL_OPT_DEREF(varptr); + ZVAL_COPY(arg, varptr); + } else /* if (IS_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(varptr))) { + zend_refcounted *ref = Z_COUNTED_P(varptr); + + varptr = Z_REFVAL_P(varptr); + ZVAL_COPY_VALUE(arg, varptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(arg)) { + Z_ADDREF_P(arg); + } + } else { + ZVAL_COPY_VALUE(arg, varptr); + } + } + + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *varptr; + + if (!(opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND)) { + if (!ARG_SHOULD_BE_SENT_BY_REF(((zend_execute_data *) EX_VAR(opline->op2.var))->func, opline->extended_value & ZEND_ARG_SEND_MASK)) { + ZEND_VM_TAIL_CALL(ZEND_SEND_VAR_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + } + } + + varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + + if ((!(opline->extended_value & ZEND_ARG_SEND_FUNCTION) || + (Z_VAR_FLAGS_P(varptr) & IS_VAR_RET_REF)) && + (Z_ISREF_P(varptr) || Z_TYPE_P(varptr) == IS_OBJECT)) { + + ZVAL_MAKE_REF(varptr); + } else { + if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? + !(opline->extended_value & ZEND_ARG_SEND_SILENT) : + !ARG_MAY_BE_SENT_BY_REF(((zend_execute_data *) EX_VAR(opline->op2.var))->func, opline->extended_value & ZEND_ARG_SEND_MASK)) { + SAVE_OPLINE(); + zend_error(E_NOTICE, "Only variables should be passed by reference"); + ZVAL_COPY_VALUE(EX_VAR(opline->result.var), varptr); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + } + + ZVAL_COPY_VALUE(EX_VAR(opline->result.var), varptr); + + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_REF_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *varptr, *arg = EX_VAR(opline->result.var); + + SAVE_OPLINE(); + varptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1); + + if (IS_VAR == IS_VAR && UNEXPECTED(varptr == NULL)) { + zend_throw_error(NULL, "Only variables can be passed by reference"); + ZVAL_UNDEF(arg); + HANDLE_EXCEPTION(); + } + + if (IS_VAR == IS_VAR && UNEXPECTED(varptr == &EG(error_zval))) { + ZVAL_NEW_REF(arg, &EG(uninitialized_zval)); + ZEND_VM_NEXT_OPCODE(); + } + + if (Z_ISREF_P(varptr)) { + Z_ADDREF_P(varptr); + ZVAL_COPY_VALUE(arg, varptr); + } else { + ZVAL_NEW_REF(arg, varptr); + Z_ADDREF_P(arg); + ZVAL_REF(varptr, Z_REF_P(arg)); + } + + if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);}; + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *varptr, *arg; + zend_free_op free_op1; + uint32_t arg_num = opline->extended_value; + zend_function *fbc = ((zend_execute_data *) EX_VAR(opline->op2.var))->func; + + if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) { + if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num)) { + goto send_var_by_ref; + } + } else if (ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num)) { +send_var_by_ref: + ZEND_VM_TAIL_CALL(ZEND_SEND_REF_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + } + + varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(varptr) == IS_UNDEF)) { + SAVE_OPLINE(); + GET_OP1_UNDEF_CV(varptr, BP_VAR_R); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + + arg = EX_VAR(opline->result.var); + if (IS_VAR == IS_CV) { + ZVAL_OPT_DEREF(varptr); + ZVAL_COPY(arg, varptr); + } else /* if (IS_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(varptr))) { + zend_refcounted *ref = Z_COUNTED_P(varptr); + + varptr = Z_REFVAL_P(varptr); + ZVAL_COPY_VALUE(arg, varptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(arg)) { + Z_ADDREF_P(arg); + } + } else { + ZVAL_COPY_VALUE(arg, varptr); + } + } + + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *args; + int arg_num = opline->extended_value & ZEND_ARG_SEND_MASK; + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op2.var); + HashTable *ht; + + SAVE_OPLINE(); + if (UNEXPECTED(!(opline->extended_value & ZEND_ARG_IS_UNPACKED))) { + array_init(EX_VAR(opline->result.var)); + } + ht = Z_ARRVAL_P(EX_VAR(opline->result.var)); + args = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + +send_again: + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { + zend_string *name; + zval *arg; + HashTable *arg_ht = Z_ARRVAL_P(args); + arg_num += zend_hash_num_elements(ht); + unpack_array_separate(args, &arg_ht, call, arg_num, IS_VAR); + + ZEND_HASH_FOREACH_STR_KEY_VAL(arg_ht, name, arg) { + if (UNEXPECTED(name != NULL)) { + zend_throw_error(NULL, "Cannot unpack array with string keys"); + zval_ptr_dtor_nogc(free_op1); + HANDLE_EXCEPTION(); + } + + if (ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num++)) { + if (!Z_IMMUTABLE_P(args)) { + ZVAL_MAKE_REF(arg); + Z_ADDREF_P(arg); + zend_hash_next_index_insert(ht, arg); + } else { + zval copy; + ZVAL_DUP(©, arg); + zend_hash_next_index_insert(ht, ©); + } + } else { + /* don't separate references for __call */ + if (UNEXPECTED(Z_ISREF_P(arg)) && EXPECTED((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) == 0)) { + arg = Z_REFVAL_P(arg); + } + Z_TRY_ADDREF_P(arg); + zend_hash_next_index_insert(ht, arg); + } + } ZEND_HASH_FOREACH_END(); + } else if (EXPECTED(Z_TYPE_P(args) == IS_OBJECT)) { + zend_class_entry *ce = Z_OBJCE_P(args); + zend_object_iterator *iter; + + if (!ce || !ce->get_iterator) { + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, object%s%s given", opline->extended_value & ZEND_ARG_SEND_MASK, ce ? " of type " : "", ce ? ZSTR_VAL(ce->name) : ""); + } else { + iter = ce->get_iterator(ce, args, 0); + if (UNEXPECTED(!iter)) { + zval_ptr_dtor_nogc(free_op1); + if (!EG(exception)) { + zend_throw_exception_ex(NULL, 0, "Object of type %s unpacked at parameter %d did not create an Iterator", ZSTR_VAL(ce->name), opline->extended_value & ZEND_ARG_SEND_MASK); + } + HANDLE_EXCEPTION(); + } + unpack_iterator_to_array(iter, ht, call, arg_num + zend_hash_num_elements(ht)); + } + } else if (EXPECTED(Z_ISREF_P(args))) { + args = Z_REFVAL_P(args); + goto send_again; + } else { + if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_P(args) == IS_UNDEF)) { + GET_OP1_UNDEF_CV(args, BP_VAR_R); + } + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, %s given", opline->extended_value & ZEND_ARG_SEND_MASK, zend_get_type_by_const(Z_TYPE_P(args))); + } + + zval_ptr_dtor_nogc(free_op1); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *arg, *param = EX_VAR(opline->result.var); + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op2.var); + zend_free_op free_op1; + + SAVE_OPLINE(); + arg = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + + if (ARG_SHOULD_BE_SENT_BY_REF(call->func, opline->extended_value)) { + if (UNEXPECTED(!Z_ISREF_P(arg))) { + if (!ARG_MAY_BE_SENT_BY_REF(call->func, opline->extended_value)) { + zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", + opline->extended_value, + call->func->common.scope ? ZSTR_VAL(call->func->common.scope->name) : "", + call->func->common.scope ? "::" : "", + ZSTR_VAL(call->func->common.function_name)); + + if (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE) { + OBJ_RELEASE((zend_object *) call->func->common.prototype); + } + if (Z_OBJ(call->This)) { + OBJ_RELEASE(Z_OBJ(call->This)); + } + ZVAL_UNDEF(param); + call->func = (zend_function*)&zend_pass_function; + call->called_scope = NULL; + Z_OBJ(call->This) = NULL; + + zval_ptr_dtor_nogc(free_op1); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + + ZVAL_NEW_REF(arg, arg); + } + Z_ADDREF_P(arg); + } else { + if (Z_ISREF_P(arg) && + !(call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + /* don't separate references for __call */ + arg = Z_REFVAL_P(arg); + } + if (Z_OPT_REFCOUNTED_P(arg)) { + Z_ADDREF_P(arg); + } + } + ZVAL_COPY_VALUE(param, arg); + + zval_ptr_dtor_nogc(free_op1); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -18916,7 +19861,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_UN SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); @@ -18947,7 +19892,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_UN zval_ptr_dtor_nogc(free_op1); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -19063,7 +20008,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V zend_class_entry *ce; zend_object *object; zend_function *fbc; - zend_execute_data *call; SAVE_OPLINE(); @@ -19189,10 +20133,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V } } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, ce, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -20196,7 +21138,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_CV SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); @@ -20227,7 +21169,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_CV zval_ptr_dtor_nogc(free_op1); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -20253,7 +21195,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_VAR_CV_HA ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_obj_r_helper_SPEC_VAR_CV(int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE zend_free_op free_op1; @@ -20322,7 +21264,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_VAR_CV_HANDLE } while (0); zval_ptr_dtor_nogc(free_op1); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_VAR_CV(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -20391,7 +21338,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_CV USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -20422,9 +21369,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_CV EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);}; - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_TAIL_CALL(ZEND_FETCH_OBJ_R_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_VAR_CV(2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } @@ -20689,7 +21636,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V zend_class_entry *ce; zend_object *object; zend_function *fbc; - zend_execute_data *call; SAVE_OPLINE(); @@ -20815,10 +21761,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V } } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, ce, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -21859,7 +22803,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_TM SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); @@ -21890,7 +22834,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_TM zval_ptr_dtor_nogc(free_op2); zval_ptr_dtor_nogc(free_op1); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_VAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -21916,7 +22860,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_VAR_TMPVA ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_VAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_obj_r_helper_SPEC_VAR_TMPVAR(int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE zend_free_op free_op1; @@ -21986,7 +22930,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_VAR_TMPVAR_HA zval_ptr_dtor_nogc(free_op2); zval_ptr_dtor_nogc(free_op1); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_VAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_VAR_TMPVAR(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_VAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -22055,7 +23004,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_TM USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -22086,9 +23035,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_TM EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);}; - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_TAIL_CALL(ZEND_FETCH_OBJ_R_SPEC_VAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_VAR_TMPVAR(2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } @@ -22266,7 +23215,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V zend_class_entry *ce; zend_object *object; zend_function *fbc; - zend_execute_data *call; SAVE_OPLINE(); @@ -22392,10 +23340,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V } } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, ce, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -22713,15 +23659,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_UNUSED_HANDLER(ZEND_O ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } else { /* We are not handling overloaded classes right now */ - zend_execute_data *call = zend_vm_stack_push_call_frame( - ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR | - (EXPECTED(RETURN_VALUE_USED(opline)) ? 0 : ZEND_CALL_CTOR_RESULT_UNUSED), + zend_init_call_frame((zend_execute_data *) EX_VAR((OP_JMP_ADDR(opline, opline->op2) - 1)->op1.var), /* maybe find a better way to access this, but we only have 3 uint32_t's for each opcode ... */ + ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR | (EXPECTED(RETURN_VALUE_USED(opline)) ? 0 : ZEND_CALL_CTOR_RESULT_UNUSED), constructor, opline->extended_value, ce, Z_OBJ(object_zval)); - call->prev_execute_data = EX(call); - EX(call) = call; if (EXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), &object_zval); @@ -23366,7 +24309,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_DEC_OBJ_SPEC_UNUSED_CONST ZEND_VM_TAIL_CALL(zend_post_incdec_property_helper_SPEC_UNUSED_CONST(0 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_obj_r_helper_SPEC_UNUSED_CONST(int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -23435,7 +24378,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_UNUSED_CONST_ } while (0); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_UNUSED_CONST(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -23576,7 +24524,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -23607,9 +24555,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_TAIL_CALL(ZEND_FETCH_OBJ_R_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_UNUSED_CONST(2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } @@ -23716,7 +24664,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_C zend_function *fbc; zend_class_entry *called_scope; zend_object *obj; - zend_execute_data *call; uint32_t call_info; SAVE_OPLINE(); @@ -23817,10 +24764,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_C GC_REFCOUNT(obj)++; /* For $this pointer */ } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, obj); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -23833,7 +24778,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U zend_class_entry *ce; zend_object *object; zend_function *fbc; - zend_execute_data *call; SAVE_OPLINE(); @@ -23959,10 +24903,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U } } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, ce, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -25188,7 +26130,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U zend_class_entry *ce; zend_object *object; zend_function *fbc; - zend_execute_data *call; SAVE_OPLINE(); @@ -25314,10 +26255,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U } } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, ce, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -26080,7 +27019,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_DEC_OBJ_SPEC_UNUSED_CV_HA ZEND_VM_TAIL_CALL(zend_post_incdec_property_helper_SPEC_UNUSED_CV(0 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_obj_r_helper_SPEC_UNUSED_CV(int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -26149,7 +27088,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_UNUSED_CV_HAN } while (0); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_UNUSED_CV(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -26290,7 +27234,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -26321,9 +27265,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_TAIL_CALL(ZEND_FETCH_OBJ_R_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_UNUSED_CV(2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } @@ -26430,7 +27374,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_C zend_function *fbc; zend_class_entry *called_scope; zend_object *obj; - zend_execute_data *call; uint32_t call_info; SAVE_OPLINE(); @@ -26531,10 +27474,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_C GC_REFCOUNT(obj)++; /* For $this pointer */ } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, obj); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -26547,7 +27488,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U zend_class_entry *ce; zend_object *object; zend_function *fbc; - zend_execute_data *call; SAVE_OPLINE(); @@ -26673,10 +27613,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U } } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, ce, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -27711,7 +28649,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_DEC_OBJ_SPEC_UNUSED_TMPVA ZEND_VM_TAIL_CALL(zend_post_incdec_property_helper_SPEC_UNUSED_TMPVAR(0 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_UNUSED_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_obj_r_helper_SPEC_UNUSED_TMPVAR(int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -27781,7 +28719,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_UNUSED_TMPVAR zval_ptr_dtor_nogc(free_op2); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_UNUSED_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_UNUSED_TMPVAR(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_UNUSED_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -27923,7 +28866,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -27954,9 +28897,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_TAIL_CALL(ZEND_FETCH_OBJ_R_SPEC_UNUSED_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_UNUSED_TMPVAR(2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } @@ -28063,7 +29006,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_T zend_function *fbc; zend_class_entry *called_scope; zend_object *obj; - zend_execute_data *call; uint32_t call_info; SAVE_OPLINE(); @@ -28164,10 +29106,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_T GC_REFCOUNT(obj)++; /* For $this pointer */ } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, obj); - call->prev_execute_data = EX(call); - EX(call) = call; zval_ptr_dtor_nogc(free_op2); @@ -28181,7 +29121,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U zend_class_entry *ce; zend_object *object; zend_function *fbc; - zend_execute_data *call; SAVE_OPLINE(); @@ -28307,10 +29246,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U } } - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, ce, object); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -28905,6 +29842,100 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ECHO_SPEC_CV_HANDLER(ZEND_OPCO ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CV(int type ZEND_OPCODE_HANDLER_ARGS_DC) +{ + USE_OPLINE + + zval *varname; + zval *retval; + zend_string *name; + HashTable *target_symbol_table; + + SAVE_OPLINE(); + varname = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + + if (IS_CV == IS_CONST) { + name = Z_STR_P(varname); + } else if (EXPECTED(Z_TYPE_P(varname) == IS_STRING)) { + name = Z_STR_P(varname); + zend_string_addref(name); + } else { + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) { + GET_OP1_UNDEF_CV(varname, BP_VAR_R); + } + name = zval_get_string(varname); + } + + target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK); + retval = zend_hash_find(target_symbol_table, name); + if (retval == NULL) { + switch (type) { + case BP_VAR_R: + case BP_VAR_UNSET: + zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); + /* break missing intentionally */ + case BP_VAR_IS: + retval = &EG(uninitialized_zval); + break; + case BP_VAR_RW: + zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); + retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval)); + break; + case BP_VAR_W: + retval = zend_hash_add_new(target_symbol_table, name, &EG(uninitialized_zval)); + break; + EMPTY_SWITCH_DEFAULT_CASE() + } + /* GLOBAL or $$name variable may be an INDIRECT pointer to CV */ + } else if (Z_TYPE_P(retval) == IS_INDIRECT) { + retval = Z_INDIRECT_P(retval); + if (Z_TYPE_P(retval) == IS_UNDEF) { + switch (type) { + case BP_VAR_R: + case BP_VAR_UNSET: + zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); + /* break missing intentionally */ + case BP_VAR_IS: + retval = &EG(uninitialized_zval); + break; + case BP_VAR_RW: + zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); + /* break missing intentionally */ + case BP_VAR_W: + ZVAL_NULL(retval); + break; + EMPTY_SWITCH_DEFAULT_CASE() + } + } + } + + 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 (IS_CV != IS_CONST) { + zend_string_release(name); + } + + ZEND_ASSERT(retval != NULL); + if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } else { + ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMPZ_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -29290,181 +30321,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_THROW_SPEC_CV_HANDLER(ZEND_OPC HANDLE_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval *varptr, *arg; - - - varptr = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); - if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(varptr) == IS_UNDEF)) { - SAVE_OPLINE(); - GET_OP1_UNDEF_CV(varptr, BP_VAR_R); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_NULL(arg); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); - } - - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - - if (IS_CV == IS_CV) { - ZVAL_OPT_DEREF(varptr); - ZVAL_COPY(arg, varptr); - } else /* if (IS_CV == IS_VAR) */ { - if (UNEXPECTED(Z_ISREF_P(varptr))) { - zend_refcounted *ref = Z_COUNTED_P(varptr); - - varptr = Z_REFVAL_P(varptr); - ZVAL_COPY_VALUE(arg, varptr); - if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { - efree_size(ref, sizeof(zend_reference)); - } else if (Z_OPT_REFCOUNTED_P(arg)) { - Z_ADDREF_P(arg); - } - } else { - ZVAL_COPY_VALUE(arg, varptr); - } - } - - ZEND_VM_NEXT_OPCODE(); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - - zval *varptr, *arg; - - SAVE_OPLINE(); - varptr = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var); - - if (IS_CV == IS_VAR && UNEXPECTED(varptr == NULL)) { - zend_throw_error(NULL, "Only variables can be passed by reference"); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_UNDEF(arg); - HANDLE_EXCEPTION(); - } - - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - if (IS_CV == IS_VAR && UNEXPECTED(varptr == &EG(error_zval))) { - ZVAL_NEW_REF(arg, &EG(uninitialized_zval)); - ZEND_VM_NEXT_OPCODE(); - } - - if (Z_ISREF_P(varptr)) { - Z_ADDREF_P(varptr); - ZVAL_COPY_VALUE(arg, varptr); - } else { - ZVAL_NEW_REF(arg, varptr); - Z_ADDREF_P(arg); - ZVAL_REF(varptr, Z_REF_P(arg)); - } - - ZEND_VM_NEXT_OPCODE(); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval *varptr, *arg; - - uint32_t arg_num = opline->op2.num; - - if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) { - if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { - goto send_var_by_ref; - } - } else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { -send_var_by_ref: - ZEND_VM_TAIL_CALL(ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); - } - - varptr = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); - if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(varptr) == IS_UNDEF)) { - SAVE_OPLINE(); - GET_OP1_UNDEF_CV(varptr, BP_VAR_R); - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - ZVAL_NULL(arg); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); - } - - arg = ZEND_CALL_VAR(EX(call), opline->result.var); - - if (IS_CV == IS_CV) { - ZVAL_OPT_DEREF(varptr); - ZVAL_COPY(arg, varptr); - } else /* if (IS_CV == IS_VAR) */ { - if (UNEXPECTED(Z_ISREF_P(varptr))) { - zend_refcounted *ref = Z_COUNTED_P(varptr); - - varptr = Z_REFVAL_P(varptr); - ZVAL_COPY_VALUE(arg, varptr); - if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { - efree_size(ref, sizeof(zend_reference)); - } else if (Z_OPT_REFCOUNTED_P(arg)) { - Z_ADDREF_P(arg); - } - } else { - ZVAL_COPY_VALUE(arg, varptr); - } - } - - ZEND_VM_NEXT_OPCODE(); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval *arg, *param; - - - SAVE_OPLINE(); - arg = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var); - param = ZEND_CALL_VAR(EX(call), opline->result.var); - - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { - if (UNEXPECTED(!Z_ISREF_P(arg))) { - - if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { - - zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", - opline->op2.num, - EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "", - EX(call)->func->common.scope ? "::" : "", - ZSTR_VAL(EX(call)->func->common.function_name)); - - if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) { - OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype); - } - if (Z_OBJ(EX(call)->This)) { - OBJ_RELEASE(Z_OBJ(EX(call)->This)); - } - ZVAL_UNDEF(param); - EX(call)->func = (zend_function*)&zend_pass_function; - EX(call)->called_scope = NULL; - Z_OBJ(EX(call)->This) = NULL; - - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); - } - - ZVAL_NEW_REF(arg, arg); - } - Z_ADDREF_P(arg); - } else { - if (Z_ISREF_P(arg) && - !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { - /* don't separate references for __call */ - arg = Z_REFVAL_P(arg); - } - if (Z_OPT_REFCOUNTED_P(arg)) { - Z_ADDREF_P(arg); - } - } - ZVAL_COPY_VALUE(param, arg); - - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BOOL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -29665,135 +30521,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCO ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_op_array *new_op_array=NULL; - - zval *inc_filename; - zval tmp_inc_filename; - zend_bool failure_retval=0; - - SAVE_OPLINE(); - inc_filename = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); - - ZVAL_UNDEF(&tmp_inc_filename); - if (Z_TYPE_P(inc_filename) != IS_STRING) { - if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(inc_filename) == IS_UNDEF)) { - inc_filename = GET_OP1_UNDEF_CV(inc_filename, BP_VAR_R); - } - ZVAL_STR(&tmp_inc_filename, zval_get_string(inc_filename)); - inc_filename = &tmp_inc_filename; - } - - if (opline->extended_value != ZEND_EVAL && strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename)) { - if (opline->extended_value == ZEND_INCLUDE_ONCE || opline->extended_value == ZEND_INCLUDE) { - zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename)); - } else { - zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename)); - } - } else { - switch (opline->extended_value) { - case ZEND_INCLUDE_ONCE: - case ZEND_REQUIRE_ONCE: { - zend_file_handle file_handle; - zend_string *resolved_path; - - resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), (int)Z_STRLEN_P(inc_filename)); - if (resolved_path) { - failure_retval = zend_hash_exists(&EG(included_files), resolved_path); - } else { - resolved_path = zend_string_copy(Z_STR_P(inc_filename)); - } - - if (failure_retval) { - /* do nothing, file already included */ - } else if (SUCCESS == zend_stream_open(ZSTR_VAL(resolved_path), &file_handle)) { - - if (!file_handle.opened_path) { - file_handle.opened_path = zend_string_copy(resolved_path); - } - - if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path)) { - new_op_array = zend_compile_file(&file_handle, (opline->extended_value==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE)); - zend_destroy_file_handle(&file_handle); - } else { - zend_file_handle_dtor(&file_handle); - failure_retval=1; - } - } else { - if (opline->extended_value == ZEND_INCLUDE_ONCE) { - zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename)); - } else { - zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename)); - } - } - zend_string_release(resolved_path); - } - break; - case ZEND_INCLUDE: - case ZEND_REQUIRE: - new_op_array = compile_filename(opline->extended_value, inc_filename); - break; - case ZEND_EVAL: { - char *eval_desc = zend_make_compiled_string_description("eval()'d code"); - - new_op_array = zend_compile_string(inc_filename, eval_desc); - efree(eval_desc); - } - break; - EMPTY_SWITCH_DEFAULT_CASE() - } - } - if (Z_TYPE(tmp_inc_filename) != IS_UNDEF) { - zend_string_release(Z_STR(tmp_inc_filename)); - } - - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); - } else if (EXPECTED(new_op_array != NULL)) { - zval *return_value = NULL; - zend_execute_data *call; - - if (RETURN_VALUE_USED(opline)) { - return_value = EX_VAR(opline->result.var); - } - - new_op_array->scope = EG(scope); - - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_CODE, - (zend_function*)new_op_array, 0, EX(called_scope), Z_OBJ(EX(This))); - - if (EX(symbol_table)) { - call->symbol_table = EX(symbol_table); - } else { - call->symbol_table = zend_rebuild_symbol_table(); - } - - call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value); - if (EXPECTED(zend_execute_ex == execute_ex)) { - ZEND_VM_ENTER(); - } else { - ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); - zend_execute_ex(call); - zend_vm_stack_free_call_frame(call); - } - - destroy_op_array(new_op_array); - efree_size(new_op_array, sizeof(zend_op_array)); - if (UNEXPECTED(EG(exception) != NULL)) { - zend_throw_exception_internal(NULL); - HANDLE_EXCEPTION(); - } - - } else if (RETURN_VALUE_USED(opline)) { - ZVAL_BOOL(EX_VAR(opline->result.var), failure_retval); - } - ZEND_VM_INTERRUPT_CHECK(); - ZEND_VM_NEXT_OPCODE(); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -31568,7 +32295,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_DEC_OBJ_SPEC_CV_CONST_HAN ZEND_VM_TAIL_CALL(zend_post_incdec_property_helper_SPEC_CV_CONST(0 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_CV_CONST(int type ZEND_OPCODE_HANDLER_ARGS_DC) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_CV_CONST(int type, int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -31668,43 +32395,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_ } else { ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_R_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_CONST(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_CONST(BP_VAR_R, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_W_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_CONST(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_CONST(BP_VAR_W, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_RW_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_CONST(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_CONST(BP_VAR_RW, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_FUNC_ARG_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_CONST(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_CONST(BP_VAR_W, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_CONST(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_CONST(BP_VAR_R, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_UNSET_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_CONST(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_CONST(BP_VAR_UNSET, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_IS_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_CONST(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_CONST(BP_VAR_IS, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -31787,7 +32514,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_CON SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); @@ -31818,7 +32545,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_CON } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -31844,7 +32571,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_CV_CONST_ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_obj_r_helper_SPEC_CV_CONST(int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -31913,7 +32640,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CV_CONST_HAND } while (0); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_CV_CONST(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -32054,7 +32786,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_CON USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -32085,9 +32817,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_CON EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_TAIL_CALL(ZEND_FETCH_OBJ_R_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_CV_CONST(2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } @@ -32406,7 +33138,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST zend_function *fbc; zend_class_entry *called_scope; zend_object *obj; - zend_execute_data *call; uint32_t call_info; SAVE_OPLINE(); @@ -32507,10 +33238,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST GC_REFCOUNT(obj)++; /* For $this pointer */ } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, obj); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -33496,6 +34225,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_SPEC_CV_TMP_H ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR(opline->op2.var))) { + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + } else { + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + } +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -33524,6 +34264,254 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_TMP_HANDLER(ZEN ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *varptr, *arg; + + + varptr = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(varptr) == IS_UNDEF)) { + SAVE_OPLINE(); + GET_OP1_UNDEF_CV(varptr, BP_VAR_R); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + + arg = EX_VAR(opline->result.var); + if (IS_CV == IS_CV) { + ZVAL_OPT_DEREF(varptr); + ZVAL_COPY(arg, varptr); + } else /* if (IS_CV == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(varptr))) { + zend_refcounted *ref = Z_COUNTED_P(varptr); + + varptr = Z_REFVAL_P(varptr); + ZVAL_COPY_VALUE(arg, varptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(arg)) { + Z_ADDREF_P(arg); + } + } else { + ZVAL_COPY_VALUE(arg, varptr); + } + } + + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_REF_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *varptr, *arg = EX_VAR(opline->result.var); + + SAVE_OPLINE(); + varptr = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var); + + if (IS_CV == IS_VAR && UNEXPECTED(varptr == NULL)) { + zend_throw_error(NULL, "Only variables can be passed by reference"); + ZVAL_UNDEF(arg); + HANDLE_EXCEPTION(); + } + + if (IS_CV == IS_VAR && UNEXPECTED(varptr == &EG(error_zval))) { + ZVAL_NEW_REF(arg, &EG(uninitialized_zval)); + ZEND_VM_NEXT_OPCODE(); + } + + if (Z_ISREF_P(varptr)) { + Z_ADDREF_P(varptr); + ZVAL_COPY_VALUE(arg, varptr); + } else { + ZVAL_NEW_REF(arg, varptr); + Z_ADDREF_P(arg); + ZVAL_REF(varptr, Z_REF_P(arg)); + } + + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *varptr, *arg; + + uint32_t arg_num = opline->extended_value; + zend_function *fbc = ((zend_execute_data *) EX_VAR(opline->op2.var))->func; + + if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) { + if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num)) { + goto send_var_by_ref; + } + } else if (ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num)) { +send_var_by_ref: + ZEND_VM_TAIL_CALL(ZEND_SEND_REF_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + } + + varptr = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(varptr) == IS_UNDEF)) { + SAVE_OPLINE(); + GET_OP1_UNDEF_CV(varptr, BP_VAR_R); + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + + arg = EX_VAR(opline->result.var); + if (IS_CV == IS_CV) { + ZVAL_OPT_DEREF(varptr); + ZVAL_COPY(arg, varptr); + } else /* if (IS_CV == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(varptr))) { + zend_refcounted *ref = Z_COUNTED_P(varptr); + + varptr = Z_REFVAL_P(varptr); + ZVAL_COPY_VALUE(arg, varptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(arg)) { + Z_ADDREF_P(arg); + } + } else { + ZVAL_COPY_VALUE(arg, varptr); + } + } + + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *args; + int arg_num = opline->extended_value & ZEND_ARG_SEND_MASK; + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op2.var); + HashTable *ht; + + SAVE_OPLINE(); + if (UNEXPECTED(!(opline->extended_value & ZEND_ARG_IS_UNPACKED))) { + array_init(EX_VAR(opline->result.var)); + } + ht = Z_ARRVAL_P(EX_VAR(opline->result.var)); + args = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + +send_again: + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { + zend_string *name; + zval *arg; + HashTable *arg_ht = Z_ARRVAL_P(args); + arg_num += zend_hash_num_elements(ht); + unpack_array_separate(args, &arg_ht, call, arg_num, IS_CV); + + ZEND_HASH_FOREACH_STR_KEY_VAL(arg_ht, name, arg) { + if (UNEXPECTED(name != NULL)) { + zend_throw_error(NULL, "Cannot unpack array with string keys"); + + HANDLE_EXCEPTION(); + } + + if (ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num++)) { + if (!Z_IMMUTABLE_P(args)) { + ZVAL_MAKE_REF(arg); + Z_ADDREF_P(arg); + zend_hash_next_index_insert(ht, arg); + } else { + zval copy; + ZVAL_DUP(©, arg); + zend_hash_next_index_insert(ht, ©); + } + } else { + /* don't separate references for __call */ + if (UNEXPECTED(Z_ISREF_P(arg)) && EXPECTED((call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) == 0)) { + arg = Z_REFVAL_P(arg); + } + Z_TRY_ADDREF_P(arg); + zend_hash_next_index_insert(ht, arg); + } + } ZEND_HASH_FOREACH_END(); + } else if (EXPECTED(Z_TYPE_P(args) == IS_OBJECT)) { + zend_class_entry *ce = Z_OBJCE_P(args); + zend_object_iterator *iter; + + if (!ce || !ce->get_iterator) { + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, object%s%s given", opline->extended_value & ZEND_ARG_SEND_MASK, ce ? " of type " : "", ce ? ZSTR_VAL(ce->name) : ""); + } else { + iter = ce->get_iterator(ce, args, 0); + if (UNEXPECTED(!iter)) { + + if (!EG(exception)) { + zend_throw_exception_ex(NULL, 0, "Object of type %s unpacked at parameter %d did not create an Iterator", ZSTR_VAL(ce->name), opline->extended_value & ZEND_ARG_SEND_MASK); + } + HANDLE_EXCEPTION(); + } + unpack_iterator_to_array(iter, ht, call, arg_num + zend_hash_num_elements(ht)); + } + } else if (EXPECTED(Z_ISREF_P(args))) { + args = Z_REFVAL_P(args); + goto send_again; + } else { + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(args) == IS_UNDEF)) { + GET_OP1_UNDEF_CV(args, BP_VAR_R); + } + zend_error(E_WARNING, "Argument unpacking at parameter %d requires array or Traversable, %s given", opline->extended_value & ZEND_ARG_SEND_MASK, zend_get_type_by_const(Z_TYPE_P(args))); + } + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *arg, *param = EX_VAR(opline->result.var); + zend_execute_data *call = (zend_execute_data *) EX_VAR(opline->op2.var); + + + SAVE_OPLINE(); + arg = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var); + + if (ARG_SHOULD_BE_SENT_BY_REF(call->func, opline->extended_value)) { + if (UNEXPECTED(!Z_ISREF_P(arg))) { + if (!ARG_MAY_BE_SENT_BY_REF(call->func, opline->extended_value)) { + zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given", + opline->extended_value, + call->func->common.scope ? ZSTR_VAL(call->func->common.scope->name) : "", + call->func->common.scope ? "::" : "", + ZSTR_VAL(call->func->common.function_name)); + + if (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE) { + OBJ_RELEASE((zend_object *) call->func->common.prototype); + } + if (Z_OBJ(call->This)) { + OBJ_RELEASE(Z_OBJ(call->This)); + } + ZVAL_UNDEF(param); + call->func = (zend_function*)&zend_pass_function; + call->called_scope = NULL; + Z_OBJ(call->This) = NULL; + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } + + ZVAL_NEW_REF(arg, arg); + } + Z_ADDREF_P(arg); + } else { + if (Z_ISREF_P(arg) && + !(call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + /* don't separate references for __call */ + arg = Z_REFVAL_P(arg); + } + if (Z_OPT_REFCOUNTED_P(arg)) { + Z_ADDREF_P(arg); + } + } + ZVAL_COPY_VALUE(param, arg); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -33701,7 +34689,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_IS_NOT_IDENTICAL_SPEC_CV_VAR_H ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_CV_VAR(int type ZEND_OPCODE_HANDLER_ARGS_DC) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_CV_VAR(int type, int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -33801,43 +34789,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_ } else { ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_R_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_VAR(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_VAR(BP_VAR_R, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_W_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_VAR(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_VAR(BP_VAR_W, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_RW_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_VAR(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_VAR(BP_VAR_RW, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_FUNC_ARG_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_VAR(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_VAR(BP_VAR_W, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_VAR(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_VAR(BP_VAR_R, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_UNSET_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_VAR(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_VAR(BP_VAR_UNSET, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_IS_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_VAR(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_VAR(BP_VAR_IS, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -34570,137 +35558,32 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_POW_SPEC_CV_UNUSED_HAND #endif } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CV_UNUSED(int type ZEND_OPCODE_HANDLER_ARGS_DC) -{ - USE_OPLINE - - zval *varname; - zval *retval; - zend_string *name; - HashTable *target_symbol_table; - - SAVE_OPLINE(); - varname = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); - - if (IS_CV == IS_CONST) { - name = Z_STR_P(varname); - } else if (EXPECTED(Z_TYPE_P(varname) == IS_STRING)) { - name = Z_STR_P(varname); - zend_string_addref(name); - } else { - if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(varname, BP_VAR_R); - } - name = zval_get_string(varname); - } - - target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK); - retval = zend_hash_find(target_symbol_table, name); - if (retval == NULL) { - switch (type) { - case BP_VAR_R: - case BP_VAR_UNSET: - zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); - /* break missing intentionally */ - case BP_VAR_IS: - retval = &EG(uninitialized_zval); - break; - case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); - retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval)); - break; - case BP_VAR_W: - retval = zend_hash_add_new(target_symbol_table, name, &EG(uninitialized_zval)); - break; - EMPTY_SWITCH_DEFAULT_CASE() - } - /* GLOBAL or $$name variable may be an INDIRECT pointer to CV */ - } else if (Z_TYPE_P(retval) == IS_INDIRECT) { - retval = Z_INDIRECT_P(retval); - if (Z_TYPE_P(retval) == IS_UNDEF) { - switch (type) { - case BP_VAR_R: - case BP_VAR_UNSET: - zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); - /* break missing intentionally */ - case BP_VAR_IS: - retval = &EG(uninitialized_zval); - break; - case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); - /* break missing intentionally */ - case BP_VAR_W: - ZVAL_NULL(retval); - break; - EMPTY_SWITCH_DEFAULT_CASE() - } - } - } - - 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 (IS_CV != IS_CONST) { - zend_string_release(name); - } - - ZEND_ASSERT(retval != NULL); - if (type == BP_VAR_R || type == BP_VAR_IS) { - if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { - ZVAL_UNREF(retval); - } - ZVAL_COPY(EX_VAR(opline->result.var), retval); - } else { - ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); - } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_R_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_W_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_RW_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); - } else { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); - } + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_IS_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV_UNUSED(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_CV(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_CV_UNUSED(int type ZEND_OPCODE_HANDLER_ARGS_DC) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_CV_UNUSED(int type, int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -34800,43 +35683,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_ } else { ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_R_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_UNUSED(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_UNUSED(BP_VAR_R, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_W_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_UNUSED(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_UNUSED(BP_VAR_W, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_RW_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_UNUSED(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_UNUSED(BP_VAR_RW, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_FUNC_ARG_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_UNUSED(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_UNUSED(BP_VAR_W, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_UNUSED(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_UNUSED(BP_VAR_R, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_UNSET_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_UNUSED(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_UNUSED(BP_VAR_UNSET, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_IS_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_UNUSED(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_CV_UNUSED(BP_VAR_IS, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_W_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -34891,7 +35774,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_UNU SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); @@ -34922,7 +35805,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_UNU } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -36945,7 +37828,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_CV_ SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); @@ -36976,7 +37859,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_CV_ } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -37002,7 +37885,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_CV_CV_HAN ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_obj_r_helper_SPEC_CV_CV(int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -37071,7 +37954,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CV_CV_HANDLER } while (0); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_CV_CV(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -37212,7 +38100,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_CV_ USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -37243,9 +38131,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_CV_ EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_TAIL_CALL(ZEND_FETCH_OBJ_R_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_CV_CV(2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } @@ -37578,7 +38466,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HA zend_function *fbc; zend_class_entry *called_scope; zend_object *obj; - zend_execute_data *call; uint32_t call_info; SAVE_OPLINE(); @@ -37679,10 +38566,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HA GC_REFCOUNT(obj)++; /* For $this pointer */ } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, obj); - call->prev_execute_data = EX(call); - EX(call) = call; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -39601,7 +40486,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_TMP SAVE_OPLINE(); - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { zend_throw_error(NULL, "Cannot use temporary expression in write context"); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); @@ -39632,7 +40517,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_TMP zval_ptr_dtor_nogc(free_op2); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -39658,7 +40543,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_UNSET_SPEC_CV_TMPVAR ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_obj_r_helper_SPEC_CV_TMPVAR(int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -39728,7 +40613,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CV_TMPVAR_HAN zval_ptr_dtor_nogc(free_op2); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_CV_TMPVAR(1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -39870,7 +40760,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_TMP USE_OPLINE zval *container; - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -39901,9 +40791,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_TMP EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var), 0); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); } else { - ZEND_VM_TAIL_CALL(ZEND_FETCH_OBJ_R_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + ZEND_VM_TAIL_CALL(zend_fetch_obj_r_helper_SPEC_CV_TMPVAR(2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } @@ -40150,7 +41040,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMPVA zend_function *fbc; zend_class_entry *called_scope; zend_object *obj; - zend_execute_data *call; uint32_t call_info; SAVE_OPLINE(); @@ -40251,10 +41140,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMPVA GC_REFCOUNT(obj)++; /* For $this pointer */ } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, obj); - call->prev_execute_data = EX(call); - EX(call) = call; zval_ptr_dtor_nogc(free_op2); @@ -40851,6 +41738,100 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ECHO_SPEC_TMPVAR_HANDLER(ZEND_ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_TMPVAR(int type ZEND_OPCODE_HANDLER_ARGS_DC) +{ + USE_OPLINE + zend_free_op free_op1; + zval *varname; + zval *retval; + zend_string *name; + HashTable *target_symbol_table; + + SAVE_OPLINE(); + varname = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + + if ((IS_TMP_VAR|IS_VAR) == IS_CONST) { + name = Z_STR_P(varname); + } else if (EXPECTED(Z_TYPE_P(varname) == IS_STRING)) { + name = Z_STR_P(varname); + zend_string_addref(name); + } else { + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) { + GET_OP1_UNDEF_CV(varname, BP_VAR_R); + } + name = zval_get_string(varname); + } + + target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK); + retval = zend_hash_find(target_symbol_table, name); + if (retval == NULL) { + switch (type) { + case BP_VAR_R: + case BP_VAR_UNSET: + zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); + /* break missing intentionally */ + case BP_VAR_IS: + retval = &EG(uninitialized_zval); + break; + case BP_VAR_RW: + zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); + retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval)); + break; + case BP_VAR_W: + retval = zend_hash_add_new(target_symbol_table, name, &EG(uninitialized_zval)); + break; + EMPTY_SWITCH_DEFAULT_CASE() + } + /* GLOBAL or $$name variable may be an INDIRECT pointer to CV */ + } else if (Z_TYPE_P(retval) == IS_INDIRECT) { + retval = Z_INDIRECT_P(retval); + if (Z_TYPE_P(retval) == IS_UNDEF) { + switch (type) { + case BP_VAR_R: + case BP_VAR_UNSET: + zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); + /* break missing intentionally */ + case BP_VAR_IS: + retval = &EG(uninitialized_zval); + break; + case BP_VAR_RW: + zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); + /* break missing intentionally */ + case BP_VAR_W: + ZVAL_NULL(retval); + break; + EMPTY_SWITCH_DEFAULT_CASE() + } + } + } + + 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) { + zval_ptr_dtor_nogc(free_op1); + } + + if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { + zend_string_release(name); + } + + ZEND_ASSERT(retval != NULL); + if (type == BP_VAR_R || type == BP_VAR_IS) { + if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { + ZVAL_UNREF(retval); + } + ZVAL_COPY(EX_VAR(opline->result.var), retval); + } else { + ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMPZ_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -41164,135 +42145,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_TMPVAR_HANDLER(ZEND ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_op_array *new_op_array=NULL; - zend_free_op free_op1; - zval *inc_filename; - zval tmp_inc_filename; - zend_bool failure_retval=0; - - SAVE_OPLINE(); - inc_filename = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); - - ZVAL_UNDEF(&tmp_inc_filename); - if (Z_TYPE_P(inc_filename) != IS_STRING) { - if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(inc_filename) == IS_UNDEF)) { - inc_filename = GET_OP1_UNDEF_CV(inc_filename, BP_VAR_R); - } - ZVAL_STR(&tmp_inc_filename, zval_get_string(inc_filename)); - inc_filename = &tmp_inc_filename; - } - - if (opline->extended_value != ZEND_EVAL && strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename)) { - if (opline->extended_value == ZEND_INCLUDE_ONCE || opline->extended_value == ZEND_INCLUDE) { - zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename)); - } else { - zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename)); - } - } else { - switch (opline->extended_value) { - case ZEND_INCLUDE_ONCE: - case ZEND_REQUIRE_ONCE: { - zend_file_handle file_handle; - zend_string *resolved_path; - - resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), (int)Z_STRLEN_P(inc_filename)); - if (resolved_path) { - failure_retval = zend_hash_exists(&EG(included_files), resolved_path); - } else { - resolved_path = zend_string_copy(Z_STR_P(inc_filename)); - } - - if (failure_retval) { - /* do nothing, file already included */ - } else if (SUCCESS == zend_stream_open(ZSTR_VAL(resolved_path), &file_handle)) { - - if (!file_handle.opened_path) { - file_handle.opened_path = zend_string_copy(resolved_path); - } - - if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path)) { - new_op_array = zend_compile_file(&file_handle, (opline->extended_value==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE)); - zend_destroy_file_handle(&file_handle); - } else { - zend_file_handle_dtor(&file_handle); - failure_retval=1; - } - } else { - if (opline->extended_value == ZEND_INCLUDE_ONCE) { - zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename)); - } else { - zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename)); - } - } - zend_string_release(resolved_path); - } - break; - case ZEND_INCLUDE: - case ZEND_REQUIRE: - new_op_array = compile_filename(opline->extended_value, inc_filename); - break; - case ZEND_EVAL: { - char *eval_desc = zend_make_compiled_string_description("eval()'d code"); - - new_op_array = zend_compile_string(inc_filename, eval_desc); - efree(eval_desc); - } - break; - EMPTY_SWITCH_DEFAULT_CASE() - } - } - if (Z_TYPE(tmp_inc_filename) != IS_UNDEF) { - zend_string_release(Z_STR(tmp_inc_filename)); - } - zval_ptr_dtor_nogc(free_op1); - if (UNEXPECTED(EG(exception) != NULL)) { - HANDLE_EXCEPTION(); - } else if (EXPECTED(new_op_array != NULL)) { - zval *return_value = NULL; - zend_execute_data *call; - - if (RETURN_VALUE_USED(opline)) { - return_value = EX_VAR(opline->result.var); - } - - new_op_array->scope = EG(scope); - - call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_CODE, - (zend_function*)new_op_array, 0, EX(called_scope), Z_OBJ(EX(This))); - - if (EX(symbol_table)) { - call->symbol_table = EX(symbol_table); - } else { - call->symbol_table = zend_rebuild_symbol_table(); - } - - call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value); - if (EXPECTED(zend_execute_ex == execute_ex)) { - ZEND_VM_ENTER(); - } else { - ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP); - zend_execute_ex(call); - zend_vm_stack_free_call_frame(call); - } - - destroy_op_array(new_op_array); - efree_size(new_op_array, sizeof(zend_op_array)); - if (UNEXPECTED(EG(exception) != NULL)) { - zend_throw_exception_internal(NULL); - HANDLE_EXCEPTION(); - } - - } else if (RETURN_VALUE_USED(opline)) { - ZVAL_BOOL(EX_VAR(opline->result.var), failure_retval); - } - ZEND_VM_INTERRUPT_CHECK(); - ZEND_VM_NEXT_OPCODE(); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_EXIT_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -41966,7 +42818,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BOOL_XOR_SPEC_TMPVAR_CONST_HAN ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(int type ZEND_OPCODE_HANDLER_ARGS_DC) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(int type, int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE zend_free_op free_op1; @@ -42068,43 +42920,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_ } else { ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_R_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(BP_VAR_R, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_W_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(BP_VAR_W, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_RW_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(BP_VAR_RW, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_FUNC_ARG_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(BP_VAR_W, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(BP_VAR_R, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_UNSET_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(BP_VAR_UNSET, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_IS_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_CONST(BP_VAR_IS, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -42327,7 +43179,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C zend_function *fbc; zend_class_entry *called_scope; zend_object *obj; - zend_execute_data *call; uint32_t call_info; SAVE_OPLINE(); @@ -42428,10 +43279,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C GC_REFCOUNT(obj)++; /* For $this pointer */ } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, obj); - call->prev_execute_data = EX(call); - EX(call) = call; zval_ptr_dtor_nogc(free_op1); @@ -42880,7 +43729,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INSTANCEOF_SPEC_TMPVAR_CONST_H ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(int type ZEND_OPCODE_HANDLER_ARGS_DC) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_TMPVAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR(opline->op2.var))) { + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + } else { + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + } +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(int type, int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE zend_free_op free_op1; @@ -42982,43 +43842,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_ } else { ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_R_SPEC_TMPVAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(BP_VAR_R, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_W_SPEC_TMPVAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(BP_VAR_W, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_RW_SPEC_TMPVAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(BP_VAR_RW, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_FUNC_ARG_SPEC_TMPVAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(BP_VAR_W, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(BP_VAR_R, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_UNSET_SPEC_TMPVAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(BP_VAR_UNSET, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_IS_SPEC_TMPVAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_VAR(BP_VAR_IS, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_STATIC_PROP_SPEC_TMPVAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -43214,137 +44074,32 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INSTANCEOF_SPEC_TMPVAR_VAR_HAN ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(int type ZEND_OPCODE_HANDLER_ARGS_DC) -{ - USE_OPLINE - zend_free_op free_op1; - zval *varname; - zval *retval; - zend_string *name; - HashTable *target_symbol_table; - - SAVE_OPLINE(); - varname = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); - - if ((IS_TMP_VAR|IS_VAR) == IS_CONST) { - name = Z_STR_P(varname); - } else if (EXPECTED(Z_TYPE_P(varname) == IS_STRING)) { - name = Z_STR_P(varname); - zend_string_addref(name); - } else { - if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(varname) == IS_UNDEF)) { - GET_OP1_UNDEF_CV(varname, BP_VAR_R); - } - name = zval_get_string(varname); - } - - target_symbol_table = zend_get_target_symbol_table(execute_data, opline->extended_value & ZEND_FETCH_TYPE_MASK); - retval = zend_hash_find(target_symbol_table, name); - if (retval == NULL) { - switch (type) { - case BP_VAR_R: - case BP_VAR_UNSET: - zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); - /* break missing intentionally */ - case BP_VAR_IS: - retval = &EG(uninitialized_zval); - break; - case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); - retval = zend_hash_update(target_symbol_table, name, &EG(uninitialized_zval)); - break; - case BP_VAR_W: - retval = zend_hash_add_new(target_symbol_table, name, &EG(uninitialized_zval)); - break; - EMPTY_SWITCH_DEFAULT_CASE() - } - /* GLOBAL or $$name variable may be an INDIRECT pointer to CV */ - } else if (Z_TYPE_P(retval) == IS_INDIRECT) { - retval = Z_INDIRECT_P(retval); - if (Z_TYPE_P(retval) == IS_UNDEF) { - switch (type) { - case BP_VAR_R: - case BP_VAR_UNSET: - zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); - /* break missing intentionally */ - case BP_VAR_IS: - retval = &EG(uninitialized_zval); - break; - case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(name)); - /* break missing intentionally */ - case BP_VAR_W: - ZVAL_NULL(retval); - break; - EMPTY_SWITCH_DEFAULT_CASE() - } - } - } - - 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) { - zval_ptr_dtor_nogc(free_op1); - } - - if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { - zend_string_release(name); - } - - ZEND_ASSERT(retval != NULL); - if (type == BP_VAR_R || type == BP_VAR_IS) { - if (/*type == BP_VAR_R &&*/ Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1) { - ZVAL_UNREF(retval); - } - ZVAL_COPY(EX_VAR(opline->result.var), retval); - } else { - ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); - } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_R_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_W_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_RW_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); -} - -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); - } else { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); - } + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_IS_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR_UNUSED(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_var_address_helper_SPEC_TMPVAR(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(int type ZEND_OPCODE_HANDLER_ARGS_DC) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(int type, int skip ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE zend_free_op free_op1; @@ -43446,43 +44201,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static_prop_helper_SPEC_ } else { ZVAL_INDIRECT(EX_VAR(opline->result.var), retval); } - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE_EX(1, skip); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_R_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(BP_VAR_R, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_W_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(BP_VAR_W, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_RW_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(BP_VAR_RW ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(BP_VAR_RW, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_FUNC_ARG_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - if (zend_is_by_ref_func_arg_fetch(opline, EX(call))) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(BP_VAR_W ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + if (zend_is_by_ref_func_arg_fetch(opline, (zend_execute_data *) EX_VAR((opline + 1)->op2.var))) { + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(BP_VAR_W, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(BP_VAR_R ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(BP_VAR_R, 2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_UNSET_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(BP_VAR_UNSET ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(BP_VAR_UNSET, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_STATIC_PROP_IS_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(BP_VAR_IS ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); + ZEND_VM_TAIL_CALL(zend_fetch_static_prop_helper_SPEC_TMPVAR_UNUSED(BP_VAR_IS, 1 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMPVAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -44568,7 +45323,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C zend_function *fbc; zend_class_entry *called_scope; zend_object *obj; - zend_execute_data *call; uint32_t call_info; SAVE_OPLINE(); @@ -44669,10 +45423,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C GC_REFCOUNT(obj)++; /* For $this pointer */ } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, obj); - call->prev_execute_data = EX(call); - EX(call) = call; zval_ptr_dtor_nogc(free_op1); @@ -45706,7 +46458,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_T zend_function *fbc; zend_class_entry *called_scope; zend_object *obj; - zend_execute_data *call; uint32_t call_info; SAVE_OPLINE(); @@ -45807,10 +46558,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_T GC_REFCOUNT(obj)++; /* For $this pointer */ } - call = zend_vm_stack_push_call_frame(call_info, + zend_init_call_frame((zend_execute_data *) EX_VAR(opline->result.var), call_info, fbc, opline->extended_value, called_scope, obj); - call->prev_execute_data = EX(call); - EX(call) = call; zval_ptr_dtor_nogc(free_op2); zval_ptr_dtor_nogc(free_op1); @@ -47110,11 +47859,11 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_DO_UNPACK_FCALL_SPEC_TMP_CONST_HANDLER, + ZEND_DO_UNPACK_FCALL_SPEC_TMP_TMP_HANDLER, + ZEND_DO_UNPACK_FCALL_SPEC_TMP_VAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_DO_UNPACK_FCALL_SPEC_TMP_CV_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, @@ -47580,31 +48329,31 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, - ZEND_DO_FCALL_SPEC_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_DO_FCALL_SPEC_TMP_HANDLER, + ZEND_DO_FCALL_SPEC_TMP_HANDLER, + ZEND_DO_FCALL_SPEC_TMP_HANDLER, + ZEND_DO_FCALL_SPEC_TMP_HANDLER, + ZEND_DO_FCALL_SPEC_TMP_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_INIT_FCALL_SPEC_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, @@ -47705,16 +48454,32 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_SEND_VAL_SPEC_CONST_HANDLER, - ZEND_SEND_VAL_SPEC_CONST_HANDLER, - ZEND_SEND_VAL_SPEC_CONST_HANDLER, - ZEND_SEND_VAL_SPEC_CONST_HANDLER, - ZEND_SEND_VAL_SPEC_CONST_HANDLER, - ZEND_SEND_VAL_SPEC_TMP_HANDLER, - ZEND_SEND_VAL_SPEC_TMP_HANDLER, - ZEND_SEND_VAL_SPEC_TMP_HANDLER, - ZEND_SEND_VAL_SPEC_TMP_HANDLER, - ZEND_SEND_VAL_SPEC_TMP_HANDLER, + ZEND_NULL_HANDLER, + ZEND_SEND_VAL_SPEC_CONST_TMP_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_SEND_VAL_SPEC_TMP_TMP_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, @@ -47725,6 +48490,7 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_SEND_VAR_EX_SPEC_VAR_TMP_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, @@ -47734,30 +48500,22 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_SEND_VAR_EX_SPEC_CV_TMP_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_SEND_VAR_EX_SPEC_VAR_HANDLER, - ZEND_SEND_VAR_EX_SPEC_VAR_HANDLER, - ZEND_SEND_VAR_EX_SPEC_VAR_HANDLER, - ZEND_SEND_VAR_EX_SPEC_VAR_HANDLER, - ZEND_SEND_VAR_EX_SPEC_VAR_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_SEND_VAR_EX_SPEC_CV_HANDLER, - ZEND_SEND_VAR_EX_SPEC_CV_HANDLER, - ZEND_SEND_VAR_EX_SPEC_CV_HANDLER, - ZEND_SEND_VAR_EX_SPEC_CV_HANDLER, - ZEND_SEND_VAR_EX_SPEC_CV_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_SEND_REF_SPEC_VAR_TMP_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, @@ -47765,21 +48523,12 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_SEND_REF_SPEC_VAR_HANDLER, - ZEND_SEND_REF_SPEC_VAR_HANDLER, - ZEND_SEND_REF_SPEC_VAR_HANDLER, - ZEND_SEND_REF_SPEC_VAR_HANDLER, - ZEND_SEND_REF_SPEC_VAR_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_SEND_REF_SPEC_CV_TMP_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_SEND_REF_SPEC_CV_HANDLER, - ZEND_SEND_REF_SPEC_CV_HANDLER, - ZEND_SEND_REF_SPEC_CV_HANDLER, - ZEND_SEND_REF_SPEC_CV_HANDLER, - ZEND_SEND_REF_SPEC_CV_HANDLER, ZEND_NEW_SPEC_CONST_HANDLER, ZEND_NEW_SPEC_CONST_HANDLER, ZEND_NEW_SPEC_CONST_HANDLER, @@ -47905,31 +48654,31 @@ void zend_init_opcodes_handlers(void) ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_TMPVAR_HANDLER, ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_UNUSED_HANDLER, ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_CV_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER, - ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER, + ZEND_INCLUDE_OR_EVAL_SPEC_TMP_CONST_HANDLER, + ZEND_INCLUDE_OR_EVAL_SPEC_TMP_TMPVAR_HANDLER, + ZEND_INCLUDE_OR_EVAL_SPEC_TMP_TMPVAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_INCLUDE_OR_EVAL_SPEC_TMP_CV_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, @@ -48381,19 +49130,19 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_FETCH_OBJ_IS_SPEC_CV_CV_HANDLER, ZEND_NULL_HANDLER, + ZEND_FETCH_FUNC_ARG_SPEC_CONST_TMP_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_FETCH_FUNC_ARG_SPEC_CONST_UNUSED_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_FETCH_FUNC_ARG_SPEC_TMPVAR_TMP_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_FETCH_FUNC_ARG_SPEC_TMPVAR_UNUSED_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_FETCH_FUNC_ARG_SPEC_TMPVAR_TMP_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_FETCH_FUNC_ARG_SPEC_TMPVAR_UNUSED_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, @@ -48401,9 +49150,9 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_FETCH_FUNC_ARG_SPEC_CV_TMP_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_FETCH_FUNC_ARG_SPEC_CV_UNUSED_HANDLER, ZEND_NULL_HANDLER, ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_CONST_HANDLER, ZEND_FETCH_DIM_FUNC_ARG_SPEC_CONST_TMPVAR_HANDLER, @@ -48740,11 +49489,11 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER, - ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER, - ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER, - ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER, - ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_SEND_VAR_NO_REF_SPEC_VAR_TMP_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, @@ -48980,16 +49729,17 @@ void zend_init_opcodes_handlers(void) ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_CV_TMPVAR_HANDLER, ZEND_NULL_HANDLER, ZEND_ISSET_ISEMPTY_DIM_OBJ_SPEC_CV_CV_HANDLER, - ZEND_SEND_VAL_EX_SPEC_CONST_HANDLER, - ZEND_SEND_VAL_EX_SPEC_CONST_HANDLER, - ZEND_SEND_VAL_EX_SPEC_CONST_HANDLER, - ZEND_SEND_VAL_EX_SPEC_CONST_HANDLER, - ZEND_SEND_VAL_EX_SPEC_CONST_HANDLER, - ZEND_SEND_VAL_EX_SPEC_TMP_HANDLER, - ZEND_SEND_VAL_EX_SPEC_TMP_HANDLER, - ZEND_SEND_VAL_EX_SPEC_TMP_HANDLER, - ZEND_SEND_VAL_EX_SPEC_TMP_HANDLER, - ZEND_SEND_VAL_EX_SPEC_TMP_HANDLER, + ZEND_NULL_HANDLER, + ZEND_SEND_VAL_EX_SPEC_CONST_TMP_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_SEND_VAL_EX_SPEC_TMP_TMP_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, @@ -49015,21 +49765,20 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_SEND_VAR_SPEC_VAR_HANDLER, - ZEND_SEND_VAR_SPEC_VAR_HANDLER, - ZEND_SEND_VAR_SPEC_VAR_HANDLER, - ZEND_SEND_VAR_SPEC_VAR_HANDLER, - ZEND_SEND_VAR_SPEC_VAR_HANDLER, + ZEND_SEND_VAR_SPEC_VAR_TMP_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_SEND_VAR_SPEC_CV_HANDLER, - ZEND_SEND_VAR_SPEC_CV_HANDLER, - ZEND_SEND_VAR_SPEC_CV_HANDLER, - ZEND_SEND_VAR_SPEC_CV_HANDLER, - ZEND_SEND_VAR_SPEC_CV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_SEND_VAR_SPEC_CV_TMP_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_INIT_USER_CALL_SPEC_CONST_CONST_HANDLER, ZEND_INIT_USER_CALL_SPEC_CONST_TMPVAR_HANDLER, ZEND_INIT_USER_CALL_SPEC_CONST_TMPVAR_HANDLER, @@ -49055,31 +49804,6 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, @@ -49090,21 +49814,46 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_SEND_USER_SPEC_VAR_HANDLER, - ZEND_SEND_USER_SPEC_VAR_HANDLER, - ZEND_SEND_USER_SPEC_VAR_HANDLER, - ZEND_SEND_USER_SPEC_VAR_HANDLER, - ZEND_SEND_USER_SPEC_VAR_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_SEND_USER_SPEC_CV_HANDLER, - ZEND_SEND_USER_SPEC_CV_HANDLER, - ZEND_SEND_USER_SPEC_CV_HANDLER, - ZEND_SEND_USER_SPEC_CV_HANDLER, - ZEND_SEND_USER_SPEC_CV_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_SEND_USER_SPEC_VAR_TMP_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_SEND_USER_SPEC_CV_TMP_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_STRLEN_SPEC_CONST_HANDLER, ZEND_STRLEN_SPEC_CONST_HANDLER, ZEND_STRLEN_SPEC_CONST_HANDLER, @@ -49305,81 +50054,81 @@ void zend_init_opcodes_handlers(void) ZEND_INIT_DYNAMIC_CALL_SPEC_TMPVAR_HANDLER, ZEND_NULL_HANDLER, ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_ICALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_UCALL_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, - ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_DO_ICALL_SPEC_TMP_HANDLER, + ZEND_DO_ICALL_SPEC_TMP_HANDLER, + ZEND_DO_ICALL_SPEC_TMP_HANDLER, + ZEND_DO_ICALL_SPEC_TMP_HANDLER, + ZEND_DO_ICALL_SPEC_TMP_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_DO_UCALL_SPEC_TMP_HANDLER, + ZEND_DO_UCALL_SPEC_TMP_HANDLER, + ZEND_DO_UCALL_SPEC_TMP_HANDLER, + ZEND_DO_UCALL_SPEC_TMP_HANDLER, + ZEND_DO_UCALL_SPEC_TMP_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_DO_FCALL_BY_NAME_SPEC_TMP_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_TMP_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_TMP_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_TMP_HANDLER, + ZEND_DO_FCALL_BY_NAME_SPEC_TMP_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, @@ -50205,31 +50954,31 @@ void zend_init_opcodes_handlers(void) ZEND_RECV_VARIADIC_SPEC_HANDLER, ZEND_RECV_VARIADIC_SPEC_HANDLER, ZEND_RECV_VARIADIC_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, - ZEND_SEND_UNPACK_SPEC_HANDLER, + ZEND_NULL_HANDLER, + ZEND_SEND_UNPACK_SPEC_CONST_TMP_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_SEND_UNPACK_SPEC_TMP_TMP_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_SEND_UNPACK_SPEC_VAR_TMP_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_SEND_UNPACK_SPEC_CV_TMP_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_POW_SPEC_CONST_CONST_HANDLER, ZEND_POW_SPEC_CONST_TMPVAR_HANDLER, ZEND_POW_SPEC_CONST_TMPVAR_HANDLER, diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index 7e223385ff212..51ab5123fd013 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -28,7 +28,7 @@ ZEND_API void zend_{%EXECUTOR_NAME%}(zend_op_array *op_array, zval *return_value return; } - execute_data = zend_vm_stack_push_call_frame(ZEND_CALL_TOP_CODE, + execute_data = zend_push_top_call_frame(ZEND_CALL_TOP_CODE, (zend_function*)op_array, 0, zend_get_called_scope(EG(current_execute_data)), zend_get_this_object(EG(current_execute_data))); if (EG(current_execute_data)) { execute_data->symbol_table = zend_rebuild_symbol_table(); @@ -38,7 +38,7 @@ ZEND_API void zend_{%EXECUTOR_NAME%}(zend_op_array *op_array, zval *return_value EX(prev_execute_data) = EG(current_execute_data); i_init_execute_data(execute_data, op_array, return_value); zend_{%EXECUTOR_NAME%}_ex(execute_data); - zend_vm_stack_free_call_frame(execute_data); + zend_vm_stack_free_call_frame(ZEND_CALL_INFO(execute_data)); } {%EXTERNAL_EXECUTOR%} diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index d8952ecc4c6b2..abc601d91f7a7 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -63,7 +63,7 @@ static const char *zend_vm_opcodes_names[182] = { "ZEND_ASSIGN", "ZEND_ASSIGN_REF", "ZEND_ECHO", - NULL, + "ZEND_DO_UNPACK_FCALL", "ZEND_JMP", "ZEND_JMPZ", "ZEND_JMPNZ", @@ -141,7 +141,7 @@ static const char *zend_vm_opcodes_names[182] = { "ZEND_SEND_VAL_EX", "ZEND_SEND_VAR", "ZEND_INIT_USER_CALL", - "ZEND_SEND_ARRAY", + NULL, "ZEND_SEND_USER", "ZEND_STRLEN", "ZEND_DEFINED", @@ -248,7 +248,7 @@ static uint32_t zend_vm_opcodes_flags[182] = { 0x00000301, 0x0b000101, 0x00000007, - 0x00000000, + 0x01000301, 0x00000020, 0x00002007, 0x00002007, @@ -267,20 +267,20 @@ static uint32_t zend_vm_opcodes_flags[182] = { 0x00000000, 0x00000001, 0x01000300, - 0x00000000, + 0x00000001, 0x01000300, 0x00000003, 0x00000010, 0x00000310, - 0x00001003, - 0x00001001, - 0x00001001, + 0x01000103, + 0x01000101, + 0x01000101, 0x01002073, 0x01000300, 0x00004005, 0x00186703, 0x00106703, - 0x08000007, + 0x08000701, 0x00030107, 0x00000751, 0x00000751, @@ -313,7 +313,7 @@ static uint32_t zend_vm_opcodes_flags[182] = { 0x00000000, 0x00000000, 0x01000000, - 0x0c001001, + 0x01000101, 0x03000103, 0x00000003, 0x05000700, @@ -323,11 +323,11 @@ static uint32_t zend_vm_opcodes_flags[182] = { 0x01008773, 0x00030107, 0x00020757, - 0x00001003, - 0x00001001, + 0x01000103, + 0x01000101, 0x01000703, 0x00000000, - 0x00001001, + 0x01000101, 0x00000007, 0x00000003, 0x07000003, @@ -336,9 +336,9 @@ static uint32_t zend_vm_opcodes_flags[182] = { 0x03000001, 0x00004005, 0x01000700, - 0x00000000, - 0x00000000, - 0x00000000, + 0x00000001, + 0x00001001, + 0x00000001, 0x00000751, 0x00000751, 0x00000751, @@ -372,7 +372,7 @@ static uint32_t zend_vm_opcodes_flags[182] = { 0x09003020, 0x0a003000, 0x00000010, - 0x00000000, + 0x01000103, 0x00000707, 0x04006751, 0x00000301, diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 760b18c31c999..9a32f5309e786 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -119,6 +119,7 @@ END_EXTERN_C() #define ZEND_ASSIGN 38 #define ZEND_ASSIGN_REF 39 #define ZEND_ECHO 40 +#define ZEND_DO_UNPACK_FCALL 41 #define ZEND_JMP 42 #define ZEND_JMPZ 43 #define ZEND_JMPNZ 44 @@ -192,7 +193,6 @@ END_EXTERN_C() #define ZEND_SEND_VAL_EX 116 #define ZEND_SEND_VAR 117 #define ZEND_INIT_USER_CALL 118 -#define ZEND_SEND_ARRAY 119 #define ZEND_SEND_USER 120 #define ZEND_STRLEN 121 #define ZEND_DEFINED 122 diff --git a/ext/date/tests/bug53437.phpt b/ext/date/tests/bug53437.phpt index f82a4879b387e..6eb588efa3647 100644 --- a/ext/date/tests/bug53437.phpt +++ b/ext/date/tests/bug53437.phpt @@ -23,7 +23,7 @@ foreach($dpu as $dt) { } ?> ==DONE== ---EXPECT-- +--EXPECTF-- Original: 2010-01-01 00:00:00 2010-01-02 00:00:00 @@ -31,7 +31,7 @@ Original: object(DatePeriod)#1 (6) { ["start"]=> - object(DateTime)#2 (3) { + object(DateTime)#%d (3) { ["date"]=> string(26) "2010-01-01 00:00:00.000000" ["timezone_type"]=> diff --git a/ext/interbase/ibase_events.c b/ext/interbase/ibase_events.c index 26656f81b9b93..67dd6891a9690 100644 --- a/ext/interbase/ibase_events.c +++ b/ext/interbase/ibase_events.c @@ -156,8 +156,8 @@ PHP_FUNCTION(ibase_wait_event) } for (; i < ZEND_NUM_ARGS(); ++i) { - convert_to_string_ex(&args[i]); - events[event_count++] = Z_STRVAL(args[i]); + convert_to_string_ex(&args[-i]); + events[event_count++] = Z_STRVAL(args[-i]); } /* fills the required data structure with information about the events */ diff --git a/ext/interbase/ibase_query.c b/ext/interbase/ibase_query.c index fce9206dd7759..c9f0a48f078fe 100644 --- a/ext/interbase/ibase_query.c +++ b/ext/interbase/ibase_query.c @@ -641,7 +641,7 @@ static int _php_ibase_bind(XSQLDA *sqlda, zval *b_vars, BIND_BUF *buf, /* {{{ */ for (i = 0; i < sqlda->sqld; ++i) { /* bound vars */ - zval *b_var = &b_vars[i]; + zval *b_var = &b_vars[-i]; XSQLVAR *var = &sqlda->sqlvar[i]; var->sqlind = &buf[i].sqlind; @@ -872,7 +872,7 @@ static int _php_ibase_exec(INTERNAL_FUNCTION_PARAMETERS, ibase_result **ib_resul RESET_ERRMSG; for (i = 0; i < argc; ++i) { - SEPARATE_ZVAL(&args[i]); + SEPARATE_ZVAL(&args[-i]); } switch (ib_query->statement_type) { @@ -1175,7 +1175,7 @@ PHP_FUNCTION(ibase_query) } if (FAILURE == _php_ibase_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, &result, &ib_query, - &bind_args[bind_i])) { + &bind_args[-bind_i])) { break; } @@ -1890,7 +1890,7 @@ PHP_FUNCTION(ibase_num_fields) if (type == le_query) { ibase_query *ib_query; - + ib_query = (ibase_query *)zend_fetch_resource_ex(result, LE_QUERY, le_query); sqlda = ib_query->out_sqlda; } else { diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index 09994f649be16..191311338694d 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -3598,7 +3598,7 @@ PHP_FUNCTION(mb_convert_variables) n = 0; while (n < argc || stack_level > 0) { if (stack_level <= 0) { - var = &args[n++]; + var = &args[-n++]; ZVAL_DEREF(var); SEPARATE_ZVAL_NOREF(var); if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) { @@ -3685,7 +3685,7 @@ PHP_FUNCTION(mb_convert_variables) n = 0; while (n < argc || stack_level > 0) { if (stack_level <= 0) { - var = &args[n++]; + var = &args[-n++]; ZVAL_DEREF(var); SEPARATE_ZVAL_NOREF(var); if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) { diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c index 911ff9c8d1d2a..a15886fe3ae83 100644 --- a/ext/mysqli/mysqli_api.c +++ b/ext/mysqli/mysqli_api.c @@ -556,7 +556,7 @@ mysqli_stmt_bind_result_do_bind(MY_STMT *stmt, zval *args, unsigned int argc) stmt->result.var_cnt = var_cnt; stmt->result.vars = safe_emalloc((var_cnt), sizeof(zval), 0); for (i = 0; i < var_cnt; i++) { - ZVAL_COPY(&stmt->result.vars[i], &args[i]); + ZVAL_COPY(&stmt->result.vars[i], &args[-i]); } } efree(bind); @@ -567,11 +567,11 @@ mysqli_stmt_bind_result_do_bind(MY_STMT *stmt, zval *args, unsigned int argc) static int mysqli_stmt_bind_result_do_bind(MY_STMT *stmt, zval *args, unsigned int argc) { - unsigned int i; + int i; MYSQLND_RESULT_BIND *params = mysqlnd_stmt_alloc_result_bind(stmt->stmt); if (params) { for (i = 0; i < argc; i++) { - ZVAL_COPY_VALUE(¶ms[i].zv, &args[i]); + ZVAL_COPY_VALUE(¶ms[i].zv, &args[-i]); } return mysqlnd_stmt_bind_result(stmt->stmt, params); } diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index dc49ef216d301..4b42712aa0ae7 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -74,6 +74,17 @@ int zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int /* Data dependencies macros */ +static zend_always_inline uint32_t linear_var_num(zend_op_array *op_array, uint32_t var) { + uint32_t num = VAR_NUM(var); + if (0 > (int32_t) num) { + return - 1 - num; + } else { + return num + op_array->num_args; + } +} +#undef VAR_NUM +#define VAR_NUM(var) linear_var_num(op_array, var) + #define VAR_NUM_EX(op) VAR_NUM((op).var) #define VAR_SOURCE(op) Tsource[VAR_NUM(op.var)] @@ -1285,7 +1296,7 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr if (1) { zend_op *target, *target_end; zend_basic_block *target_block; - int var_num = op_array->last_var + op_array->T; + int var_num = op_array->num_args + op_array->last_var + op_array->T; if (var_num <= 0) { return; @@ -1608,6 +1619,7 @@ static void zend_t_usage(zend_cfg *cfg, zend_op_array *op_array, zend_bitset use case ZEND_DO_ICALL: case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: + case ZEND_DO_UNPACK_FCALL: opline->result_type |= EXT_TYPE_UNUSED; break; } @@ -1754,10 +1766,10 @@ void optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx) zend_dump_op_array(op_array, ZEND_DUMP_CFG, "before block pass", &cfg); } - if (op_array->last_var || op_array->T) { + if (op_array->last_var || op_array->T || op_array->num_args) { bitset_len = zend_bitset_len(op_array->last_var + op_array->T); - Tsource = zend_arena_calloc(&ctx->arena, op_array->last_var + op_array->T, sizeof(zend_op *)); - same_t = zend_arena_alloc(&ctx->arena, op_array->last_var + op_array->T); + Tsource = zend_arena_calloc(&ctx->arena, op_array->num_args + op_array->last_var + op_array->T, sizeof(zend_op *)); + same_t = zend_arena_alloc(&ctx->arena, op_array->num_args + op_array->last_var + op_array->T); usage = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE); } else { bitset_len = 0; @@ -1781,7 +1793,7 @@ void optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx) if (!(b->flags & ZEND_BB_FOLLOW) || (b->flags & ZEND_BB_TARGET)) { /* Skip continuation of "extended" BB */ - memset(Tsource, 0, (op_array->last_var + op_array->T) * sizeof(zend_op *)); + memset(Tsource, 0, (op_array->num_args + op_array->last_var + op_array->T) * sizeof(zend_op *)); } zend_optimize_block(b, op_array, usage, &cfg, Tsource); } diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c index 68597b1d5df55..4d4686c0e357e 100644 --- a/ext/opcache/Optimizer/optimize_func_calls.c +++ b/ext/opcache/Optimizer/optimize_func_calls.c @@ -78,28 +78,34 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) case ZEND_DO_ICALL: case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: + case ZEND_DO_UNPACK_FCALL: call--; if (call_stack[call].func && call_stack[call].opline) { zend_op *fcall = call_stack[call].opline; if (fcall->opcode == ZEND_INIT_FCALL_BY_NAME) { fcall->opcode = ZEND_INIT_FCALL; - fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func); Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]); literal_dtor(&ZEND_OP2_LITERAL(fcall)); fcall->op2.constant = fcall->op2.constant + 1; - opline->opcode = zend_get_call_op(ZEND_INIT_FCALL, call_stack[call].func); + if (opline->opcode != ZEND_DO_UNPACK_FCALL) { + opline->opcode = zend_get_call_op(ZEND_INIT_FCALL, call_stack[call].func); + } } else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) { fcall->opcode = ZEND_INIT_FCALL; - fcall->op1.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func); Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]); literal_dtor(&op_array->literals[fcall->op2.constant]); literal_dtor(&op_array->literals[fcall->op2.constant + 2]); fcall->op2.constant = fcall->op2.constant + 1; - opline->opcode = zend_get_call_op(ZEND_INIT_FCALL, call_stack[call].func); + if (opline->opcode != ZEND_DO_UNPACK_FCALL) { + opline->opcode = zend_get_call_op(ZEND_INIT_FCALL, call_stack[call].func); + } } else { ZEND_ASSERT(0); } + if (opline->opcode == ZEND_DO_UCALL) { + opline->op2.num = zend_vm_calc_used_stack(fcall->extended_value, call_stack[call].func); + } } call_stack[call].func = NULL; call_stack[call].opline = NULL; @@ -109,6 +115,12 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) case ZEND_FETCH_OBJ_FUNC_ARG: case ZEND_FETCH_DIM_FUNC_ARG: if (call_stack[call - 1].func) { + if (opline->opcode == ZEND_FETCH_FUNC_ARG) { + opline->op2_type = IS_UNUSED; + } else { + /* NOP the ZEND_OP_DATA out */ + MAKE_NOP(opline + 1); + } if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { opline->extended_value &= ZEND_FETCH_TYPE_MASK; if (opline->opcode != ZEND_FETCH_STATIC_PROP_FUNC_ARG) { @@ -163,10 +175,6 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) } break; #endif - case ZEND_SEND_UNPACK: - call_stack[call - 1].func = NULL; - call_stack[call - 1].opline = NULL; - break; default: break; } diff --git a/ext/opcache/Optimizer/optimize_temp_vars_5.c b/ext/opcache/Optimizer/optimize_temp_vars_5.c index 586471017c5e8..5431d1a98d2a9 100644 --- a/ext/opcache/Optimizer/optimize_temp_vars_5.c +++ b/ext/opcache/Optimizer/optimize_temp_vars_5.c @@ -39,10 +39,45 @@ max = i; \ } +/* we need to handle the fcall ops separately as they need to be always at the end of the op array */ +#define IS_FCALL_OP1_TMP(opcode) \ + (opcode == ZEND_DO_FCALL \ + || opcode == ZEND_DO_ICALL \ + || opcode == ZEND_DO_UCALL \ + || opcode == ZEND_DO_FCALL_BY_NAME \ + || opcode == ZEND_DO_UNPACK_FCALL \ + || opcode == ZEND_INCLUDE_OR_EVAL) +#define IS_SEND_OPCODE(opcode) \ + (opcode == ZEND_SEND_VAL \ + || opcode == ZEND_SEND_VAR_EX \ + || opcode == ZEND_SEND_REF \ + || opcode == ZEND_SEND_VAR_NO_REF \ + || opcode == ZEND_SEND_VAL_EX \ + || opcode == ZEND_SEND_VAR \ + || opcode == ZEND_SEND_USER) +#define IS_FCALL_OP2_TMP(opcode) \ + (IS_SEND_OPCODE(opcode) \ + || opcode == ZEND_SEND_UNPACK \ + || opcode == ZEND_FETCH_FUNC_ARG) +#define IS_FCALL_RESULT_TMP(opcode) \ + (IS_SEND_OPCODE(opcode) \ + || opcode == ZEND_INIT_FCALL_BY_NAME \ + || opcode == ZEND_INIT_FCALL \ + || opcode == ZEND_INIT_NS_FCALL_BY_NAME \ + || opcode == ZEND_INIT_METHOD_CALL \ + || opcode == ZEND_INIT_STATIC_METHOD_CALL \ + || opcode == ZEND_INIT_USER_CALL \ + || opcode == ZEND_INIT_DYNAMIC_CALL) +#define IS_FUNC_ARG_OP_DATA(opcode) \ + (opcode == ZEND_FETCH_DIM_FUNC_ARG \ + || opcode == ZEND_FETCH_OBJ_FUNC_ARG \ + || opcode == ZEND_FETCH_STATIC_PROP_FUNC_ARG) + void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *ctx) { int T = op_array->T; int offset = op_array->last_var; + int max = -1, max_old = -1, max_diff; uint32_t bitset_len; zend_bitset taken_T; /* T index in use */ zend_op **start_of_T; /* opline where T is first used */ @@ -51,7 +86,6 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c zend_op *opline, *end; int currT; int i; - int max = -1; int var_to_free = -1; void *checkpoint = zend_arena_checkpoint(ctx->arena); @@ -79,8 +113,11 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c opline = &op_array->opcodes[op_array->last - 1]; while (opline >= end) { - if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) { + if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) && !IS_FCALL_OP1_TMP(opline->opcode)) { currT = VAR_NUM(ZEND_OP1(opline).var) - offset; + if (currT > max_old) { + max_old = currT; + } if (opline->opcode == ZEND_ROPE_END) { int num = (((opline->extended_value + 1) * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval); int var; @@ -141,13 +178,16 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c /* Skip OP_DATA */ if (opline->opcode == ZEND_OP_DATA && - (opline-1)->opcode == ZEND_ASSIGN_DIM) { + ((opline-1)->opcode == ZEND_ASSIGN_DIM || IS_FUNC_ARG_OP_DATA((opline-1)->opcode))) { opline--; continue; } - if ((ZEND_OP2_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) { + if ((ZEND_OP2_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) && !IS_FCALL_OP2_TMP(opline->opcode)) { currT = VAR_NUM(ZEND_OP2(opline).var) - offset; + if (currT > max_old) { + max_old = currT; + } if (!zend_bitset_in(valid_T, currT)) { GET_AVAILABLE_T(); map_T[currT] = i; @@ -181,8 +221,11 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c var_to_free = i; } - if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) { + if ((ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) && !IS_FCALL_RESULT_TMP(opline->opcode)) { currT = VAR_NUM(ZEND_RESULT(opline).var) - offset; + if (currT > max_old) { + max_old = currT; + } if (zend_bitset_in(valid_T, currT)) { if (start_of_T[currT] == opline) { /* ZEND_FAST_CALL can not share temporary var with others @@ -224,6 +267,23 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c opline--; } + max_diff = max_old - max; + + for (opline = &op_array->opcodes[op_array->last - 1]; opline >= end; opline--) { + if (IS_FCALL_OP1_TMP(opline->opcode)) { + map_T[VAR_NUM(opline->op1.var) - offset] = VAR_NUM(opline->op1.var) - offset - max_diff; + opline->op1.var -= max_diff * sizeof(zval); + } + if (IS_FCALL_OP2_TMP(opline->opcode) || (opline->opcode == ZEND_OP_DATA && IS_FUNC_ARG_OP_DATA((opline-1)->opcode))) { + map_T[VAR_NUM(opline->op2.var) - offset] = VAR_NUM(opline->op2.var) - offset - max_diff; + opline->op2.var -= max_diff * sizeof(zval); + } + if (IS_FCALL_RESULT_TMP(opline->opcode)) { + map_T[VAR_NUM(opline->result.var) - offset] = VAR_NUM(opline->result.var) - offset - max_diff; + opline->result.var -= max_diff * sizeof(zval); + } + } + if (op_array->live_range) { for (i = 0; i < op_array->last_live_range; i++) { op_array->live_range[i].var = @@ -233,5 +293,6 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c } zend_arena_release(&ctx->arena, checkpoint); - op_array->T = max + 1; + op_array->T -= max_diff; + op_array->stack_size -= max_diff * sizeof(zval); } diff --git a/ext/opcache/Optimizer/zend_call_graph.c b/ext/opcache/Optimizer/zend_call_graph.c index 2d163c5ae133a..638ba59d9061e 100644 --- a/ext/opcache/Optimizer/zend_call_graph.c +++ b/ext/opcache/Optimizer/zend_call_graph.c @@ -110,7 +110,6 @@ static void zend_collect_args_info(zend_call_info *call_info) call_info->arg_info[num].opline = opline; } break; - case ZEND_SEND_ARRAY: case ZEND_SEND_USER: case ZEND_SEND_UNPACK: // ??? @@ -129,6 +128,7 @@ static void zend_collect_args_info(zend_call_info *call_info) case ZEND_DO_ICALL: case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: + case ZEND_DO_UNPACK_FCALL: level--; break; } @@ -190,6 +190,7 @@ static int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t case ZEND_DO_FCALL: case ZEND_DO_ICALL: case ZEND_DO_UCALL: + case ZEND_DO_UNPACK_FCALL: case ZEND_DO_FCALL_BY_NAME: func_info->flags |= ZEND_FUNC_HAS_CALLS; call--; diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c index c7399316842e6..1009d900ea793 100644 --- a/ext/opcache/Optimizer/zend_cfg.c +++ b/ext/opcache/Optimizer/zend_cfg.c @@ -278,6 +278,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b case ZEND_DO_FCALL: case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: + case ZEND_DO_UNPACK_FCALL: flags |= ZEND_FUNC_HAS_CALLS; if (build_flags & ZEND_CFG_STACKLESS) { BB_START(i + 1); diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index aeb2c42542f54..73041110c0fea 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -63,19 +63,19 @@ int zend_optimizer_lookup_cv(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_var) { + while (i < op_array->last_var + op_array->num_args) { if (op_array->vars[i] == name || (ZSTR_H(op_array->vars[i]) == hash_value && ZSTR_LEN(op_array->vars[i]) == ZSTR_LEN(name) && memcmp(ZSTR_VAL(op_array->vars[i]), ZSTR_VAL(name), ZSTR_LEN(name)) == 0)) { - return (int)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, i); + return (int)(zend_intptr_t)(i >= op_array->num_args ? ZEND_CALL_VAR_NUM(NULL, i - op_array->num_args) : ZEND_CALL_ARG(NULL, i + 1)); } i++; } i = op_array->last_var; op_array->last_var++; - op_array->vars = erealloc(op_array->vars, op_array->last_var * sizeof(zend_string*)); - op_array->vars[i] = zend_string_dup(name, 0); + op_array->vars = erealloc(op_array->vars, (op_array->last_var + op_array->num_args) * sizeof(zend_string*)); + op_array->vars[op_array->num_args + i] = zend_string_dup(name, 0); /* all IS_TMP_VAR and IS_VAR variable numbers have to be adjusted */ { @@ -695,20 +695,23 @@ static void zend_optimize_op_array(zend_op_array *op_array, static void zend_adjust_fcall_stack_size(zend_op_array *op_array, zend_optimizer_ctx *ctx) { zend_function *func; - zend_op *opline, *end; - - opline = op_array->opcodes; - end = opline + op_array->last; - while (opline < end) { - if (opline->opcode == ZEND_INIT_FCALL) { + zend_op *opline, *start; + + start = op_array->opcodes; + opline = start + op_array->last; + while (--opline >= start) { + if (opline->opcode == ZEND_DO_UCALL) { + zend_op *tmp = opline; + do { + --tmp; + } while (tmp->opcode != ZEND_INIT_FCALL || tmp->result.var != opline->op1.var); func = zend_hash_find_ptr( &ctx->script->function_table, - Z_STR_P(RT_CONSTANT(op_array, opline->op2))); + Z_STR_P(RT_CONSTANT(op_array, tmp->op2))); if (func) { - opline->op1.num = zend_vm_calc_used_stack(opline->extended_value, func); + opline->op2.num = zend_vm_calc_used_stack(0, func); } } - opline++; } } diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index ee8c6bad88649..b5f364bdbbf1b 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -446,13 +446,13 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra } } - if (op_array->vars) { + if (op_array->vars || op_array->num_args) { zend_string **p, **end; SERIALIZE_PTR(op_array->vars); p = op_array->vars; UNSERIALIZE_PTR(p); - end = p + op_array->last_var; + end = p + op_array->last_var + op_array->num_args; while (p < end) { if (!IS_SERIALIZED(*p)) { SERIALIZE_STR(*p); @@ -1020,12 +1020,12 @@ static void zend_file_cache_unserialize_op_array(zend_op_array *op_arr } } - if (op_array->vars) { + if (op_array->vars || op_array->num_args) { zend_string **p, **end; UNSERIALIZE_PTR(op_array->vars); p = op_array->vars; - end = p + op_array->last_var; + end = p + op_array->last_var + op_array->num_args; while (p < end) { if (!IS_UNSERIALIZED(*p)) { UNSERIALIZE_STR(*p); diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index d7c56cdfe433b..8f36105263ab4 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -645,15 +645,15 @@ 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->vars) { + if (op_array->vars || op_array->num_args) { if (already_stored) { persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->vars); ZEND_ASSERT(persist_ptr != NULL); op_array->vars = (zend_string**)persist_ptr; } else { int i; - zend_accel_store(op_array->vars, sizeof(zend_string*) * op_array->last_var); - for (i = 0; i < op_array->last_var; i++) { + zend_accel_store(op_array->vars, sizeof(zend_string*) * (op_array->num_args + op_array->last_var)); + for (i = 0; i < op_array->last_var + op_array->num_args; i++) { zend_accel_store_interned_string(op_array->vars[i]); } } diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index 0431054f76ff8..4546da4596635 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -246,11 +246,11 @@ 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->vars) { + if (op_array->vars || op_array->num_args) { int i; - ADD_DUP_SIZE(op_array->vars, sizeof(zend_string*) * op_array->last_var); - for (i = 0; i < op_array->last_var; i++) { + ADD_DUP_SIZE(op_array->vars, sizeof(zend_string*) * (op_array->last_var + op_array->num_args)); + for (i = 0; i < op_array->last_var + op_array->num_args; i++) { ADD_INTERNED_STRING(op_array->vars[i], 0); } } diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 21205b5624fea..63ce396d1674d 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -1968,7 +1968,7 @@ ZEND_METHOD(reflection_function, invoke) fci.symbol_table = NULL; fci.object = NULL; fci.retval = &retval; - fci.param_count = num_args; + fci.param_count = -num_args; fci.params = params; fci.no_separation = 1; @@ -3259,8 +3259,8 @@ ZEND_METHOD(reflection_method, invoke) fci.symbol_table = NULL; fci.object = object; fci.retval = &retval; - fci.param_count = num_args - 1; - fci.params = params + 1; + fci.param_count = 1 - num_args; + fci.params = params - 1; fci.no_separation = 1; fcc.initialized = 1; @@ -4889,8 +4889,8 @@ ZEND_METHOD(reflection_class, newInstance) RETURN_FALSE; } - for (i = 0; i < num_args; i++) { - if (Z_REFCOUNTED(params[i])) Z_ADDREF(params[i]); + for (i = 0; i > -num_args; i--) { + Z_TRY_ADDREF(params[i]); } fci.size = sizeof(fci); @@ -4899,7 +4899,7 @@ ZEND_METHOD(reflection_class, newInstance) fci.symbol_table = NULL; fci.object = Z_OBJ_P(return_value); fci.retval = &retval; - fci.param_count = num_args; + fci.param_count = -num_args; fci.params = params; fci.no_separation = 1; @@ -4911,7 +4911,7 @@ ZEND_METHOD(reflection_class, newInstance) ret = zend_call_function(&fci, &fcc); zval_ptr_dtor(&retval); - for (i = 0; i < num_args; i++) { + for (i = 0; i > -num_args; i--) { zval_ptr_dtor(¶ms[i]); } if (ret == FAILURE) { diff --git a/ext/session/session.c b/ext/session/session.c index 61ccc343171ca..b8a3e83f9a23d 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -1942,7 +1942,7 @@ static PHP_FUNCTION(session_set_save_handler) /* At this point argc can only be between 6 and PS_NUM_APIS */ for (i = 0; i < argc; i++) { - if (!zend_is_callable(&args[i], 0, &name)) { + if (!zend_is_callable(&args[-i], 0, &name)) { php_error_docref(NULL, E_WARNING, "Argument %d is not a valid callback", i+1); zend_string_release(name); RETURN_FALSE; @@ -1962,7 +1962,7 @@ static PHP_FUNCTION(session_set_save_handler) if (!Z_ISUNDEF(PS(mod_user_names).names[i])) { zval_ptr_dtor(&PS(mod_user_names).names[i]); } - ZVAL_COPY(&PS(mod_user_names).names[i], &args[i]); + ZVAL_COPY(&PS(mod_user_names).names[i], &args[-i]); } RETURN_TRUE; diff --git a/ext/soap/soap.c b/ext/soap/soap.c index b6fc5a0f3dabf..e047dec1b758d 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -93,7 +93,7 @@ static void soap_error_handler(int error_num, const char *error_filename, const int _old_soap_version = SOAP_GLOBAL(soap_version);\ zend_bool _old_in_compilation = CG(in_compilation); \ zend_execute_data *_old_current_execute_data = EG(current_execute_data); \ - zval *_old_stack_top = EG(vm_stack_top); \ + zend_vm_stack _old_stack = EG(vm_stack); \ int _bailout = 0;\ SOAP_GLOBAL(use_soap_error_handler) = 1;\ SOAP_GLOBAL(error_code) = "Client";\ @@ -108,17 +108,12 @@ static void soap_error_handler(int error_num, const char *error_filename, const !instanceof_function(EG(exception)->ce, soap_fault_class_entry)) {\ _bailout = 1;\ }\ - if (_old_stack_top != EG(vm_stack_top)) { \ - while (EG(vm_stack)->prev != NULL && \ - ((char*)_old_stack_top < (char*)EG(vm_stack) || \ - (char*) _old_stack_top > (char*)EG(vm_stack)->end)) { \ - zend_vm_stack tmp = EG(vm_stack)->prev; \ - efree(EG(vm_stack)); \ - EG(vm_stack) = tmp; \ - EG(vm_stack_end) = tmp->end; \ - } \ - EG(vm_stack)->top = _old_stack_top; \ + while (EG(vm_stack)->prev != NULL && _old_stack != EG(vm_stack)) {\ + zend_vm_stack tmp = EG(vm_stack)->prev; \ + efree(EG(vm_stack)); \ + EG(vm_stack) = tmp; \ } \ + EG(vm_stack_end) = EG(vm_stack)->end; \ } zend_end_try();\ SOAP_GLOBAL(use_soap_error_handler) = _old_handler;\ SOAP_GLOBAL(error_code) = _old_error_code;\ diff --git a/ext/standard/array.c b/ext/standard/array.c index 79c9ab6207ad5..b58e628c30fbc 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -1361,7 +1361,7 @@ PHP_FUNCTION(min) min = &args[0]; - for (i = 1; i < argc; i++) { + for (i = -1; i > -argc; i--) { is_smaller_function(&result, &args[i], min); if (Z_TYPE(result) == IS_TRUE) { min = &args[i]; @@ -1408,7 +1408,7 @@ PHP_FUNCTION(max) max = &args[0]; - for (i = 1; i < argc; i++) { + for (i = -1; i > -argc; i--) { is_smaller_or_equal_function(&result, &args[i], max); if (Z_TYPE(result) == IS_FALSE) { max = &args[i]; @@ -1967,7 +1967,7 @@ static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_valu PHP_FUNCTION(compact) { zval *args = NULL; /* function arguments array */ - uint32_t num_args, i; + int num_args, i; zend_array *symbol_table; if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &num_args) == FAILURE) { @@ -1982,10 +1982,10 @@ PHP_FUNCTION(compact) if (ZEND_NUM_ARGS() == 1 && Z_TYPE(args[0]) == IS_ARRAY) { array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0]))); } else { - array_init_size(return_value, ZEND_NUM_ARGS()); + array_init_size(return_value, num_args); } - for (i=0; i -num_args; i--) { php_compact_var(symbol_table, return_value, &args[i]); } } @@ -2515,7 +2515,7 @@ PHP_FUNCTION(array_push) } /* For each subsequent argument, make it a reference, increase refcount, and add it to the end of the array */ - for (i = 0; i < argc; i++) { + for (i = 0; i > -argc; i--) { ZVAL_COPY(&new_var, &args[i]); if (zend_hash_next_index_insert(Z_ARRVAL_P(stack), &new_var) == NULL) { @@ -2726,7 +2726,7 @@ PHP_FUNCTION(array_unshift) } zend_hash_init(&new_hash, zend_hash_num_elements(Z_ARRVAL_P(stack)) + argc, NULL, ZVAL_PTR_DTOR, 0); - for (i = 0; i < argc; i++) { + for (i = 0; i > -argc; i--) { if (Z_REFCOUNTED(args[i])) { Z_ADDREF(args[i]); } @@ -2742,7 +2742,7 @@ PHP_FUNCTION(array_unshift) } ZEND_HASH_FOREACH_END(); } else { uint32_t old_idx; - uint32_t new_idx = i; + uint32_t new_idx = argc; uint32_t iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), 0); ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) { @@ -3136,7 +3136,7 @@ static inline void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETE #endif for (i = 0; i < argc; i++) { - zval *arg = args + i; + zval *arg = args - i; ZVAL_DEREF(arg); if (Z_TYPE_P(arg) != IS_ARRAY) { @@ -3180,13 +3180,13 @@ static inline void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETE if (recursive) { for (i = 1; i < argc; i++) { - arg = args + i; + arg = args - i; ZVAL_DEREF(arg); php_array_replace_recursive(Z_ARRVAL_P(return_value), Z_ARRVAL_P(arg)); } } else { for (i = 1; i < argc; i++) { - arg = args + i; + arg = args - i; ZVAL_DEREF(arg); zend_hash_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(arg), zval_add_ref, 1); } @@ -3217,13 +3217,13 @@ static inline void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETE if (recursive) { for (i = 1; i < argc; i++) { - arg = args + i; + arg = args - i; ZVAL_DEREF(arg); php_array_merge_recursive(Z_ARRVAL_P(return_value), Z_ARRVAL_P(arg)); } } else { for (i = 1; i < argc; i++) { - arg = args + i; + arg = args - i; ZVAL_DEREF(arg); php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(arg)); } @@ -3847,7 +3847,7 @@ static void php_array_intersect_key(INTERNAL_FUNCTION_PARAMETERS, int data_compa } for (i = 0; i < argc; i++) { - if (Z_TYPE(args[i]) != IS_ARRAY) { + if (Z_TYPE(args[-i]) != IS_ARRAY) { php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1); RETURN_NULL(); } @@ -3868,7 +3868,7 @@ static void php_array_intersect_key(INTERNAL_FUNCTION_PARAMETERS, int data_compa } if (p->key == NULL) { ok = 1; - for (i = 1; i < argc; i++) { + for (i = -1; i > -argc; i--) { if ((data = zend_hash_index_find(Z_ARRVAL(args[i]), p->h)) == NULL || (intersect_data_compare_func && intersect_data_compare_func(val, data) != 0) @@ -3885,7 +3885,7 @@ static void php_array_intersect_key(INTERNAL_FUNCTION_PARAMETERS, int data_compa } } else { ok = 1; - for (i = 1; i < argc; i++) { + for (i = -1; i > -argc; i--) { if ((data = zend_hash_find_ind(Z_ARRVAL(args[i]), p->key)) == NULL || (intersect_data_compare_func && intersect_data_compare_func(val, data) != 0) @@ -4023,12 +4023,12 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int } for (i = 0; i < arr_argc; i++) { - if (Z_TYPE(args[i]) != IS_ARRAY) { + if (Z_TYPE(args[-i]) != IS_ARRAY) { php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1); arr_argc = i; /* only free up to i - 1 */ goto out; } - hash = Z_ARRVAL(args[i]); + hash = Z_ARRVAL(args[-i]); list = (Bucket *) pemalloc((hash->nNumOfElements + 1) * sizeof(Bucket), hash->u.flags & HASH_FLAG_PERSISTENT); if (!list) { PHP_ARRAY_CMP_FUNC_RESTORE(); @@ -4160,7 +4160,7 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int } out: for (i = 0; i < arr_argc; i++) { - hash = Z_ARRVAL(args[i]); + hash = Z_ARRVAL(args[-i]); pefree(lists[i], hash->u.flags & HASH_FLAG_PERSISTENT); } @@ -4270,7 +4270,7 @@ static void php_array_diff_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_ty } for (i = 0; i < argc; i++) { - if (Z_TYPE(args[i]) != IS_ARRAY) { + if (Z_TYPE(args[-i]) != IS_ARRAY) { php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1); RETURN_NULL(); } @@ -4292,7 +4292,7 @@ static void php_array_diff_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_ty if (p->key == NULL) { ok = 1; for (i = 1; i < argc; i++) { - if ((data = zend_hash_index_find(Z_ARRVAL(args[i]), p->h)) != NULL && + if ((data = zend_hash_index_find(Z_ARRVAL(args[-i]), p->h)) != NULL && (!diff_data_compare_func || diff_data_compare_func(val, data) == 0) ) { @@ -4309,7 +4309,7 @@ static void php_array_diff_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_ty } else { ok = 1; for (i = 1; i < argc; i++) { - if ((data = zend_hash_find_ind(Z_ARRVAL(args[i]), p->key)) != NULL && + if ((data = zend_hash_find_ind(Z_ARRVAL(args[-i]), p->key)) != NULL && (!diff_data_compare_func || diff_data_compare_func(val, data) == 0) ) { @@ -4445,12 +4445,12 @@ static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_ } for (i = 0; i < arr_argc; i++) { - if (Z_TYPE(args[i]) != IS_ARRAY) { + if (Z_TYPE(args[-i]) != IS_ARRAY) { php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1); arr_argc = i; /* only free up to i - 1 */ goto out; } - hash = Z_ARRVAL(args[i]); + hash = Z_ARRVAL(args[-i]); list = (Bucket *) pemalloc((hash->nNumOfElements + 1) * sizeof(Bucket), hash->u.flags & HASH_FLAG_PERSISTENT); if (!list) { PHP_ARRAY_CMP_FUNC_RESTORE(); @@ -4580,7 +4580,7 @@ static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_ } out: for (i = 0; i < arr_argc; i++) { - hash = Z_ARRVAL(args[i]); + hash = Z_ARRVAL(args[-i]); pefree(lists[i], hash->u.flags & HASH_FLAG_PERSISTENT); } @@ -4637,11 +4637,11 @@ PHP_FUNCTION(array_diff) /* count number of elements */ num = 0; for (i = 1; i < argc; i++) { - if (Z_TYPE(args[i]) != IS_ARRAY) { + if (Z_TYPE(args[-i]) != IS_ARRAY) { php_error_docref(NULL, E_WARNING, "Argument #%d is not an array", i + 1); RETURN_NULL(); } - num += zend_hash_num_elements(Z_ARRVAL(args[i])); + num += zend_hash_num_elements(Z_ARRVAL(args[-i])); } if (num == 0) { @@ -4653,7 +4653,7 @@ PHP_FUNCTION(array_diff) /* create exclude map */ zend_hash_init(&exclude, num, NULL, NULL, 0); for (i = 1; i < argc; i++) { - ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL(args[i]), value) { + ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL(args[-i]), value) { str = zval_get_string(value); zend_hash_add(&exclude, str, &dummy); zend_string_release(str); @@ -4794,7 +4794,7 @@ PHP_FUNCTION(array_multisort) * accordingly. There can't be two sort flags of the same type after an * array, and the very first argument has to be an array. */ for (i = 0; i < argc; i++) { - zval *arg = &args[i]; + zval *arg = &args[-i]; ZVAL_DEREF(arg); if (Z_TYPE_P(arg) == IS_ARRAY) { @@ -5278,13 +5278,13 @@ PHP_FUNCTION(array_map) uint32_t *array_pos = (HashPosition *)ecalloc(n_arrays, sizeof(HashPosition)); for (i = 0; i < n_arrays; i++) { - if (Z_TYPE(arrays[i]) != IS_ARRAY) { + if (Z_TYPE(arrays[-i]) != IS_ARRAY) { php_error_docref(NULL, E_WARNING, "Argument #%d should be an array", i + 2); efree(array_pos); return; } - if (zend_hash_num_elements(Z_ARRVAL(arrays[i])) > maxlen) { - maxlen = zend_hash_num_elements(Z_ARRVAL(arrays[i])); + if (zend_hash_num_elements(Z_ARRVAL(arrays[-i])) > maxlen) { + maxlen = zend_hash_num_elements(Z_ARRVAL(arrays[-i])); } } @@ -5305,11 +5305,11 @@ PHP_FUNCTION(array_map) * parameter list, otherwise use null value. */ uint32_t pos = array_pos[i]; while (1) { - if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) { + if (pos >= Z_ARRVAL(arrays[-i])->nNumUsed) { ZVAL_NULL(&zv); break; - } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) { - ZVAL_COPY(&zv, &Z_ARRVAL(arrays[i])->arData[pos].val); + } else if (Z_TYPE(Z_ARRVAL(arrays[-i])->arData[pos].val) != IS_UNDEF) { + ZVAL_COPY(&zv, &Z_ARRVAL(arrays[-i])->arData[pos].val); array_pos[i] = pos + 1; break; } @@ -5331,11 +5331,11 @@ PHP_FUNCTION(array_map) * parameter list, otherwise use null value. */ uint32_t pos = array_pos[i]; while (1) { - if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) { + if (pos >= Z_ARRVAL(arrays[-i])->nNumUsed) { ZVAL_NULL(¶ms[i]); break; - } else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) { - ZVAL_COPY(¶ms[i], &Z_ARRVAL(arrays[i])->arData[pos].val); + } else if (Z_TYPE(Z_ARRVAL(arrays[-i])->arData[pos].val) != IS_UNDEF) { + ZVAL_COPY(¶ms[i], &Z_ARRVAL(arrays[-i])->arData[pos].val); array_pos[i] = pos + 1; break; } diff --git a/ext/standard/formatted_print.c b/ext/standard/formatted_print.c index e206bb92253fd..b2b7a4f090bd1 100644 --- a/ext/standard/formatted_print.c +++ b/ext/standard/formatted_print.c @@ -411,37 +411,37 @@ php_formatted_print(zend_execute_data *execute_data, int use_array, int format_o WRONG_PARAM_COUNT_WITH_RETVAL(NULL); } - convert_to_string_ex(&args[format_offset]); + convert_to_string_ex(&args[-format_offset]); if (use_array) { - int i = 1; + int i = -1; zval *zv; zval *array; - z_format = &args[format_offset]; - array = &args[1 + format_offset]; + z_format = &args[-format_offset]; + array = &args[-1 - format_offset]; if (Z_TYPE_P(array) != IS_ARRAY) { convert_to_array(array); } argc = 1 + zend_hash_num_elements(Z_ARRVAL_P(array)); - newargs = (zval *)safe_emalloc(argc, sizeof(zval), 0); + newargs = ((zval *)safe_emalloc(argc, sizeof(zval), 0)) + argc - 1; ZVAL_COPY_VALUE(&newargs[0], z_format); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), zv) { ZVAL_COPY_VALUE(&newargs[i], zv); - i++; + --i; } ZEND_HASH_FOREACH_END(); args = newargs; format_offset = 0; } - format = Z_STRVAL(args[format_offset]); - format_len = Z_STRLEN(args[format_offset]); + format = Z_STRVAL(args[-format_offset]); + format_len = Z_STRLEN(args[-format_offset]); result = zend_string_alloc(size, 0); currarg = 1; - while (inpos < Z_STRLEN(args[format_offset])) { + while (inpos < Z_STRLEN(args[-format_offset])) { int expprec = 0; zval *tmp; @@ -472,7 +472,7 @@ php_formatted_print(zend_execute_data *execute_data, int use_array, int format_o if (argnum <= 0) { efree(result); if (newargs) { - efree(newargs); + efree(newargs - argc + 1); } php_error_docref(NULL, E_WARNING, "Argument number must be greater than zero"); return NULL; @@ -515,7 +515,7 @@ php_formatted_print(zend_execute_data *execute_data, int use_array, int format_o if ((width = php_sprintf_getnumber(format, &inpos)) < 0) { efree(result); if (newargs) { - efree(newargs); + efree(newargs - argc + 1); } php_error_docref(NULL, E_WARNING, "Width must be greater than zero and less than %d", INT_MAX); return NULL; @@ -534,7 +534,7 @@ php_formatted_print(zend_execute_data *execute_data, int use_array, int format_o if ((precision = php_sprintf_getnumber(format, &inpos)) < 0) { efree(result); if (newargs) { - efree(newargs); + efree(newargs - argc + 1); } php_error_docref(NULL, E_WARNING, "Precision must be greater than zero and less than %d", INT_MAX); return NULL; @@ -556,7 +556,7 @@ php_formatted_print(zend_execute_data *execute_data, int use_array, int format_o if (argnum >= argc) { efree(result); if (newargs) { - efree(newargs); + efree(newargs - argc + 1); } php_error_docref(NULL, E_WARNING, "Too few arguments"); return NULL; @@ -567,7 +567,7 @@ php_formatted_print(zend_execute_data *execute_data, int use_array, int format_o } PRINTF_DEBUG(("sprintf: format character='%c'\n", format[inpos])); /* now we expect to find a type specifier */ - tmp = &args[argnum]; + tmp = &args[-argnum]; switch (format[inpos]) { case 's': { zend_string *str = zval_get_string(tmp); @@ -653,7 +653,7 @@ php_formatted_print(zend_execute_data *execute_data, int use_array, int format_o } if (newargs) { - efree(newargs); + efree(newargs - argc + 1); } /* possibly, we have to make sure we have room for the terminating null? */ diff --git a/ext/standard/pack.c b/ext/standard/pack.c index f044ab5ce2827..e02d9c7043254 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -179,8 +179,8 @@ PHP_FUNCTION(pack) } if (arg < 0) { - convert_to_string(&argv[currentarg]); - arg = Z_STRLEN(argv[currentarg]); + convert_to_string(&argv[-currentarg]); + arg = Z_STRLEN(argv[-currentarg]); if (code == 'Z') { /* add one because Z is always NUL-terminated: * pack("Z*", "aa") === "aa\0" @@ -336,7 +336,7 @@ PHP_FUNCTION(pack) case 'Z': { int arg_cp = (code != 'Z') ? arg : MAX(0, arg - 1); - zend_string *str = zval_get_string(&argv[currentarg++]); + zend_string *str = zval_get_string(&argv[-currentarg++]); memset(&ZSTR_VAL(output)[outputpos], (code == 'a' || code == 'Z') ? '\0' : ' ', arg); memcpy(&ZSTR_VAL(output)[outputpos], ZSTR_VAL(str), @@ -352,7 +352,7 @@ PHP_FUNCTION(pack) int nibbleshift = (code == 'h') ? 0 : 4; int first = 1; - zend_string *str = zval_get_string(&argv[currentarg++]); + zend_string *str = zval_get_string(&argv[-currentarg++]); char *v = ZSTR_VAL(str); outputpos--; @@ -393,7 +393,7 @@ PHP_FUNCTION(pack) case 'c': case 'C': while (arg-- > 0) { - php_pack(&argv[currentarg++], 1, byte_map, &ZSTR_VAL(output)[outputpos]); + php_pack(&argv[-currentarg++], 1, byte_map, &ZSTR_VAL(output)[outputpos]); outputpos++; } break; @@ -411,7 +411,7 @@ PHP_FUNCTION(pack) } while (arg-- > 0) { - php_pack(&argv[currentarg++], 2, map, &ZSTR_VAL(output)[outputpos]); + php_pack(&argv[-currentarg++], 2, map, &ZSTR_VAL(output)[outputpos]); outputpos += 2; } break; @@ -420,7 +420,7 @@ PHP_FUNCTION(pack) case 'i': case 'I': while (arg-- > 0) { - php_pack(&argv[currentarg++], sizeof(int), int_map, &ZSTR_VAL(output)[outputpos]); + php_pack(&argv[-currentarg++], sizeof(int), int_map, &ZSTR_VAL(output)[outputpos]); outputpos += sizeof(int); } break; @@ -438,7 +438,7 @@ PHP_FUNCTION(pack) } while (arg-- > 0) { - php_pack(&argv[currentarg++], 4, map, &ZSTR_VAL(output)[outputpos]); + php_pack(&argv[-currentarg++], 4, map, &ZSTR_VAL(output)[outputpos]); outputpos += 4; } break; @@ -458,7 +458,7 @@ PHP_FUNCTION(pack) } while (arg-- > 0) { - php_pack(&argv[currentarg++], 8, map, &ZSTR_VAL(output)[outputpos]); + php_pack(&argv[-currentarg++], 8, map, &ZSTR_VAL(output)[outputpos]); outputpos += 8; } break; @@ -467,7 +467,7 @@ PHP_FUNCTION(pack) case 'f': { while (arg-- > 0) { - float v = (float) zval_get_double(&argv[currentarg++]); + float v = (float) zval_get_double(&argv[-currentarg++]); memcpy(&ZSTR_VAL(output)[outputpos], &v, sizeof(v)); outputpos += sizeof(v); } @@ -476,7 +476,7 @@ PHP_FUNCTION(pack) case 'd': { while (arg-- > 0) { - double v = (double) zval_get_double(&argv[currentarg++]); + double v = (double) zval_get_double(&argv[-currentarg++]); memcpy(&ZSTR_VAL(output)[outputpos], &v, sizeof(v)); outputpos += sizeof(v); } diff --git a/ext/standard/scanf.c b/ext/standard/scanf.c index 2bbf34a7bfe0a..3b08f3e3045ca 100644 --- a/ext/standard/scanf.c +++ b/ext/standard/scanf.c @@ -622,8 +622,8 @@ PHPAPI int php_sscanf_internal( char *string, char *format, * If any variables are passed, make sure they are all passed by reference */ if (numVars) { - for (i = varStart;i < argCount;i++){ - if ( ! Z_ISREF(args[ i ] ) ) { + for (i = varStart; i < argCount; i++){ + if (!Z_ISREF(args[-i])) { php_error_docref(NULL, E_WARNING, "Parameter %d must be passed by reference", i); scan_set_error_return(numVars, return_value); return SCAN_ERROR_VAR_PASSED_BYVAL; @@ -741,7 +741,7 @@ PHPAPI int php_sscanf_internal( char *string, char *format, if (numVars && objIndex >= argCount) { break; } else if (numVars) { - current = Z_REFVAL(args[objIndex++]); + current = Z_REFVAL(args[-objIndex++]); zval_ptr_dtor(current); ZVAL_LONG(current, (zend_long)(string - baseString) ); } else { @@ -860,7 +860,7 @@ PHPAPI int php_sscanf_internal( char *string, char *format, if (numVars && objIndex >= argCount) { break; } else if (numVars) { - current = Z_REFVAL(args[objIndex++]); + current = Z_REFVAL(args[-objIndex++]); zval_ptr_dtor(current); ZVAL_STRINGL(current, string, end-string); } else { @@ -901,7 +901,7 @@ PHPAPI int php_sscanf_internal( char *string, char *format, if (numVars && objIndex >= argCount) { break; } else if (numVars) { - current = Z_REFVAL(args[objIndex++]); + current = Z_REFVAL(args[-objIndex++]); zval_ptr_dtor(current); ZVAL_STRINGL(current, string, end-string); } else { @@ -922,7 +922,7 @@ PHPAPI int php_sscanf_internal( char *string, char *format, char __buf[2]; __buf[0] = sch; __buf[1] = '\0';; - current = args[objIndex++]; + current = args[-objIndex++]; zval_dtor(*current); ZVAL_STRINGL( *current, __buf, 1); } else { @@ -1055,7 +1055,7 @@ PHPAPI int php_sscanf_internal( char *string, char *format, break; } else if (numVars) { /* change passed value type to string */ - current = Z_REFVAL(args[objIndex++]); + current = Z_REFVAL(args[-objIndex++]); zval_ptr_dtor(current); ZVAL_STRING(current, buf); } else { @@ -1065,7 +1065,7 @@ PHPAPI int php_sscanf_internal( char *string, char *format, if (numVars && objIndex >= argCount) { break; } else if (numVars) { - current = Z_REFVAL(args[objIndex++]); + current = Z_REFVAL(args[-objIndex++]); zval_ptr_dtor(current); ZVAL_LONG(current, value); } else { @@ -1170,7 +1170,7 @@ PHPAPI int php_sscanf_internal( char *string, char *format, if (numVars && objIndex >= argCount) { break; } else if (numVars) { - current = Z_REFVAL(args[objIndex++]); + current = Z_REFVAL(args[-objIndex++]); zval_ptr_dtor(current); ZVAL_DOUBLE(current, dvalue); } else { diff --git a/ext/standard/string.c b/ext/standard/string.c index 01c7c6dffe189..a1f791133427d 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -4499,7 +4499,7 @@ PHP_FUNCTION(setlocale) break; } } else { - plocale = &args[i]; + plocale = &args[-i]; } loc = zval_get_string(plocale); diff --git a/ext/standard/tests/general_functions/call_user_func_array_variation_003.phpt b/ext/standard/tests/general_functions/call_user_func_array_variation_003.phpt index 5ab5e461bf879..12f27df204a5a 100644 --- a/ext/standard/tests/general_functions/call_user_func_array_variation_003.phpt +++ b/ext/standard/tests/general_functions/call_user_func_array_variation_003.phpt @@ -109,102 +109,102 @@ foreach($inputs as $key =>$value) { *** Testing call_user_func_array() : usage variation *** --int 0-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, integer given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, integer given, %s(%d) NULL --int 1-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, integer given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, integer given, %s(%d) NULL --int 12345-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, integer given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, integer given, %s(%d) NULL --int -12345-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, integer given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, integer given, %s(%d) NULL --float 10.5-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, float given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, float given, %s(%d) NULL --float -10.5-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, float given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, float given, %s(%d) NULL --float 12.3456789000e10-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, float given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, float given, %s(%d) NULL --float -12.3456789000e10-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, float given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, float given, %s(%d) NULL --float .5-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, float given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, float given, %s(%d) NULL --uppercase NULL-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, null given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, null given, %s(%d) NULL --lowercase null-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, null given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, null given, %s(%d) NULL --lowercase true-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, boolean given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, boolean given, %s(%d) NULL --lowercase false-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, boolean given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, boolean given, %s(%d) NULL --uppercase TRUE-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, boolean given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, boolean given, %s(%d) NULL --uppercase FALSE-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, boolean given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, boolean given, %s(%d) NULL --empty string DQ-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, string given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, string given, %s(%d) NULL --empty string SQ-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, string given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, string given, %s(%d) NULL --string DQ-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, string given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, string given, %s(%d) NULL --string SQ-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, string given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, string given, %s(%d) NULL --mixed case string-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, string given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, string given, %s(%d) NULL --heredoc-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, string given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, string given, %s(%d) NULL --instance of classWithToString-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, object given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, object of type classWithToString given, %s(%d) NULL --instance of classWithoutToString-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, object given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, object of type classWithoutToString given, %s(%d) NULL --undefined var-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, null given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, null given, %s(%d) NULL --unset var-- -Error: 2 - call_user_func_array() expects parameter 2 to be array, null given, %s(%d) +Error: 2 - call_user_func_array() expects parameter 2 to be array or Traversable, null given, %s(%d) NULL ===DONE=== diff --git a/ext/standard/var.c b/ext/standard/var.c index 7ae9fcf105b46..e17b02032a407 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -201,7 +201,7 @@ PHP_FUNCTION(var_dump) return; } - for (i = 0; i < argc; i++) { + for (i = 0; i > -argc; i--) { php_var_dump(&args[i], 1); } } @@ -365,7 +365,7 @@ PHP_FUNCTION(debug_zval_dump) return; } - for (i = 0; i < argc; i++) { + for (i = 0; i > -argc; --i) { php_debug_zval_dump(&args[i], 1); } } diff --git a/ext/wddx/wddx.c b/ext/wddx/wddx.c index d719be9d1e075..6d3d5826a0ebe 100644 --- a/ext/wddx/wddx.c +++ b/ext/wddx/wddx.c @@ -1108,7 +1108,7 @@ PHP_FUNCTION(wddx_serialize_vars) php_wddx_packet_start(packet, NULL, 0); php_wddx_add_chunk_static(packet, WDDX_STRUCT_S); - for (i=0; i -num_args; i--) { zval *arg; if (!Z_ISREF(args[i])) { arg = &args[i]; @@ -1217,7 +1217,7 @@ PHP_FUNCTION(wddx_add_vars) RETURN_FALSE; } - for (i=0; i -num_args; i--) { zval *arg; if (!Z_ISREF(args[i])) { arg = &args[i]; diff --git a/sapi/cli/php_cli.c b/sapi/cli/php_cli.c index b4288b87a2db6..02be264fb0daa 100644 --- a/sapi/cli/php_cli.c +++ b/sapi/cli/php_cli.c @@ -1059,7 +1059,9 @@ static int do_cli(int argc, char **argv) /* {{{ */ { zend_class_entry *pce = NULL; zval arg, ref; - zend_execute_data execute_data; + zend_function func; + func.type = ZEND_INTERNAL_FUNCTION; + func.common.stack_size = ZEND_CALL_FRAME_SLOT * sizeof(zval); switch (behavior) { default: @@ -1085,8 +1087,8 @@ static int do_cli(int argc, char **argv) /* {{{ */ ZVAL_STRING(&arg, reflection_what); object_init_ex(&ref, pce); - memset(&execute_data, 0, sizeof(zend_execute_data)); - EG(current_execute_data) = &execute_data; + EG(current_execute_data) = zend_push_top_call_frame(ZEND_CALL_TOP, &func, 0, NULL, NULL); + EG(current_execute_data)->prev_execute_data = NULL; zend_call_method_with_1_params(&ref, pce, &pce->constructor, "__construct", NULL, &arg); if (EG(exception)) { diff --git a/sapi/phpdbg/phpdbg_opcode.c b/sapi/phpdbg/phpdbg_opcode.c index a792090275b2d..b2b8bbafd55d1 100644 --- a/sapi/phpdbg/phpdbg_opcode.c +++ b/sapi/phpdbg/phpdbg_opcode.c @@ -42,7 +42,7 @@ static inline char *phpdbg_decode_op(zend_op_array *ops, znode_op *op, uint32_t switch (type) { case IS_CV: { - zend_string *var = ops->vars[EX_VAR_TO_NUM(op->var)]; + zend_string *var = RT_CV_DEF_OF(ops, EX_VAR_TO_NUM(op->var)); spprintf(&decode, 0, "$%.*s%c", ZSTR_LEN(var) <= 19 ? (int) ZSTR_LEN(var) : 18, ZSTR_VAL(var), ZSTR_LEN(var) <= 19 ? 0 : '+'); @@ -115,6 +115,7 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op) /*{{{ */ case ZEND_JMPNZ_EX: case ZEND_JMP_SET: case ZEND_ASSERT_CHECK: + case ZEND_NEW: spprintf(&decode[2], 0, "J%td", OP_JMP_ADDR(op, op->op2) - ops->opcodes); break; @@ -125,16 +126,6 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op) /*{{{ */ } break; - case ZEND_SEND_VAL: - case ZEND_SEND_VAL_EX: - case ZEND_SEND_VAR: - case ZEND_SEND_VAR_NO_REF: - case ZEND_SEND_REF: - case ZEND_SEND_VAR_EX: - case ZEND_SEND_USER: - spprintf(&decode[2], 0, "%" PRIu32, op->op2.num); - break; - default: decode[2] = phpdbg_decode_op(ops, &op->op2, op->op2_type); break; diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 50971b25ecc51..d749f77332c93 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -802,8 +802,6 @@ PHPDBG_COMMAND(ev) /* {{{ */ PHPDBG_OUTPUT_BACKUP(); - original_stack->top = EG(vm_stack_top); - if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) { phpdbg_try_access { phpdbg_parse_variable(param->str, param->len, &EG(symbol_table), 0, phpdbg_output_ev_variable, 0); @@ -845,7 +843,6 @@ PHPDBG_COMMAND(ev) /* {{{ */ } EG(current_execute_data) = original_execute_data; EG(scope) = original_scope; - EG(vm_stack_top) = original_stack->top; EG(vm_stack_end) = original_stack->end; EG(vm_stack) = original_stack; EG(exit_status) = 0; @@ -1621,10 +1618,11 @@ void phpdbg_execute_ex(zend_execute_data *execute_data) /* {{{ */ PHPDBG_G(last_line) = execute_data->opline->lineno; /* stupid hack to make zend_do_fcall_common_helper return ZEND_VM_ENTER() instead of recursively calling zend_execute() and eventually segfaulting */ - if ((execute_data->opline->opcode == ZEND_DO_FCALL || - execute_data->opline->opcode == ZEND_DO_UCALL || - execute_data->opline->opcode == ZEND_DO_FCALL_BY_NAME) && - execute_data->call->func->type == ZEND_USER_FUNCTION) { + if ((EX(opline)->opcode == ZEND_DO_FCALL || + EX(opline)->opcode == ZEND_DO_UCALL || + EX(opline)->opcode == ZEND_DO_UNPACK_FCALL || + EX(opline)->opcode == ZEND_DO_FCALL_BY_NAME) && + ((zend_execute_data *) EX_VAR(EX(opline->op1.var)))->func->type == ZEND_USER_FUNCTION) { zend_execute_ex = execute_ex; } PHPDBG_G(vmret) = zend_vm_call_opcode_handler(execute_data); diff --git a/sapi/phpdbg/tests/print_001.phpt b/sapi/phpdbg/tests/print_001.phpt index 1f7a5ac0b9404..e3477e4ea2b3f 100644 --- a/sapi/phpdbg/tests/print_001.phpt +++ b/sapi/phpdbg/tests/print_001.phpt @@ -13,19 +13,19 @@ q prompt> [User Function foo (8 ops)] L14-16 foo() %s - %s + 8 ops L14 #0 RECV 1 $baz - L15 #1 INIT_FCALL%s %d %s "var_dump" - L15 #2 INIT_FCALL%s %d %s "strrev" - L15 #3 SEND_VAR $baz 1 - L15 #4 DO_%cCALL @0 - L15 #5 SEND_VAR @0 1 - L15 #6 DO_%cCALL + L15 #1 INIT_FCALL%s %d %s "var_dump" ~3 + L15 #2 INIT_FCALL%s %d %s "strrev" ~9 + L15 #3 SEND_VAR $baz ~9 @8 + L15 #4 DO_%cCALL ~9 @0 + L15 #5 SEND_VAR @0 ~3 @2 + L15 #6 DO_%cCALL ~3 L16 #7 RETURN null prompt> [User Class: Foo\Bar (2 methods)] L5-7 Foo\Bar::Foo() %s - %s + 5 ops L5 #0 RECV 1 $bar - L6 #1 INIT_NS_FCALL_BY_NAME "Foo\\var_dump" - L6 #2 SEND_VAR_EX $bar 1 - L6 #3 DO_FCALL + L6 #1 INIT_NS_FCALL_BY_NAME "Foo\\var_dump" ~7 + L6 #2 SEND_VAR_EX $bar ~7 @6 + L6 #3 DO_FCALL ~7 L7 #4 RETURN null L9-9 Foo\Bar::baz() %s - %s + 1 ops L9 #0 RETURN null @@ -34,14 +34,14 @@ prompt> [Context %s (11 ops)] L1-19 {main}() %s - %s + 11 ops L4 #0 NOP L14 #1 NOP - L18 #2 NEW "Foo\\Bar" @1 - L18 #3 DO_FCALL - L18 #4 INIT_METHOD_CALL @1 "Foo" - L18 #5 SEND_VAL_EX "test" 1 - L18 #6 DO_FCALL - L19 #7 INIT_FCALL%s %d %s "foo" - L19 #8 SEND_VAL "test" 1 - L19 #9 DO_FCALL + L18 #2 NEW "Foo\\Bar" J4 @1 + L18 #3 DO_FCALL ~10 + L18 #4 INIT_METHOD_CALL @1 "Foo" ~11 + L18 #5 SEND_VAL_EX "test" ~11 @10 + L18 #6 DO_FCALL ~11 + L19 #7 INIT_FCALL%s %d %s "foo" ~6 + L19 #8 SEND_VAL "test" ~6 @5 + L19 #9 DO_FCALL ~6 L19 #10 RETURN 1 prompt> --FILE-- diff --git a/sapi/phpdbg/tests/print_002.phpt b/sapi/phpdbg/tests/print_002.phpt index 3a824986c112a..1b76f9f2e491f 100644 --- a/sapi/phpdbg/tests/print_002.phpt +++ b/sapi/phpdbg/tests/print_002.phpt @@ -19,14 +19,14 @@ prompt> string(4) "test" prompt> [Stack in foo() (8 ops)] L14-16 foo() %s - %s + 8 ops L14 #0 RECV 1 $baz - L15 #1 INIT_FCALL%s %d %s "var_dump" - L15 #2 INIT_FCALL%s %d %s "strrev" - L15 #3 SEND_VAR $baz 1 - L15 #4 DO_%cCALL @0 - L15 #5 SEND_VAR @0 1 - L15 #6 DO_%cCALL + L15 #1 INIT_FCALL%s %d %s "var_dump" ~3 + L15 #2 INIT_FCALL%s %d %s "strrev" ~9 + L15 #3 SEND_VAR $baz ~9 @8 + L15 #4 DO_%cCALL ~9 @0 + L15 #5 SEND_VAR @0 ~3 @2 + L15 #6 DO_%cCALL ~3 L16 #7 RETURN null -prompt> [L15 %s INIT_FCALL%s %d %s "var_dump" %s] +prompt> [L15 %s INIT_FCALL%s %d %s "var_dump" ~3 %s] prompt> --FILE-- Date: Tue, 22 Dec 2015 19:50:39 +0100 Subject: [PATCH 2/4] Move fcall/arg temp generation to zend_compile.c --- Zend/zend_compile.c | 224 +++++++++++++------ Zend/zend_compile.h | 7 +- Zend/zend_opcode.c | 159 +++---------- ext/opcache/Optimizer/block_pass.c | 23 +- ext/opcache/Optimizer/optimize_temp_vars_5.c | 67 +----- ext/opcache/Optimizer/zend_dump.c | 12 +- ext/opcache/Optimizer/zend_ssa.c | 14 +- 7 files changed, 226 insertions(+), 280 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ac69b06e3b3dd..94d516978abee 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -238,6 +238,7 @@ void zend_oparray_context_begin(zend_oparray_context *prev_context) /* {{{ */ CG(context).last_brk_cont = 0; CG(context).brk_cont_array = NULL; CG(context).labels = NULL; + CG(context).current_arg = 0; } /* }}} */ @@ -1878,7 +1879,7 @@ static inline void zend_make_tmp_result(znode *result, zend_op *opline) /* {{{ * } /* }}} */ -static void zend_find_live_range(zend_op *opline, zend_uchar type, uint32_t var) /* {{{ */ +static void zend_find_live_range(zend_op *opline, zend_uchar type, uint32_t var, uint32_t range_type) /* {{{ */ { zend_op *def = opline; @@ -1917,7 +1918,7 @@ static void zend_find_live_range(zend_op *opline, zend_uchar type, uint32_t var) zend_start_live_range(CG(active_op_array), def + 1 - CG(active_op_array)->opcodes), opline - CG(active_op_array)->opcodes, - ZEND_LIVE_TMPVAR, def->result.var); + range_type, def->result.var); break; } } @@ -1955,7 +1956,7 @@ static void zend_check_live_ranges(zend_op *opline) /* {{{ */ if (opline->opcode == ZEND_OP_DATA) { if (!zend_is_def_range(opline - 2, opline->op1_type, opline->op1.var)) { - zend_find_live_range(opline - 1, opline->op1_type, opline->op1.var); + zend_find_live_range(opline - 1, opline->op1_type, opline->op1.var, ZEND_LIVE_TMPVAR); } } else if (opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || opline->opcode == ZEND_NEW || @@ -1978,7 +1979,7 @@ static void zend_check_live_ranges(zend_op *opline) /* {{{ */ opline->opcode == ZEND_VERIFY_RETURN_TYPE) { /* these opcodes are handled separately */ } else { - zend_find_live_range(opline, opline->op1_type, opline->op1.var); + zend_find_live_range(opline, opline->op1_type, opline->op1.var, ZEND_LIVE_TMPVAR); } } @@ -1987,7 +1988,7 @@ static void zend_check_live_ranges(zend_op *opline) /* {{{ */ if (opline->opcode == ZEND_OP_DATA) { if (!zend_is_def_range(opline - 2, opline->op2_type, opline->op2.var)) { - zend_find_live_range(opline-1, opline->op2_type, opline->op2.var); + zend_find_live_range(opline-1, opline->op2_type, opline->op2.var, ZEND_LIVE_TMPVAR); } } else if (opline->opcode == ZEND_FETCH_STATIC_PROP_R || opline->opcode == ZEND_FETCH_STATIC_PROP_W || @@ -2000,7 +2001,7 @@ static void zend_check_live_ranges(zend_op *opline) /* {{{ */ opline->opcode == ZEND_INSTANCEOF) { /* classes don't have to be destroyed */ } else { - zend_find_live_range(opline, opline->op2_type, opline->op2.var); + zend_find_live_range(opline, opline->op2_type, opline->op2.var, ZEND_LIVE_TMPVAR); } } } @@ -2172,7 +2173,7 @@ static zend_op *zend_delayed_compile_end(uint32_t offset) /* {{{ */ } /* }}} */ -static void zend_adjust_for_fetch_type(zend_op *opline, uint32_t type, zend_bool delayed) /* {{{ */ +static void zend_adjust_for_fetch_type(zend_op *opline, uint64_t type, zend_bool delayed) /* {{{ */ { zend_uchar factor = (opline->opcode == ZEND_FETCH_STATIC_PROP_R) ? 1 : 3; @@ -2190,14 +2191,16 @@ static void zend_adjust_for_fetch_type(zend_op *opline, uint32_t type, zend_bool return; case BP_VAR_FUNC_ARG: opline->opcode += 4 * factor; - opline->extended_value |= type >> BP_VAR_SHIFT; + opline->extended_value |= ((uint32_t) type) >> BP_VAR_SHIFT; if (opline->opcode != ZEND_FETCH_FUNC_ARG) { if (delayed) { - zend_delayed_emit_op(NULL, ZEND_OP_DATA, NULL, NULL); + opline = zend_delayed_emit_op(NULL, ZEND_OP_DATA, NULL, NULL); } else { - zend_emit_op_data(NULL); + opline = zend_emit_op_data(NULL); } } + opline->op2.var = (uint32_t) (type >> 32); + opline->op2_type = IS_ARG; return; case BP_VAR_UNSET: opline->opcode += 5 * factor; @@ -2442,7 +2445,7 @@ static int zend_try_compile_cv(znode *result, zend_ast *ast) /* {{{ */ } /* }}} */ -static zend_op *zend_compile_simple_var_no_cv(znode *result, zend_ast *ast, uint32_t type, int delayed) /* {{{ */ +static zend_op *zend_compile_simple_var_no_cv(znode *result, zend_ast *ast, uint64_t type, int delayed) /* {{{ */ { zend_ast *name_ast = ast->child[0]; znode name_node; @@ -2478,7 +2481,7 @@ static zend_op *zend_compile_simple_var_no_cv(znode *result, zend_ast *ast, uint } /* }}} */ -static void zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t type, int delayed) /* {{{ */ +static void zend_compile_simple_var(znode *result, zend_ast *ast, uint64_t type, int delayed) /* {{{ */ { if (zend_try_compile_cv(result, ast) == FAILURE) { zend_op *opline = zend_compile_simple_var_no_cv(result, ast, type, delayed); @@ -2487,7 +2490,7 @@ static void zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t type, } /* }}} */ -static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, uint32_t type) /* {{{ */ +static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, uint64_t type) /* {{{ */ { if (type != BP_VAR_R && type != BP_VAR_IS && zend_is_call(ast)) { if (node->op_type == IS_VAR) { @@ -2501,7 +2504,7 @@ static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, uint32_t } /* }}} */ -void zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type); +void zend_delayed_compile_var(znode *result, zend_ast *ast, uint64_t type); void zend_compile_assign(znode *result, zend_ast *ast); static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_node); @@ -2519,7 +2522,7 @@ static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node) } /* }}} */ -static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ +static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint64_t type) /* {{{ */ { zend_ast *var_ast = ast->child[0]; zend_ast *dim_ast = ast->child[1]; @@ -2546,7 +2549,7 @@ static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t } /* }}} */ -static inline zend_op *zend_compile_dim_common(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ +static inline zend_op *zend_compile_dim_common(znode *result, zend_ast *ast, uint64_t type) /* {{{ */ { uint32_t offset = zend_delayed_compile_begin(); zend_delayed_compile_dim(result, ast, type); @@ -2554,7 +2557,7 @@ static inline zend_op *zend_compile_dim_common(znode *result, zend_ast *ast, uin } /* }}} */ -void zend_compile_dim(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ +void zend_compile_dim(znode *result, zend_ast *ast, uint64_t type) /* {{{ */ { zend_op *opline = zend_compile_dim_common(result, ast, type); zend_adjust_for_fetch_type(opline, type, 0); @@ -2572,7 +2575,7 @@ static zend_bool is_this_fetch(zend_ast *ast) /* {{{ */ } /* }}} */ -static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ +static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint64_t type) /* {{{ */ { zend_ast *obj_ast = ast->child[0]; zend_ast *prop_ast = ast->child[1]; @@ -2598,7 +2601,7 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t } /* }}} */ -static zend_op *zend_compile_prop_common(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ +static zend_op *zend_compile_prop_common(znode *result, zend_ast *ast, uint64_t type) /* {{{ */ { uint32_t offset = zend_delayed_compile_begin(); zend_delayed_compile_prop(result, ast, type); @@ -2606,14 +2609,14 @@ static zend_op *zend_compile_prop_common(znode *result, zend_ast *ast, uint32_t } /* }}} */ -void zend_compile_prop(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ +void zend_compile_prop(znode *result, zend_ast *ast, uint64_t type) /* {{{ */ { zend_op *opline = zend_compile_prop_common(result, ast, type); zend_adjust_for_fetch_type(opline, type, 0); } /* }}} */ -zend_op *zend_compile_static_prop_common(znode *result, zend_ast *ast, uint32_t type, int delayed) /* {{{ */ +zend_op *zend_compile_static_prop_common(znode *result, zend_ast *ast, uint64_t type, int delayed) /* {{{ */ { zend_ast *class_ast = ast->child[0]; zend_ast *prop_ast = ast->child[1]; @@ -2646,7 +2649,7 @@ zend_op *zend_compile_static_prop_common(znode *result, zend_ast *ast, uint32_t } /* }}} */ -void zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type, int delayed) /* {{{ */ +void zend_compile_static_prop(znode *result, zend_ast *ast, uint64_t type, int delayed) /* {{{ */ { zend_op *opline = zend_compile_static_prop_common(result, ast, type, delayed); zend_adjust_for_fetch_type(opline, type, delayed); @@ -2920,10 +2923,26 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */ { zend_ast_list *args = zend_ast_get_list(ast); uint32_t i, live_var; - zend_bool uses_arg_unpack = 0; zend_op *opline; znode arg_node, unpack_node; - uint32_t arg_count = 0; /* number of arguments not including unpacks */ + uint32_t arg_count, ex_offset, arg_offset; /* number of arguments not including unpacks */ + + for (arg_count = args->children; arg_count > 0; arg_count--) { + if (args->child[arg_count - 1]->kind != ZEND_AST_UNPACK) { + break; + } + } + + if (fbc && args->children == arg_count) { + if (ZEND_USER_CODE(fbc->type) && arg_count < fbc->op_array.num_args) { + CG(context).current_arg += fbc->op_array.num_args - arg_count; + } + } else { + CG(context).current_arg += ZEND_RESERVED_RECV_SLOTS; + } + + arg_offset = ex_offset = CG(context).current_arg + arg_count; + CG(context).current_arg = ex_offset + ZEND_CALL_FRAME_SLOT; for (i = 0; i < args->children; ++i) { zend_ast *arg = args->child[i]; @@ -2935,36 +2954,43 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */ if (arg->kind == ZEND_AST_UNPACK) { fbc = NULL; - zend_compile_expr(&arg_node, arg->child[0]); - if (uses_arg_unpack++) { - opline = zend_emit_op(NULL, ZEND_SEND_UNPACK, &arg_node, NULL); - SET_NODE(opline->result, &unpack_node); - opline->extended_value = ZEND_ARG_IS_UNPACKED; - } else { - if (arg_num == args->children) { - unpack_node = arg_node; - continue; + if (arg_num != args->children) { + live_var = zend_start_live_range(CG(active_op_array), get_next_op_number(CG(active_op_array))); + zend_compile_expr(&arg_node, arg->child[0]); + opline = zend_emit_op_tmp(&unpack_node, ZEND_SEND_UNPACK, &arg_node, NULL); + opline->extended_value = arg_num; + opline->op2.var = ex_offset; + opline->op2_type = IS_ARG; + + while (++i < args->children) { + arg = args->child[i]; + if (arg->kind != ZEND_AST_UNPACK) { + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot use positional argument after argument unpacking"); + } + + zend_compile_expr(&arg_node, arg->child[0]); + opline = zend_emit_op(NULL, ZEND_SEND_UNPACK, &arg_node, NULL); + SET_NODE(opline->result, &unpack_node); + opline->extended_value = ZEND_ARG_IS_UNPACKED | arg_num; + opline->op2.var = ex_offset; + opline->op2_type = IS_ARG; } - live_var = zend_start_live_range(CG(active_op_array), get_next_op_number(CG(active_op_array)) - 1); - opline = zend_emit_op_tmp(&unpack_node, ZEND_SEND_UNPACK, &arg_node, NULL); - opline->extended_value = 0; - uses_arg_unpack++; + opline = zend_emit_op(&arg_node, ZEND_DO_UNPACK_FCALL, NULL, &unpack_node); + opline->extended_value = arg_num | ZEND_ARG_IS_UNPACKED; + zend_end_live_range(CG(active_op_array), live_var, get_next_op_number(CG(active_op_array)) - 1, ZEND_LIVE_TMPVAR, unpack_node.u.op.var); + } else { + zend_compile_expr(&arg_node, arg->child[0]); + opline = zend_emit_op(&arg_node, ZEND_DO_UNPACK_FCALL, NULL, &arg_node); + opline->extended_value = arg_num; } - opline->extended_value |= arg_count + 1; - continue; - } - - if (uses_arg_unpack) { - zend_error_noreturn(E_COMPILE_ERROR, - "Cannot use positional argument after argument unpacking"); + break; } - arg_count++; if (zend_is_variable(arg)) { if (zend_is_call(arg)) { zend_compile_var(&arg_node, arg, BP_VAR_R); -/* TODO: ZEND_SEND_VAL is redundant here for IS_TMP_VAR */ if (arg_node.op_type & (IS_CONST|IS_TMP_VAR)) { /* Function call was converted into builtin instruction */ opcode = ZEND_SEND_VAL; @@ -2988,7 +3014,7 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */ } } else { zend_compile_var(&arg_node, arg, - BP_VAR_FUNC_ARG | (arg_num << BP_VAR_SHIFT)); + (((uint64_t) ex_offset) << 32) | BP_VAR_FUNC_ARG | (arg_num << BP_VAR_SHIFT)); opcode = ZEND_SEND_VAR_EX; } } else { @@ -3013,8 +3039,10 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */ opline = zend_emit_op(NULL, opcode, &arg_node, NULL); opline->extended_value = arg_num; - /* temporary value, to be used and changed via zend_convert_arg_num_to_temps(); order must be maintained! */ - opline->result.num = zend_start_live_range(CG(active_op_array), opline - CG(active_op_array)->opcodes + 1); + opline->op2.var = ex_offset; + opline->op2_type = IS_ARG; + opline->result.var = --arg_offset; + opline->result_type = IS_ARG; if (opcode == ZEND_SEND_VAR_NO_REF) { if (fbc) { @@ -3031,15 +3059,10 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */ } } - if (uses_arg_unpack) { - opline = zend_emit_op(&arg_node, ZEND_DO_UNPACK_FCALL, NULL, &unpack_node); - opline->extended_value = arg_count + 1; - if (uses_arg_unpack > 1) { - zend_end_live_range(CG(active_op_array), live_var, get_next_op_number(CG(active_op_array)) - 1, ZEND_LIVE_TMPVAR, unpack_node.u.op.var); - opline->extended_value |= ZEND_ARG_IS_UNPACKED; - } + if (CG(context).current_arg > CG(active_op_array)->last_arg) { + CG(active_op_array)->last_arg = CG(context).current_arg; } - + CG(context).current_arg -= ZEND_CALL_FRAME_SLOT; return arg_count; } /* }}} */ @@ -3074,7 +3097,9 @@ void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function * zend_op *opline; uint32_t opnum_init = get_next_op_number(CG(active_op_array)) - 1; uint32_t arg_count; + int32_t i; uint32_t live_var = zend_start_live_range(CG(active_op_array), opnum_init + 1); + uint32_t old_arg = CG(context).current_arg; zend_uchar call_op; zend_bool is_variadic; @@ -3097,14 +3122,22 @@ void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function * } } - /* temporary value, to be used and changed via zend_convert_arg_num_to_temps(); order must be maintained! */ - opline->op1.num = live_var; + opline->op1.var = CG(context).current_arg; + opline->op1_type = IS_ARG; + zend_end_live_range(CG(active_op_array), live_var, get_next_op_number(CG(active_op_array)) - 1, ZEND_LIVE_EXECUTE_DATA, opline->op1.var); + + for (i = CG(context).current_arg - 1; i >= (int32_t) (CG(context).current_arg - arg_count); i--) { + zend_find_live_range(opline, IS_ARG, i, ZEND_LIVE_ARG); + } opline = &CG(active_op_array)->opcodes[opnum_init]; if (opline->opcode != ZEND_NEW) { - opline->result.num = is_variadic; + opline->result.var = CG(context).current_arg; + opline->result_type = IS_ARG; } + CG(context).current_arg = old_arg; + zend_do_extended_fcall_end(); } /* }}} */ @@ -3313,13 +3346,26 @@ int zend_compile_func_cufa(znode *result, zend_ast_list *args, zend_string *lcna return FAILURE; } - live_var = zend_start_live_range(CG(active_op_array), get_next_op_number(CG(active_op_array))); + CG(context).current_arg += ZEND_RESERVED_RECV_SLOTS; zend_compile_init_user_func(args->child[0], 0, lcname); + live_var = zend_start_live_range(CG(active_op_array), get_next_op_number(CG(active_op_array)) - 1); opline = &CG(active_op_array)->opcodes[get_next_op_number(CG(active_op_array)) - 1]; - opline->result.num = 1; + opline->result_type = IS_ARG; + opline->result.var = CG(context).current_arg; + + CG(context).current_arg += ZEND_CALL_FRAME_SLOT; zend_compile_expr(&arg_node, args->child[1]); + + if (CG(context).current_arg > CG(active_op_array)->last_arg) { + CG(active_op_array)->last_arg = CG(context).current_arg; + } + CG(context).current_arg -= ZEND_CALL_FRAME_SLOT + ZEND_RESERVED_RECV_SLOTS; + zend_end_live_range(CG(active_op_array), live_var, get_next_op_number(CG(active_op_array)), + ZEND_LIVE_EXECUTE_DATA, CG(context).current_arg); + opline = zend_emit_op(result, ZEND_DO_UNPACK_FCALL, NULL, &arg_node); - opline->op1.num = live_var; + opline->op1_type = IS_ARG; + opline->op1.var = CG(context).current_arg + ZEND_RESERVED_RECV_SLOTS; opline->extended_value = ZEND_ARG_IS_CUFA | 1; return SUCCESS; @@ -3329,22 +3375,31 @@ int zend_compile_func_cufa(znode *result, zend_ast_list *args, zend_string *lcna /* cuf = call_user_func */ int zend_compile_func_cuf(znode *result, zend_ast_list *args, zend_string *lcname) /* {{{ */ { - uint32_t i, live_var; + uint32_t live_var, old_arg, arg_offset, ex_offset, i; zend_op *opline; if (args->children < 1 || zend_args_contain_unpack(args)) { return FAILURE; } - live_var = zend_start_live_range(CG(active_op_array), get_next_op_number(CG(active_op_array))); zend_compile_init_user_func(args->child[0], args->children - 1, lcname); + live_var = zend_start_live_range(CG(active_op_array), get_next_op_number(CG(active_op_array)) - 1); + old_arg = CG(context).current_arg; + arg_offset = ex_offset = old_arg + args->children - 1; + CG(context).current_arg = old_arg + ZEND_CALL_FRAME_SLOT; + + opline = &CG(active_op_array)->opcodes[get_next_op_number(CG(active_op_array)) - 1]; + opline->result_type = IS_ARG; + opline->result.var = ex_offset; + for (i = 1; i < args->children; ++i) { zend_ast *arg_ast = args->child[i]; znode arg_node; zend_bool send_user = 0; if (zend_is_variable(arg_ast) && !zend_is_call(arg_ast)) { - zend_compile_var(&arg_node, arg_ast, BP_VAR_FUNC_ARG | (i << BP_VAR_SHIFT)); + zend_compile_var(&arg_node, arg_ast, + (((uint64_t) ex_offset) << 32) | BP_VAR_FUNC_ARG | (i << BP_VAR_SHIFT)); send_user = 1; } else { zend_compile_expr(&arg_node, arg_ast); @@ -3360,11 +3415,26 @@ int zend_compile_func_cuf(znode *result, zend_ast_list *args, zend_string *lcnam } opline->extended_value = i; - /* temporary value, to be used and changed via zend_convert_arg_num_to_temps(); order must be maintained! */ - opline->result.num = zend_start_live_range(CG(active_op_array), opline - CG(active_op_array)->opcodes + 1); + opline->op2.var = ex_offset; + opline->op2_type = IS_ARG; + opline->result.var = --arg_offset; + opline->result_type = IS_ARG; + } + + if (CG(context).current_arg > CG(active_op_array)->last_arg) { + CG(active_op_array)->last_arg = CG(context).current_arg; } + CG(context).current_arg = old_arg; + zend_end_live_range(CG(active_op_array), live_var, get_next_op_number(CG(active_op_array)), + ZEND_LIVE_EXECUTE_DATA, ex_offset); + opline = zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL); - opline->op1.num = live_var; + opline->op1.var = ex_offset; + opline->op1_type = IS_ARG; + + for (i = CG(context).current_arg; i < CG(context).current_arg + args->children - 1; i++) { + zend_find_live_range(opline, IS_ARG, i, ZEND_LIVE_ARG); + } return SUCCESS; } @@ -3482,7 +3552,7 @@ int zend_try_compile_special_func(znode *result, zend_string *lcname, zend_ast_l } /* }}} */ -void zend_compile_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ +void zend_compile_call(znode *result, zend_ast *ast, uint64_t type) /* {{{ */ { zend_ast *name_ast = ast->child[0]; zend_ast *args_ast = ast->child[1]; @@ -3544,7 +3614,7 @@ void zend_compile_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ } /* }}} */ -void zend_compile_method_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ +void zend_compile_method_call(znode *result, zend_ast *ast, uint64_t type) /* {{{ */ { zend_ast *obj_ast = ast->child[0]; zend_ast *method_ast = ast->child[1]; @@ -3585,7 +3655,7 @@ static zend_bool zend_is_constructor(zend_string *name) /* {{{ */ } /* }}} */ -void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ +void zend_compile_static_call(znode *result, zend_ast *ast, uint64_t type) /* {{{ */ { zend_ast *class_ast = ast->child[0]; zend_ast *method_ast = ast->child[1]; @@ -6642,8 +6712,14 @@ void zend_compile_include_or_eval(znode *result, zend_ast *ast) /* {{{ */ zend_compile_expr(&expr_node, expr_ast); opline = zend_emit_op(result, ZEND_INCLUDE_OR_EVAL, NULL, &expr_node); + opline->op1_type = IS_ARG; + opline->op1.var = CG(context).current_arg; opline->extended_value = ast->attr; + if (CG(context).current_arg < ZEND_CALL_FRAME_SLOT) { + CG(active_op_array)->last_arg = ZEND_CALL_FRAME_SLOT; + } + zend_do_extended_fcall_end(); } /* }}} */ @@ -7514,7 +7590,7 @@ void zend_compile_expr(znode *result, zend_ast *ast) /* {{{ */ } /* }}} */ -void zend_compile_var(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ +void zend_compile_var(znode *result, zend_ast *ast, uint64_t type) /* {{{ */ { switch (ast->kind) { case ZEND_AST_VAR: @@ -7553,7 +7629,7 @@ void zend_compile_var(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ } /* }}} */ -void zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ +void zend_delayed_compile_var(znode *result, zend_ast *ast, uint64_t type) /* {{{ */ { zend_op *opline; switch (ast->kind) { diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index ed481b0474d1e..759aecde1b5eb 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -134,7 +134,7 @@ typedef union _zend_parser_stack_elem { void zend_compile_top_stmt(zend_ast *ast); void zend_compile_stmt(zend_ast *ast); void zend_compile_expr(znode *node, zend_ast *ast); -void zend_compile_var(znode *node, zend_ast *ast, uint32_t type); +void zend_compile_var(znode *node, zend_ast *ast, uint64_t type); void zend_eval_const_expr(zend_ast **ast_ptr); void zend_const_expr_to_zval(zval *result, zend_ast *ast); @@ -178,6 +178,7 @@ typedef struct _zend_try_catch_element { #define ZEND_LIVE_SILENCE 2 #define ZEND_LIVE_ROPE 3 #define ZEND_LIVE_EXECUTE_DATA 4 +#define ZEND_LIVE_ARG 5 #define ZEND_LIVE_MASK 7 typedef struct _zend_live_range { @@ -198,6 +199,7 @@ typedef struct _zend_oparray_context { int last_brk_cont; zend_brk_cont_element *brk_cont_array; HashTable *labels; + uint32_t current_arg; } zend_oparray_context; /* method flags (types) */ @@ -374,6 +376,7 @@ struct _zend_op_array { int last_var; uint32_t T; + uint32_t last_arg; zend_string **vars; int last_live_range; @@ -691,6 +694,8 @@ struct _zend_execute_data { #define EXT_TYPE_UNUSED (1<<5) +#define IS_ARG (1<<6) /* to be used only during compilation */ + #include "zend_globals.h" BEGIN_EXTERN_C() diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index fbe21c104ecd1..fbd0c16dbbc06 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -66,6 +66,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->last_arg = 0; op_array->function_name = NULL; op_array->filename = zend_get_compiled_filename(); @@ -599,110 +600,9 @@ static uint32_t zend_get_brk_cont_target(const zend_op_array *op_array, const ze return opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont; } -static uint32_t zend_resolve_fcall(zend_op_array *op_array, zend_op **opline, uint32_t offset) { - uint32_t lr_off = 0, end; - uint32_t fcall_Ts, max_fcall_Ts = 0; - zend_op *init = *opline; - uint32_t num_args = init->extended_value; - uint32_t *live_ranges; - - if (init->opcode == ZEND_INCLUDE_OR_EVAL) { - init->op1.var = offset; - init->op1_type = IS_TMP_VAR; - return ZEND_CALL_FRAME_SLOT; - } - - live_ranges = emalloc(sizeof(uint32_t) * num_args); - - if (init->opcode == ZEND_INIT_FCALL && init->result.num == 0) { - zend_function *fbc = zend_hash_find_ptr(CG(function_table), Z_STR_P(CT_CONSTANT_EX(op_array, init->op2.constant))); - ZEND_ASSERT(fbc); - if (ZEND_USER_CODE(fbc->type)) { - num_args = MAX(num_args, fbc->op_array.num_args); - } - } else { - num_args += ZEND_RESERVED_RECV_SLOTS; - } - - if (init->opcode != ZEND_NEW) { - /* only one result var per opcode ... can't set object *and* execute_data as result ... maybe find a better solution? */ - init->result.var = offset + num_args; - init->result_type = IS_TMP_VAR; - } - - while (1) { - switch ((++*opline)->opcode) { - case ZEND_NEW: - case ZEND_INIT_FCALL_BY_NAME: - case ZEND_INIT_FCALL: - case ZEND_INIT_NS_FCALL_BY_NAME: - case ZEND_INIT_METHOD_CALL: - case ZEND_INIT_STATIC_METHOD_CALL: - case ZEND_INIT_USER_CALL: - case ZEND_INIT_DYNAMIC_CALL: - case ZEND_INCLUDE_OR_EVAL: - fcall_Ts = zend_resolve_fcall(op_array, opline, offset + num_args + ZEND_CALL_FRAME_SLOT); - if (fcall_Ts > max_fcall_Ts) { - max_fcall_Ts = fcall_Ts; - } - break; - - case ZEND_DO_FCALL: - case ZEND_DO_ICALL: - case ZEND_DO_UCALL: - case ZEND_DO_FCALL_BY_NAME: - case ZEND_DO_UNPACK_FCALL: - end = *opline - op_array->opcodes; - while (lr_off--) { - zend_live_range *range = op_array->live_range + live_ranges[lr_off]; - if (range->start == end && live_ranges[lr_off] == op_array->last_live_range - 1) { - op_array->last_live_range--; - } else { - range->end = end; - } - } - zend_end_live_range(op_array, (*opline)->op1.num, *opline - op_array->opcodes, ZEND_LIVE_EXECUTE_DATA, offset + num_args); - (*opline)->op1_type = IS_TMP_VAR; - (*opline)->op1.var = offset + num_args; - - efree(live_ranges); - return ZEND_CALL_FRAME_SLOT + num_args + max_fcall_Ts; - - case ZEND_SEND_VAL: - case ZEND_SEND_VAR_EX: - case ZEND_SEND_REF: - case ZEND_SEND_VAR_NO_REF: - case ZEND_SEND_VAL_EX: - case ZEND_SEND_VAR: - case ZEND_SEND_USER: - live_ranges[lr_off] = (*opline)->result.num; - (*opline)->result.var = num_args - ((*opline)->extended_value & ZEND_ARG_SEND_MASK) + offset; - (*opline)->result_type = IS_VAR; - op_array->live_range[live_ranges[lr_off]].var = ((*opline)->result.var * sizeof(zval)) | ZEND_LIVE_TMPVAR; - lr_off++; - case ZEND_SEND_UNPACK: - case ZEND_FETCH_FUNC_ARG: - (*opline)->op2.var = offset + num_args; - (*opline)->op2_type = IS_TMP_VAR; - break; - - /* No operands left, using ZEND_OP_DATA here */ - case ZEND_FETCH_STATIC_PROP_FUNC_ARG: - case ZEND_FETCH_DIM_FUNC_ARG: - case ZEND_FETCH_OBJ_FUNC_ARG: - (*opline)++; - ZEND_ASSERT((*opline)->opcode == ZEND_OP_DATA); - (*opline)->op2.var = offset + num_args; - (*opline)->op2_type = IS_TMP_VAR; - break; - } - } -} - ZEND_API int pass_two(zend_op_array *op_array) { - zend_op *opline, *end, *fcall_end = NULL; - uint32_t max_fcall_Ts = 0; + zend_op *opline, *end; if (!ZEND_USER_CODE(op_array->type)) { return 0; @@ -729,6 +629,22 @@ 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->live_range) { + uint32_t i; + for (i = 0; i < op_array->last_live_range; i++) { + uint32_t off = op_array->last_var; + uint32_t type = op_array->live_range[i].var & ZEND_LIVE_MASK; + if (type == ZEND_LIVE_EXECUTE_DATA) { + off = op_array->T + op_array->last_var; + } else if (type == ZEND_LIVE_ARG) { + off = op_array->T + op_array->last_var; + type = ZEND_LIVE_TMPVAR; // same handling + } + op_array->live_range[i].var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, off + (op_array->live_range[i].var / sizeof(zval))) | type; + } + } + opline = op_array->opcodes; end = opline + op_array->last; while (opline < end) { @@ -814,36 +730,29 @@ ZEND_API int pass_two(zend_op_array *op_array) break; case ZEND_NEW: ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2); - case ZEND_INIT_FCALL_BY_NAME: - case ZEND_INIT_FCALL: - case ZEND_INIT_NS_FCALL_BY_NAME: - case ZEND_INIT_METHOD_CALL: - case ZEND_INIT_STATIC_METHOD_CALL: - case ZEND_INIT_USER_CALL: - case ZEND_INIT_DYNAMIC_CALL: - case ZEND_INCLUDE_OR_EVAL: - if (opline > fcall_end) { - uint32_t fcall_Ts; - fcall_end = opline; - fcall_Ts = zend_resolve_fcall(op_array, &fcall_end, op_array->T); - if (max_fcall_Ts < fcall_Ts) { - max_fcall_Ts = fcall_Ts; - } - } break; } 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, op_array->last_var + opline->op1.var); + } else if (opline->op1_type == IS_ARG) { + opline->op1_type = IS_TMP_VAR; + opline->op1.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + op_array->T + opline->op1.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, op_array->last_var + opline->op2.var); + } else if (opline->op2_type == IS_ARG) { + opline->op2_type = IS_TMP_VAR; + opline->op2.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + op_array->T + opline->op2.var); } if (opline->result_type & (IS_VAR|IS_TMP_VAR)) { opline->result.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->result.var); + } else if (opline->result_type == IS_ARG) { + opline->result_type = IS_VAR; + opline->result.var = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + op_array->T + opline->result.var); } if ((zend_get_opcode_flags(opline->opcode) & ZEND_VM_EXT_MASK) == ZEND_VM_EXT_VAR) { opline->extended_value = (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + opline->extended_value); @@ -852,19 +761,7 @@ ZEND_API int pass_two(zend_op_array *op_array) opline++; } - op_array->T += max_fcall_Ts; - op_array->stack_size = (uint32_t)(zend_intptr_t)(((zval *) NULL) + (ZEND_CALL_FRAME_SLOT + op_array->T + op_array->last_var)); - - if (op_array->live_range) { - uint32_t i; - - for (i = 0; i < op_array->last_live_range; i++) { - op_array->live_range[i].var = - (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + (op_array->live_range[i].var / sizeof(zval))) | - (op_array->live_range[i].var & ZEND_LIVE_MASK); - } - } - + op_array->stack_size = (uint32_t)(zend_intptr_t)(((zval *) NULL) + (ZEND_CALL_FRAME_SLOT + op_array->last_arg + op_array->T + op_array->last_var)); op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO; return 0; } diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 4b42712aa0ae7..580bf9476551e 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -144,7 +144,7 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array /* Constant Propagation: strip X = QM_ASSIGN(const) */ if ((opline->op1_type & (IS_TMP_VAR|IS_VAR)) && - opline->opcode != ZEND_FREE) { + (zend_get_opcode_flags(opline->opcode) & ZEND_VM_OP1_CONST)) { src = VAR_SOURCE(opline->op1); if (src && src->opcode == ZEND_QM_ASSIGN && @@ -164,7 +164,8 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array } /* Constant Propagation: strip X = QM_ASSIGN(const) */ - if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) { + if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && + (zend_get_opcode_flags(opline->opcode) & ZEND_VM_OP2_CONST)) { src = VAR_SOURCE(opline->op2); if (src && src->opcode == ZEND_QM_ASSIGN && @@ -1296,7 +1297,7 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr if (1) { zend_op *target, *target_end; zend_basic_block *target_block; - int var_num = op_array->num_args + op_array->last_var + op_array->T; + int var_num = op_array->num_args + op_array->last_var + op_array->T + op_array->last_arg; if (var_num <= 0) { return; @@ -1491,7 +1492,7 @@ static void zend_t_usage(zend_cfg *cfg, zend_op_array *op_array, zend_bitset use } checkpoint = zend_arena_checkpoint(ctx->arena); - bitset_len = zend_bitset_len(op_array->last_var + op_array->T); + bitset_len = zend_bitset_len(op_array->last_var + op_array->T + op_array->last_arg); defined_here = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE); zend_bitset_clear(defined_here, bitset_len); @@ -1627,7 +1628,8 @@ static void zend_t_usage(zend_cfg *cfg, zend_op_array *op_array, zend_bitset use zend_bitset_excl(usage, VAR_NUM(opline->result.var)); } } else if (opline->result_type == IS_TMP_VAR) { - if (!zend_bitset_in(usage, VAR_NUM(opline->result.var))) { + /* do not optimize temporary targets inside fcall/arg range away */ + if (!zend_bitset_in(usage, VAR_NUM(opline->result.var)) && VAR_NUM(opline->result.var) < op_array->num_args + op_array->last_var + op_array->T) { switch (opline->opcode) { case ZEND_POST_INC: case ZEND_POST_DEC: @@ -1766,10 +1768,11 @@ void optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx) zend_dump_op_array(op_array, ZEND_DUMP_CFG, "before block pass", &cfg); } - if (op_array->last_var || op_array->T || op_array->num_args) { - bitset_len = zend_bitset_len(op_array->last_var + op_array->T); - Tsource = zend_arena_calloc(&ctx->arena, op_array->num_args + op_array->last_var + op_array->T, sizeof(zend_op *)); - same_t = zend_arena_alloc(&ctx->arena, op_array->num_args + op_array->last_var + op_array->T); + if (op_array->last_var || op_array->T || op_array->num_args || op_array->last_arg) { + int i; + bitset_len = zend_bitset_len(op_array->num_args + op_array->last_var + op_array->T + op_array->last_arg); + Tsource = zend_arena_calloc(&ctx->arena, op_array->num_args + op_array->last_var + op_array->T + op_array->last_arg, sizeof(zend_op *)); + same_t = zend_arena_alloc(&ctx->arena, op_array->num_args + op_array->last_var + op_array->T + op_array->last_arg); usage = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE); } else { bitset_len = 0; @@ -1793,7 +1796,7 @@ void optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx) if (!(b->flags & ZEND_BB_FOLLOW) || (b->flags & ZEND_BB_TARGET)) { /* Skip continuation of "extended" BB */ - memset(Tsource, 0, (op_array->num_args + op_array->last_var + op_array->T) * sizeof(zend_op *)); + memset(Tsource, 0, (op_array->num_args + op_array->last_var + op_array->T + op_array->last_arg) * sizeof(zend_op *)); } zend_optimize_block(b, op_array, usage, &cfg, Tsource); } diff --git a/ext/opcache/Optimizer/optimize_temp_vars_5.c b/ext/opcache/Optimizer/optimize_temp_vars_5.c index 5431d1a98d2a9..d56a3d99dafa9 100644 --- a/ext/opcache/Optimizer/optimize_temp_vars_5.c +++ b/ext/opcache/Optimizer/optimize_temp_vars_5.c @@ -39,45 +39,11 @@ max = i; \ } -/* we need to handle the fcall ops separately as they need to be always at the end of the op array */ -#define IS_FCALL_OP1_TMP(opcode) \ - (opcode == ZEND_DO_FCALL \ - || opcode == ZEND_DO_ICALL \ - || opcode == ZEND_DO_UCALL \ - || opcode == ZEND_DO_FCALL_BY_NAME \ - || opcode == ZEND_DO_UNPACK_FCALL \ - || opcode == ZEND_INCLUDE_OR_EVAL) -#define IS_SEND_OPCODE(opcode) \ - (opcode == ZEND_SEND_VAL \ - || opcode == ZEND_SEND_VAR_EX \ - || opcode == ZEND_SEND_REF \ - || opcode == ZEND_SEND_VAR_NO_REF \ - || opcode == ZEND_SEND_VAL_EX \ - || opcode == ZEND_SEND_VAR \ - || opcode == ZEND_SEND_USER) -#define IS_FCALL_OP2_TMP(opcode) \ - (IS_SEND_OPCODE(opcode) \ - || opcode == ZEND_SEND_UNPACK \ - || opcode == ZEND_FETCH_FUNC_ARG) -#define IS_FCALL_RESULT_TMP(opcode) \ - (IS_SEND_OPCODE(opcode) \ - || opcode == ZEND_INIT_FCALL_BY_NAME \ - || opcode == ZEND_INIT_FCALL \ - || opcode == ZEND_INIT_NS_FCALL_BY_NAME \ - || opcode == ZEND_INIT_METHOD_CALL \ - || opcode == ZEND_INIT_STATIC_METHOD_CALL \ - || opcode == ZEND_INIT_USER_CALL \ - || opcode == ZEND_INIT_DYNAMIC_CALL) -#define IS_FUNC_ARG_OP_DATA(opcode) \ - (opcode == ZEND_FETCH_DIM_FUNC_ARG \ - || opcode == ZEND_FETCH_OBJ_FUNC_ARG \ - || opcode == ZEND_FETCH_STATIC_PROP_FUNC_ARG) - void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *ctx) { int T = op_array->T; int offset = op_array->last_var; - int max = -1, max_old = -1, max_diff; + uint32_t last_T = NUM_VAR(T + offset); uint32_t bitset_len; zend_bitset taken_T; /* T index in use */ zend_op **start_of_T; /* opline where T is first used */ @@ -86,6 +52,7 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c zend_op *opline, *end; int currT; int i; + int max = -1, max_diff; int var_to_free = -1; void *checkpoint = zend_arena_checkpoint(ctx->arena); @@ -93,7 +60,7 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c taken_T = (zend_bitset) zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE); start_of_T = (zend_op **) zend_arena_alloc(&ctx->arena, T * sizeof(zend_op *)); valid_T = (zend_bitset) zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE); - map_T = (int *) zend_arena_alloc(&ctx->arena, T * sizeof(int)); + map_T = (int *) zend_arena_alloc(&ctx->arena, (T + op_array->last_arg) * sizeof(int)); end = op_array->opcodes; opline = &op_array->opcodes[op_array->last - 1]; @@ -113,11 +80,8 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c opline = &op_array->opcodes[op_array->last - 1]; while (opline >= end) { - if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) && !IS_FCALL_OP1_TMP(opline->opcode)) { + if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) && opline->op1.var < last_T) { currT = VAR_NUM(ZEND_OP1(opline).var) - offset; - if (currT > max_old) { - max_old = currT; - } if (opline->opcode == ZEND_ROPE_END) { int num = (((opline->extended_value + 1) * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval); int var; @@ -177,17 +141,13 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c } /* Skip OP_DATA */ - if (opline->opcode == ZEND_OP_DATA && - ((opline-1)->opcode == ZEND_ASSIGN_DIM || IS_FUNC_ARG_OP_DATA((opline-1)->opcode))) { + if (opline->opcode == ZEND_OP_DATA && (opline-1)->opcode == ZEND_ASSIGN_DIM) { opline--; continue; } - if ((ZEND_OP2_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) && !IS_FCALL_OP2_TMP(opline->opcode)) { + if ((ZEND_OP2_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) && opline->op2.var < last_T) { currT = VAR_NUM(ZEND_OP2(opline).var) - offset; - if (currT > max_old) { - max_old = currT; - } if (!zend_bitset_in(valid_T, currT)) { GET_AVAILABLE_T(); map_T[currT] = i; @@ -221,11 +181,8 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c var_to_free = i; } - if ((ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) && !IS_FCALL_RESULT_TMP(opline->opcode)) { + if ((ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) && opline->result.var < last_T) { currT = VAR_NUM(ZEND_RESULT(opline).var) - offset; - if (currT > max_old) { - max_old = currT; - } if (zend_bitset_in(valid_T, currT)) { if (start_of_T[currT] == opline) { /* ZEND_FAST_CALL can not share temporary var with others @@ -267,18 +224,18 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c opline--; } - max_diff = max_old - max; + max_diff = op_array->T - max - 1; for (opline = &op_array->opcodes[op_array->last - 1]; opline >= end; opline--) { - if (IS_FCALL_OP1_TMP(opline->opcode)) { + if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && opline->op1.var >= last_T) { map_T[VAR_NUM(opline->op1.var) - offset] = VAR_NUM(opline->op1.var) - offset - max_diff; opline->op1.var -= max_diff * sizeof(zval); } - if (IS_FCALL_OP2_TMP(opline->opcode) || (opline->opcode == ZEND_OP_DATA && IS_FUNC_ARG_OP_DATA((opline-1)->opcode))) { + if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && opline->op2.var >= last_T) { map_T[VAR_NUM(opline->op2.var) - offset] = VAR_NUM(opline->op2.var) - offset - max_diff; opline->op2.var -= max_diff * sizeof(zval); } - if (IS_FCALL_RESULT_TMP(opline->opcode)) { + if ((opline->result_type & (IS_VAR|IS_TMP_VAR)) && opline->result.var >= last_T) { map_T[VAR_NUM(opline->result.var) - offset] = VAR_NUM(opline->result.var) - offset - max_diff; opline->result.var -= max_diff * sizeof(zval); } @@ -293,6 +250,6 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c } zend_arena_release(&ctx->arena, checkpoint); - op_array->T -= max_diff; op_array->stack_size -= max_diff * sizeof(zval); + op_array->T -= max_diff; } diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c index 8150ac59ee1ba..a340816fb32b2 100644 --- a/ext/opcache/Optimizer/zend_dump.c +++ b/ext/opcache/Optimizer/zend_dump.c @@ -91,6 +91,11 @@ static void zend_dump_class_fetch_type(uint32_t fetch_type) void zend_dump_var(const zend_op_array *op_array, zend_uchar var_type, int var_num) { if (var_type == IS_CV && var_num < op_array->last_var) { + if (var_num < 0) { + var_num = - ZEND_CALL_FRAME_SLOT - var_num - 1; + } else { + var_num += op_array->num_args; + } fprintf(stderr, "CV%d($%s)", var_num, op_array->vars[var_num]->val); } else if (var_type == IS_VAR) { fprintf(stderr, "V%d", var_num); @@ -855,7 +860,7 @@ void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, cons if (func_info && func_info->num_args >= 0) { fprintf(stderr, "/%d", func_info->num_args); } - fprintf(stderr, ", vars=%d, tmps=%d", op_array->last_var, op_array->T); + fprintf(stderr, ", vars=%d, tmps=%d, fcalls=%d", op_array->last_var, op_array->T, op_array->last_arg); if (ssa) { fprintf(stderr, ", ssa_vars=%d", ssa->vars_count); } @@ -968,6 +973,9 @@ void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, cons case ZEND_LIVE_ROPE: fprintf(stderr, "(rope)\n"); break; + case ZEND_LIVE_EXECUTE_DATA: + fprintf(stderr, "(execute_data)\n"); + break; } } } @@ -1115,7 +1123,7 @@ static void zend_dump_var_set(const zend_op_array *op_array, const char *name, z uint32_t i; fprintf(stderr, " ; %s = {", name); - for (i = 0; i < op_array->last_var + op_array->T; i++) { + for (i = 0; i < op_array->last_var + op_array->T + op_array->last_arg; i++) { if (zend_bitset_in(set, i)) { if (first) { first = 0; diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index 86e7e2d6ff694..1026588407be0 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -86,8 +86,8 @@ static int zend_ssa_rename(const zend_op_array *op_array, zend_ssa *ssa, int *va // FIXME: Can we optimize this copying out in some cases? if (blocks[n].next_child >= 0) { - tmp = do_alloca(sizeof(int) * (op_array->last_var + op_array->T), use_heap); - memcpy(tmp, var, sizeof(int) * (op_array->last_var + op_array->T)); + tmp = do_alloca(sizeof(int) * (op_array->last_var + op_array->T + op_array->last_arg), use_heap); + memcpy(tmp, var, sizeof(int) * (op_array->last_var + op_array->T + op_array->last_arg)); var = tmp; } @@ -395,7 +395,7 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b ssa->blocks = ssa_blocks; /* Compute Variable Liveness */ - dfg.vars = op_array->last_var + op_array->T; + dfg.vars = op_array->last_var + op_array->T + op_array->last_arg; dfg.size = set_size = zend_bitset_len(dfg.vars); dfg.tmp = do_alloca((set_size * sizeof(zend_ulong)) * (blocks_count * 5 + 1), dfg_use_heap); memset(dfg.tmp, 0, (set_size * sizeof(zend_ulong)) * (blocks_count * 5 + 1)); @@ -443,7 +443,7 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b } while (changed); /* SSA construction, Step 2: Phi placement based on Dominance Frontiers */ - var = do_alloca(sizeof(int) * (op_array->last_var + op_array->T), var_use_heap); + var = do_alloca(sizeof(int) * (op_array->last_var + op_array->T + op_array->last_arg), var_use_heap); if (!var) { free_alloca(dfg.tmp, dfg_use_heap); return FAILURE; @@ -472,7 +472,7 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b } if (!zend_bitset_empty(tmp, set_size)) { - i = op_array->last_var + op_array->T; + i = op_array->last_var + op_array->T + op_array->last_arg; while (i > 0) { i--; if (zend_bitset_in(tmp, i)) { @@ -830,7 +830,7 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b } if (!zend_bitset_empty(tmp, set_size)) { - i = op_array->last_var + op_array->T; + i = op_array->last_var + op_array->T + op_array->last_arg; while (i > 0) { i--; if (zend_bitset_in(tmp, i)) { @@ -873,7 +873,7 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b /* SSA construction, Step 3: Renaming */ ssa->ops = zend_arena_calloc(arena, op_array->last, sizeof(zend_ssa_op)); memset(ssa->ops, 0xff, op_array->last * sizeof(zend_ssa_op)); - memset(var, 0xff, (op_array->last_var + op_array->T) * sizeof(int)); + memset(var, 0xff, (op_array->last_var + op_array->T + op_array->last_arg) * sizeof(int)); /* Create uninitialized SSA variables for each CV */ for (j = 0; j < op_array->last_var; j++) { var[j] = j; From 82d44e6a5cfb8a4ebf0ba25a05ef9a3b88814735 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Tue, 22 Dec 2015 19:51:12 +0100 Subject: [PATCH 3/4] Add a simple optimization to remove nearly all ZEND_SEND_VAL_SPEC_TMP_TMP_HANDLERs --- ext/opcache/Optimizer/optimize_func_calls.c | 33 +++++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c index 4d4686c0e357e..4ce198c8d7e3f 100644 --- a/ext/opcache/Optimizer/optimize_func_calls.c +++ b/ext/opcache/Optimizer/optimize_func_calls.c @@ -45,6 +45,7 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) int call = 0; void *checkpoint; optimizer_call_info *call_stack; + zend_bool had_fcall; if (op_array->last < 2) { return; @@ -80,6 +81,7 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) case ZEND_DO_FCALL_BY_NAME: case ZEND_DO_UNPACK_FCALL: call--; + had_fcall = call != 0; /* we must not replace ZEND_SEND_VAL after a DO_FCALL inside nested calls */ if (call_stack[call].func && call_stack[call].opline) { zend_op *fcall = call_stack[call].opline; @@ -139,13 +141,32 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) } break; case ZEND_SEND_VAL_EX: - if (call_stack[call - 1].func) { - if (ARG_MUST_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) { - /* We won't convert it into_DO_FCALL to emit error at run-time */ - call_stack[call - 1].opline = NULL; - } else { - opline->opcode = ZEND_SEND_VAL; + if (!call_stack[call - 1].func) { + break; + } + if (ARG_MUST_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) { + /* We won't convert it into_DO_FCALL to emit error at run-time */ + call_stack[call - 1].opline = NULL; + break; + } + + opline->opcode = ZEND_SEND_VAL; + /* break intentionally missing */ + case ZEND_SEND_VAL: + if (!had_fcall && opline->op1_type == IS_TMP_VAR) { + zend_op *orig = opline; + while (--orig >= op_array->opcodes) { + if (orig->op1.var == opline->op1.var && orig->op1_type == IS_TMP_VAR) { + orig->op1.var = opline->result.var; + } + if (orig->op2.var == opline->op2.var && orig->op2_type == IS_TMP_VAR) { + orig->op2.var = opline->result.var; + } + if (orig->result.var == opline->op1.var && orig->result_type == IS_TMP_VAR) { + orig->result.var = opline->result.var; + } } + opline->opcode = ZEND_NOP; } break; case ZEND_SEND_VAR_EX: From 21e996f128eedcaa2b034182f069181d67d5eee9 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Tue, 22 Dec 2015 23:35:52 +0100 Subject: [PATCH 4/4] Fix phpdbg tests, add handling for live_range when optimizing out SEND_VAL --- ext/opcache/Optimizer/optimize_func_calls.c | 21 ++++++++++++++++++++- sapi/phpdbg/tests/print_001.phpt | 10 +++++----- sapi/phpdbg/tests/print_002.phpt | 6 +++--- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c index 7a6a4b5168928..0b766fda1b1dd 100644 --- a/ext/opcache/Optimizer/optimize_func_calls.c +++ b/ext/opcache/Optimizer/optimize_func_calls.c @@ -154,6 +154,7 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) /* break intentionally missing */ case ZEND_SEND_VAL: if (!had_fcall && opline->op1_type == IS_TMP_VAR) { + int i, result = -1, src = -1; zend_op *orig = opline; while (--orig >= op_array->opcodes) { if (orig->op1.var == opline->op1.var && orig->op1_type == IS_TMP_VAR) { @@ -166,7 +167,25 @@ void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) orig->result.var = opline->result.var; } } - opline->opcode = ZEND_NOP; + for (i = 0; i < op_array->last_live_range; i++) { + if ((op_array->live_range[i].var & ZEND_LIVE_MASK) == opline->op1.var) { + src = i; + } + if ((op_array->live_range[i].var & ZEND_LIVE_MASK) == opline->result.var) { + result = i; + } + } + if (!src && !result) { + /* we're done, the temporary is immediately followed by the fcall executing opcode */ + } else if (src && result) { + op_array->live_range[result].start = op_array->live_range[src].start; + zend_optimizer_remove_live_range(op_array, opline->op1.var); + } else if (src) { + op_array->live_range[src].end++; + } else if (result) { + op_array->live_range[result].start--; + } + MAKE_NOP(opline); } break; case ZEND_SEND_VAR_EX: diff --git a/sapi/phpdbg/tests/print_001.phpt b/sapi/phpdbg/tests/print_001.phpt index e3477e4ea2b3f..73b9067868443 100644 --- a/sapi/phpdbg/tests/print_001.phpt +++ b/sapi/phpdbg/tests/print_001.phpt @@ -13,8 +13,8 @@ q prompt> [User Function foo (8 ops)] L14-16 foo() %s - %s + 8 ops L14 #0 RECV 1 $baz - L15 #1 INIT_FCALL%s %d %s "var_dump" ~3 - L15 #2 INIT_FCALL%s %d %s "strrev" ~9 + L15 #1 INIT_FCALL%s %d %s "var_dump" @3 + L15 #2 INIT_FCALL%s %d %s "strrev" @9 L15 #3 SEND_VAR $baz ~9 @8 L15 #4 DO_%cCALL ~9 @0 L15 #5 SEND_VAR @0 ~3 @2 @@ -23,7 +23,7 @@ L14-16 foo() %s - %s + 8 ops prompt> [User Class: Foo\Bar (2 methods)] L5-7 Foo\Bar::Foo() %s - %s + 5 ops L5 #0 RECV 1 $bar - L6 #1 INIT_NS_FCALL_BY_NAME "Foo\\var_dump" ~7 + L6 #1 INIT_NS_FCALL_BY_NAME "Foo\\var_dump" @7 L6 #2 SEND_VAR_EX $bar ~7 @6 L6 #3 DO_FCALL ~7 L7 #4 RETURN null @@ -36,10 +36,10 @@ L1-19 {main}() %s - %s + 11 ops L14 #1 NOP L18 #2 NEW "Foo\\Bar" J4 @1 L18 #3 DO_FCALL ~10 - L18 #4 INIT_METHOD_CALL @1 "Foo" ~11 + L18 #4 INIT_METHOD_CALL @1 "Foo" @11 L18 #5 SEND_VAL_EX "test" ~11 @10 L18 #6 DO_FCALL ~11 - L19 #7 INIT_FCALL%s %d %s "foo" ~6 + L19 #7 INIT_FCALL%s %d %s "foo" @6 L19 #8 SEND_VAL "test" ~6 @5 L19 #9 DO_FCALL ~6 L19 #10 RETURN 1 diff --git a/sapi/phpdbg/tests/print_002.phpt b/sapi/phpdbg/tests/print_002.phpt index 1b76f9f2e491f..c369e1288d436 100644 --- a/sapi/phpdbg/tests/print_002.phpt +++ b/sapi/phpdbg/tests/print_002.phpt @@ -19,14 +19,14 @@ prompt> string(4) "test" prompt> [Stack in foo() (8 ops)] L14-16 foo() %s - %s + 8 ops L14 #0 RECV 1 $baz - L15 #1 INIT_FCALL%s %d %s "var_dump" ~3 - L15 #2 INIT_FCALL%s %d %s "strrev" ~9 + L15 #1 INIT_FCALL%s %d %s "var_dump" @3 + L15 #2 INIT_FCALL%s %d %s "strrev" @9 L15 #3 SEND_VAR $baz ~9 @8 L15 #4 DO_%cCALL ~9 @0 L15 #5 SEND_VAR @0 ~3 @2 L15 #6 DO_%cCALL ~3 L16 #7 RETURN null -prompt> [L15 %s INIT_FCALL%s %d %s "var_dump" ~3 %s] +prompt> [L15 %s INIT_FCALL%s %d %s "var_dump" @3 %s] prompt> --FILE--