From 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 23 May 2016 22:18:36 +0300 Subject: [PATCH] Fixed inconsistent $this behavior --- Zend/tests/030.phpt | 38 +-- Zend/tests/bug68370.phpt | 4 +- Zend/tests/this_as_global.phpt | 12 + Zend/tests/this_as_parameter.phpt | 11 + Zend/tests/this_as_static.phpt | 12 + Zend/tests/this_in_catch.phpt | 18 ++ Zend/tests/this_in_foreach_001.phpt | 11 + Zend/tests/this_in_foreach_002.phpt | 11 + Zend/tests/this_in_foreach_003.phpt | 11 + Zend/tests/this_in_foreach_004.phpt | 11 + Zend/tests/this_in_unset.phpt | 8 + Zend/tests/this_reassign.phpt | 17 ++ Zend/zend_compile.c | 82 +++--- Zend/zend_compile.h | 2 - Zend/zend_execute.c | 26 +- Zend/zend_object_handlers.c | 1 - Zend/zend_opcode.c | 2 - Zend/zend_vm_def.h | 87 ++++++- Zend/zend_vm_execute.h | 315 +++++++++++++++++++---- Zend/zend_vm_opcodes.c | 10 +- Zend/zend_vm_opcodes.h | 5 +- ext/opcache/Optimizer/compact_literals.c | 12 +- ext/opcache/Optimizer/zend_inference.c | 9 +- tests/classes/__call_007.phpt | 12 +- tests/classes/static_this.phpt | 10 +- 25 files changed, 556 insertions(+), 181 deletions(-) create mode 100644 Zend/tests/this_as_global.phpt create mode 100644 Zend/tests/this_as_parameter.phpt create mode 100644 Zend/tests/this_as_static.phpt create mode 100644 Zend/tests/this_in_catch.phpt create mode 100644 Zend/tests/this_in_foreach_001.phpt create mode 100644 Zend/tests/this_in_foreach_002.phpt create mode 100644 Zend/tests/this_in_foreach_003.phpt create mode 100644 Zend/tests/this_in_foreach_004.phpt create mode 100644 Zend/tests/this_in_unset.phpt create mode 100644 Zend/tests/this_reassign.phpt diff --git a/Zend/tests/030.phpt b/Zend/tests/030.phpt index 8afcb66bd86..2318420319a 100644 --- a/Zend/tests/030.phpt +++ b/Zend/tests/030.phpt @@ -31,40 +31,4 @@ $test->bar(); ?> --EXPECTF-- -object(Exception)#%d (7) { - ["message":protected]=> - string(3) "foo" - ["string":"Exception":private]=> - string(0) "" - ["code":protected]=> - int(0) - ["file":protected]=> - string(%d) "%s030.php" - ["line":protected]=> - int(%d) - ["trace":"Exception":private]=> - array(1) { - [0]=> - array(6) { - ["file"]=> - string(%d) "%s030.php" - ["line"]=> - int(%d) - ["function"]=> - string(3) "bar" - ["class"]=> - string(3) "foo" - ["type"]=> - string(2) "->" - ["args"]=> - array(0) { - } - } - } - ["previous":"Exception":private]=> - NULL -} -'test' => '0' -'test_2' => '1' -'test_3' => '2' -ok +Fatal error: Cannot re-assign $this in %s030.php on line 11 diff --git a/Zend/tests/bug68370.phpt b/Zend/tests/bug68370.phpt index 25589bf455d..73411ca9b95 100644 --- a/Zend/tests/bug68370.phpt +++ b/Zend/tests/bug68370.phpt @@ -13,6 +13,4 @@ $x = $c->test(); print_r($x); unset($c, $x); --EXPECTF-- -Array -( -) +Fatal error: Cannot unset $this in %sbug68370.php on line 4 diff --git a/Zend/tests/this_as_global.phpt b/Zend/tests/this_as_global.phpt new file mode 100644 index 00000000000..0ba9ade1b93 --- /dev/null +++ b/Zend/tests/this_as_global.phpt @@ -0,0 +1,12 @@ +--TEST-- +$this as global variable +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use $this as global variable in %sthis_as_global.php on line 3 diff --git a/Zend/tests/this_as_parameter.phpt b/Zend/tests/this_as_parameter.phpt new file mode 100644 index 00000000000..93101969a7e --- /dev/null +++ b/Zend/tests/this_as_parameter.phpt @@ -0,0 +1,11 @@ +--TEST-- +$this as parameter +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use $this as parameter in %sthis_as_parameter.php on line 2 diff --git a/Zend/tests/this_as_static.phpt b/Zend/tests/this_as_static.phpt new file mode 100644 index 00000000000..f094449c12d --- /dev/null +++ b/Zend/tests/this_as_static.phpt @@ -0,0 +1,12 @@ +--TEST-- +$this as static variable +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use $this as static variable in %sthis_as_static.php on line 3 diff --git a/Zend/tests/this_in_catch.phpt b/Zend/tests/this_in_catch.phpt new file mode 100644 index 00000000000..d621bb18ea7 --- /dev/null +++ b/Zend/tests/this_in_catch.phpt @@ -0,0 +1,18 @@ +--TEST-- +$this in catch +--FILE-- +foo(); +?> +--EXPECTF-- +Fatal error: Cannot re-assign $this in %sthis_in_catch.php on line 6 diff --git a/Zend/tests/this_in_foreach_001.phpt b/Zend/tests/this_in_foreach_001.phpt new file mode 100644 index 00000000000..a724338b905 --- /dev/null +++ b/Zend/tests/this_in_foreach_001.phpt @@ -0,0 +1,11 @@ +--TEST-- +$this in foreach +--FILE-- + +--EXPECTF-- +Fatal error: Cannot re-assign $this in %sthis_in_foreach_001.php on line 3 diff --git a/Zend/tests/this_in_foreach_002.phpt b/Zend/tests/this_in_foreach_002.phpt new file mode 100644 index 00000000000..511ea36a242 --- /dev/null +++ b/Zend/tests/this_in_foreach_002.phpt @@ -0,0 +1,11 @@ +--TEST-- +$this in foreach +--FILE-- + $dummy) { + var_dump($this); +} +?> +--EXPECTF-- +Fatal error: Cannot re-assign $this in %sthis_in_foreach_002.php on line 3 diff --git a/Zend/tests/this_in_foreach_003.phpt b/Zend/tests/this_in_foreach_003.phpt new file mode 100644 index 00000000000..5f5b5ae0d8e --- /dev/null +++ b/Zend/tests/this_in_foreach_003.phpt @@ -0,0 +1,11 @@ +--TEST-- +$this in foreach +--FILE-- + +--EXPECTF-- +Fatal error: Cannot re-assign $this in %sthis_in_foreach_003.php on line 3 diff --git a/Zend/tests/this_in_foreach_004.phpt b/Zend/tests/this_in_foreach_004.phpt new file mode 100644 index 00000000000..13bfbf18b4c --- /dev/null +++ b/Zend/tests/this_in_foreach_004.phpt @@ -0,0 +1,11 @@ +--TEST-- +$this in foreach +--FILE-- + +--EXPECTF-- +Fatal error: Cannot re-assign $this in %sthis_in_foreach_004.php on line 3 diff --git a/Zend/tests/this_in_unset.phpt b/Zend/tests/this_in_unset.phpt new file mode 100644 index 00000000000..bc815049f96 --- /dev/null +++ b/Zend/tests/this_in_unset.phpt @@ -0,0 +1,8 @@ +--TEST-- +$this in unset +--FILE-- + +--EXPECTF-- +Fatal error: Cannot unset $this in %sthis_in_unset.php on line 2 diff --git a/Zend/tests/this_reassign.phpt b/Zend/tests/this_reassign.phpt new file mode 100644 index 00000000000..d965ef47010 --- /dev/null +++ b/Zend/tests/this_reassign.phpt @@ -0,0 +1,17 @@ +--TEST-- +$this re-assign +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught Error: Cannot re-assign $this in %sthis_reassign.php:4 +Stack trace: +#0 %sthis_reassign.php(7): foo() +#1 {main} + thrown in %sthis_reassign.php on line 4 diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0994681c209..303e0c91cae 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -755,6 +755,9 @@ void zend_do_free(znode *op1) /* {{{ */ additional FREE opcode and simplify the FETCH handlers their selves */ zend_emit_op(NULL, ZEND_FREE, op1, NULL); + } else if (opline->opcode == ZEND_FETCH_THIS) { + opline->opcode = ZEND_NOP; + opline->result_type = IS_UNUSED; } else { opline->result_type = IS_UNUSED; } @@ -1927,6 +1930,13 @@ 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; + if (opline->opcode == ZEND_FETCH_THIS) { + if ((type & BP_VAR_MASK) == BP_VAR_IS) { + opline->opcode = ZEND_FETCH_THIS_IS; + } + return; + } + switch (type & BP_VAR_MASK) { case BP_VAR_R: return; @@ -2507,9 +2517,6 @@ static int zend_try_compile_cv(znode *result, zend_ast *ast) /* {{{ */ /* 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")) { - CG(active_op_array)->this_var = result->u.op.var; - } return SUCCESS; } @@ -2540,22 +2547,31 @@ static zend_op *zend_compile_simple_var_no_cv(znode *result, zend_ast *ast, uint opline->extended_value = ZEND_FETCH_GLOBAL; } else { opline->extended_value = ZEND_FETCH_LOCAL; - /* there is a chance someone is accessing $this */ - if (ast->kind != ZEND_AST_ZVAL - && CG(active_op_array)->scope && CG(active_op_array)->this_var == (uint32_t)-1 - ) { - zend_string *key = CG(known_strings)[ZEND_STR_THIS]; - CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), key); - } } return opline; } /* }}} */ +static zend_bool is_this_fetch(zend_ast *ast) /* {{{ */ +{ + if (ast->kind == ZEND_AST_VAR && ast->child[0]->kind == ZEND_AST_ZVAL) { + zval *name = zend_ast_get_zval(ast->child[0]); + return Z_TYPE_P(name) == IS_STRING && zend_string_equals_literal(Z_STR_P(name), "this"); + } + + return 0; +} +/* }}} */ + static void zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t type, int delayed) /* {{{ */ { - if (zend_try_compile_cv(result, ast) == FAILURE) { + zend_op *opline; + + if (is_this_fetch(ast)) { + opline = zend_emit_op(result, ZEND_FETCH_THIS, NULL, NULL); + zend_adjust_for_fetch_type(opline, type); + } else 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); } @@ -2636,17 +2652,6 @@ void zend_compile_dim(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ } /* }}} */ -static zend_bool is_this_fetch(zend_ast *ast) /* {{{ */ -{ - if (ast->kind == ZEND_AST_VAR && ast->child[0]->kind == ZEND_AST_ZVAL) { - zval *name = zend_ast_get_zval(ast->child[0]); - return Z_TYPE_P(name) == IS_STRING && zend_string_equals_literal(Z_STR_P(name), "this"); - } - - return 0; -} -/* }}} */ - static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t type) /* {{{ */ { zend_ast *obj_ast = ast->child[0]; @@ -2944,7 +2949,8 @@ void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */ offset = zend_delayed_compile_begin(); zend_delayed_compile_dim(result, var_ast, BP_VAR_W); - if (zend_is_assign_to_self(var_ast, expr_ast)) { + if (zend_is_assign_to_self(var_ast, expr_ast) + && !is_this_fetch(expr_ast)) { /* $a[0] = $a should evaluate the right $a first */ zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0); } else { @@ -3886,7 +3892,9 @@ void zend_compile_global_var(zend_ast *ast) /* {{{ */ convert_to_string(&name_node.u.constant); } - if (zend_try_compile_cv(&result, var_ast) == SUCCESS) { + if (is_this_fetch(var_ast)) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as global variable"); + } else if (zend_try_compile_cv(&result, var_ast) == SUCCESS) { zend_op *opline = zend_emit_op(NULL, ZEND_BIND_GLOBAL, &result, &name_node); zend_alloc_cache_slot(opline->op2.constant); } else { @@ -3931,6 +3939,10 @@ static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, zend_ } zend_hash_update(CG(active_op_array)->static_variables, Z_STR(var_node.u.constant), value); + if (zend_string_equals_literal(Z_STR(var_node.u.constant), "this")) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as static variable"); + } + opline = zend_emit_op(NULL, ZEND_BIND_STATIC, NULL, &var_node); opline->op1_type = IS_CV; opline->op1.var = lookup_cv(CG(active_op_array), zend_string_copy(Z_STR(var_node.u.constant))); @@ -3964,7 +3976,9 @@ void zend_compile_unset(zend_ast *ast) /* {{{ */ switch (var_ast->kind) { case ZEND_AST_VAR: - if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) { + if (is_this_fetch(var_ast)) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot unset $this"); + } else if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) { opline = zend_emit_op(NULL, ZEND_UNSET_VAR, &var_node, NULL); opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET; } else { @@ -4394,7 +4408,9 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ opnum_fetch = get_next_op_number(CG(active_op_array)); opline = zend_emit_op(NULL, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL); - if (value_ast->kind == ZEND_AST_VAR && + if (is_this_fetch(value_ast)) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this"); + } else if (value_ast->kind == ZEND_AST_VAR && zend_try_compile_cv(&value_node, value_ast) == SUCCESS) { SET_NODE(opline->op2, &value_node); } else { @@ -4645,6 +4661,10 @@ void zend_compile_try(zend_ast *ast) /* {{{ */ opline->op1.constant = zend_add_class_name_literal(CG(active_op_array), zend_resolve_class_name_ast(class_ast)); + if (zend_string_equals_literal(Z_STR_P(var_name), "this")) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this"); + } + opline->op2_type = IS_CV; opline->op2.var = lookup_cv(CG(active_op_array), zend_string_copy(Z_STR_P(var_name))); @@ -4971,11 +4991,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ 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_CLOSURE)) - && (op_array->fn_flags & ZEND_ACC_STATIC) == 0) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as parameter"); - } - op_array->this_var = var_node.u.op.var; + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as parameter"); } if (op_array->fn_flags & ZEND_ACC_VARIADIC) { @@ -6958,7 +6974,9 @@ void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */ switch (var_ast->kind) { case ZEND_AST_VAR: - if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) { + if (is_this_fetch(var_ast)) { + opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_THIS, NULL, NULL); + } else if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) { opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_VAR, &var_node, NULL); opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET; } else { diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 0de475da11d..a692f17d458 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -363,8 +363,6 @@ struct _zend_op_array { uint32_t *refcount; - uint32_t this_var; - uint32_t last; zend_op *opcodes; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 5fb00039860..4d204adad26 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2146,7 +2146,7 @@ static zend_never_inline ZEND_COLD ZEND_NORETURN void ZEND_FASTCALL zend_interru * +----------------------------------------+ */ -static zend_always_inline void i_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value, int check_this) /* {{{ */ +static zend_always_inline void i_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */ { uint32_t first_extra_arg, num_args; ZEND_ASSERT(EX(func) == (zend_function*)op_array); @@ -2204,11 +2204,6 @@ static zend_always_inline void i_init_func_execute_data(zend_execute_data *execu } while (var != end); } - if (check_this && op_array->this_var != (uint32_t)-1 && EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { - ZVAL_OBJ(EX_VAR(op_array->this_var), Z_OBJ(EX(This))); - GC_REFCOUNT(Z_OBJ(EX(This)))++; - } - EX_LOAD_RUN_TIME_CACHE(op_array); EX_LOAD_LITERALS(op_array); @@ -2232,13 +2227,6 @@ static zend_always_inline void i_init_code_execute_data(zend_execute_data *execu EX(call) = NULL; EX(return_value) = return_value; - if (UNEXPECTED(op_array->this_var != (uint32_t)-1) && EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { - GC_REFCOUNT(Z_OBJ(EX(This)))++; - if (!zend_hash_add(EX(symbol_table), CG(known_strings)[ZEND_STR_THIS], &EX(This))) { - GC_REFCOUNT(Z_OBJ(EX(This)))--; - } - } - zend_attach_symbol_table(execute_data); if (!op_array->run_time_cache) { @@ -2261,13 +2249,6 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da EX(return_value) = return_value; if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) { - if (UNEXPECTED(op_array->this_var != (uint32_t)-1) && EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { - GC_REFCOUNT(Z_OBJ(EX(This)))++; - if (!zend_hash_add(EX(symbol_table), CG(known_strings)[ZEND_STR_THIS], &EX(This))) { - GC_REFCOUNT(Z_OBJ(EX(This)))--; - } - } - zend_attach_symbol_table(execute_data); } else { uint32_t first_extra_arg, num_args; @@ -2320,11 +2301,6 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da var++; } while (var != end); } - - if (op_array->this_var != (uint32_t)-1 && EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { - ZVAL_OBJ(EX_VAR(op_array->this_var), Z_OBJ(EX(This))); - GC_REFCOUNT(Z_OBJ(EX(This)))++; - } } if (!op_array->run_time_cache) { diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 6aa5d731c5b..e814fa56d33 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1165,7 +1165,6 @@ ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend if (is_static) { func->fn_flags |= ZEND_ACC_STATIC; } - func->this_var = -1; func->opcodes = &EG(call_trampoline_op); func->prototype = fbc; diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 34e060fa4ae..49b6fb537f2 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -85,8 +85,6 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->static_variables = NULL; op_array->last_try_catch = 0; - op_array->this_var = -1; - op_array->fn_flags = 0; op_array->early_binding = -1; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 93ff58e8070..e7514280528 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1493,6 +1493,41 @@ ZEND_VM_HELPER(zend_fetch_var_address_helper, CONST|TMPVAR|CV, UNUSED, int type) 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) { + if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) { + zval *result = EX_VAR(opline->result.var); + + switch (type) { + case BP_VAR_R: + if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { + ZVAL_OBJ(result, Z_OBJ(EX(This))); + Z_ADDREF_P(result); + } else { + ZVAL_NULL(result); + zend_error(E_NOTICE,"Undefined variable: this"); + } + break; + case BP_VAR_IS: + if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { + ZVAL_OBJ(result, Z_OBJ(EX(This))); + Z_ADDREF_P(result); + } else { + ZVAL_NULL(result); + } + break; + case BP_VAR_RW: + case BP_VAR_W: + zend_throw_error(NULL, "Cannot re-assign $this"); + break; + case BP_VAR_UNSET: + zend_throw_error(NULL, "Cannot unset $this"); + break; + EMPTY_SWITCH_DEFAULT_CASE() + } + if (OP1_TYPE != IS_CONST) { + zend_string_release(name); + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } switch (type) { case BP_VAR_R: case BP_VAR_UNSET: @@ -3618,7 +3653,7 @@ ZEND_VM_HANDLER(130, ZEND_DO_UCALL, ANY, ANY, SPEC(RETVAL)) } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret, 0); + i_init_func_execute_data(call, &fbc->op_array, ret); ZEND_VM_ENTER(); } @@ -3641,7 +3676,7 @@ ZEND_VM_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL)) } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret, 0); + i_init_func_execute_data(call, &fbc->op_array, ret); ZEND_VM_ENTER(); } else { @@ -3738,7 +3773,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL)) } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret, 1); + i_init_func_execute_data(call, &fbc->op_array, ret); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); @@ -7898,8 +7933,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY) if (UNEXPECTED(!fbc->op_array.run_time_cache)) { init_func_run_time_cache(&fbc->op_array); } - i_init_func_execute_data(call, &fbc->op_array, - ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0); + i_init_func_execute_data(call, &fbc->op_array, ret); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { @@ -8059,6 +8093,49 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, CONST, REF) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +ZEND_VM_HANDLER(184, ZEND_FETCH_THIS, UNUSED, UNUSED) +{ + USE_OPLINE + zval *result = EX_VAR(opline->result.var); + + if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { + ZVAL_OBJ(result, Z_OBJ(EX(This))); + Z_ADDREF_P(result); + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_NULL(result); + SAVE_OPLINE(); + zend_error(E_NOTICE,"Undefined variable: this"); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } +} + +ZEND_VM_HANDLER(185, ZEND_FETCH_THIS_IS, UNUSED, UNUSED) +{ + USE_OPLINE + zval *result = EX_VAR(opline->result.var); + + if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { + ZVAL_OBJ(result, Z_OBJ(EX(This))); + Z_ADDREF_P(result); + } else { + ZVAL_NULL(result); + } + ZEND_VM_NEXT_OPCODE(); +} + +ZEND_VM_HANDLER(186, ZEND_ISSET_ISEMPTY_THIS, UNUSED, UNUSED) +{ + USE_OPLINE + zval *result = EX_VAR(opline->result.var); + + ZVAL_BOOL(EX_VAR(opline->result.var), + (opline->extended_value & ZEND_ISSET) ? + (Z_TYPE(EX(This)) == IS_OBJECT) : + (Z_TYPE(EX(This)) != IS_OBJECT)); + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_TYPE_SPEC_HANDLER(ZEND_ADD, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_ADD_LONG_NO_OVERFLOW, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE)) { USE_OPLINE diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 1b673b8c2a5..596a2080cd8 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -707,7 +707,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_HA } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret, 0); + i_init_func_execute_data(call, &fbc->op_array, ret); ZEND_VM_ENTER(); } @@ -729,7 +729,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_RETVAL_USED_HAND } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret, 0); + i_init_func_execute_data(call, &fbc->op_array, ret); ZEND_VM_ENTER(); } @@ -752,7 +752,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_U } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret, 0); + i_init_func_execute_data(call, &fbc->op_array, ret); ZEND_VM_ENTER(); } else { @@ -831,7 +831,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_U } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret, 0); + i_init_func_execute_data(call, &fbc->op_array, ret); ZEND_VM_ENTER(); } else { @@ -928,7 +928,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HA } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret, 1); + i_init_func_execute_data(call, &fbc->op_array, ret); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); @@ -1057,7 +1057,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETVAL_USED_HAND } call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, ret, 1); + i_init_func_execute_data(call, &fbc->op_array, ret); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); @@ -1988,8 +1988,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z if (UNEXPECTED(!fbc->op_array.run_time_cache)) { init_func_run_time_cache(&fbc->op_array); } - i_init_func_execute_data(call, &fbc->op_array, - ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0); + i_init_func_execute_data(call, &fbc->op_array, ret); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { @@ -6977,6 +6976,41 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_ 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) { + if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) { + zval *result = EX_VAR(opline->result.var); + + switch (type) { + case BP_VAR_R: + if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { + ZVAL_OBJ(result, Z_OBJ(EX(This))); + Z_ADDREF_P(result); + } else { + ZVAL_NULL(result); + zend_error(E_NOTICE,"Undefined variable: this"); + } + break; + case BP_VAR_IS: + if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { + ZVAL_OBJ(result, Z_OBJ(EX(This))); + Z_ADDREF_P(result); + } else { + ZVAL_NULL(result); + } + break; + case BP_VAR_RW: + case BP_VAR_W: + zend_throw_error(NULL, "Cannot re-assign $this"); + break; + case BP_VAR_UNSET: + zend_throw_error(NULL, "Cannot unset $this"); + break; + EMPTY_SWITCH_DEFAULT_CASE() + } + if (IS_CONST != IS_CONST) { + zend_string_release(name); + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } switch (type) { case BP_VAR_R: case BP_VAR_UNSET: @@ -31742,6 +31776,49 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDL ZEND_VM_RETURN(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_THIS_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *result = EX_VAR(opline->result.var); + + if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { + ZVAL_OBJ(result, Z_OBJ(EX(This))); + Z_ADDREF_P(result); + ZEND_VM_NEXT_OPCODE(); + } else { + ZVAL_NULL(result); + SAVE_OPLINE(); + zend_error(E_NOTICE,"Undefined variable: this"); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_THIS_IS_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *result = EX_VAR(opline->result.var); + + if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { + ZVAL_OBJ(result, Z_OBJ(EX(This))); + Z_ADDREF_P(result); + } else { + ZVAL_NULL(result); + } + ZEND_VM_NEXT_OPCODE(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ISSET_ISEMPTY_THIS_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *result = EX_VAR(opline->result.var); + + ZVAL_BOOL(EX_VAR(opline->result.var), + (opline->extended_value & ZEND_ISSET) ? + (Z_TYPE(EX(This)) == IS_OBJECT) : + (Z_TYPE(EX(This)) != IS_OBJECT)); + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(binary_op_type binary_op ZEND_OPCODE_HANDLER_ARGS_DC) { USE_OPLINE @@ -44273,6 +44350,41 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_ 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) { + if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) { + zval *result = EX_VAR(opline->result.var); + + switch (type) { + case BP_VAR_R: + if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { + ZVAL_OBJ(result, Z_OBJ(EX(This))); + Z_ADDREF_P(result); + } else { + ZVAL_NULL(result); + zend_error(E_NOTICE,"Undefined variable: this"); + } + break; + case BP_VAR_IS: + if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { + ZVAL_OBJ(result, Z_OBJ(EX(This))); + Z_ADDREF_P(result); + } else { + ZVAL_NULL(result); + } + break; + case BP_VAR_RW: + case BP_VAR_W: + zend_throw_error(NULL, "Cannot re-assign $this"); + break; + case BP_VAR_UNSET: + zend_throw_error(NULL, "Cannot unset $this"); + break; + EMPTY_SWITCH_DEFAULT_CASE() + } + if (IS_CV != IS_CONST) { + zend_string_release(name); + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } switch (type) { case BP_VAR_R: case BP_VAR_UNSET: @@ -56240,6 +56352,41 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_ 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) { + if (UNEXPECTED(zend_string_equals(name, CG(known_strings)[ZEND_STR_THIS]))) { + zval *result = EX_VAR(opline->result.var); + + switch (type) { + case BP_VAR_R: + if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { + ZVAL_OBJ(result, Z_OBJ(EX(This))); + Z_ADDREF_P(result); + } else { + ZVAL_NULL(result); + zend_error(E_NOTICE,"Undefined variable: this"); + } + break; + case BP_VAR_IS: + if (EXPECTED(Z_TYPE(EX(This)) == IS_OBJECT)) { + ZVAL_OBJ(result, Z_OBJ(EX(This))); + Z_ADDREF_P(result); + } else { + ZVAL_NULL(result); + } + break; + case BP_VAR_RW: + case BP_VAR_W: + zend_throw_error(NULL, "Cannot re-assign $this"); + break; + case BP_VAR_UNSET: + zend_throw_error(NULL, "Cannot unset $this"); + break; + EMPTY_SWITCH_DEFAULT_CASE() + } + if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { + zend_string_release(name); + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); + } switch (type) { case BP_VAR_R: case BP_VAR_UNSET: @@ -63706,6 +63853,81 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_FETCH_THIS_SPEC_UNUSED_UNUSED_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_FETCH_THIS_IS_SPEC_UNUSED_UNUSED_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_ISSET_ISEMPTY_THIS_SPEC_UNUSED_UNUSED_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV_HANDLER, ZEND_ADD_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV_HANDLER, ZEND_NULL_HANDLER, @@ -64707,9 +64929,9 @@ void zend_init_opcodes_handlers(void) 1423 | SPEC_RULE_OP1, 1428 | SPEC_RULE_OP1, 1433 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 4471, - 4471, - 4471, + 4546, + 4546, + 4546, 1458 | SPEC_RULE_OP1, 1463 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 1488 | SPEC_RULE_OP1 | SPEC_RULE_OP2, @@ -64758,7 +64980,7 @@ void zend_init_opcodes_handlers(void) 2197 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2222 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2247 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 4471, + 4546, 2272, 2273, 2274, @@ -64842,7 +65064,10 @@ void zend_init_opcodes_handlers(void) 3446 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3471 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3496 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 4471 + 3521 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3546 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3571 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 4546 }; zend_opcode_handlers = labels; zend_handlers_count = sizeof(labels) / sizeof(void*); @@ -64949,7 +65174,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3521 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3596 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -64957,7 +65182,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3546 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3621 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -64965,7 +65190,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3571 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3646 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -64976,17 +65201,17 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3596 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3671 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } else if ((op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG)) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3621 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3696 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } else if ((op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE)) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3646 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3721 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; case ZEND_MUL: @@ -64994,7 +65219,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3671 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3746 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -65002,7 +65227,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3696 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3771 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -65010,7 +65235,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3721 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3796 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -65021,7 +65246,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3746 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3821 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -65029,7 +65254,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3821 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3896 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -65040,7 +65265,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3896 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3971 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -65048,7 +65273,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3971 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4046 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -65059,12 +65284,12 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4046 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4121 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } else if ((op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE)) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4121 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4196 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_IS_SMALLER_OR_EQUAL: @@ -65072,60 +65297,60 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4196 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4271 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } else if ((op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE)) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4271 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4346 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_QM_ASSIGN: if ((op1_info == MAY_BE_DOUBLE)) { - spec = 4436 | SPEC_RULE_OP1; + spec = 4511 | SPEC_RULE_OP1; } else if ((!(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))))) { - spec = 4441 | SPEC_RULE_OP1; + spec = 4516 | SPEC_RULE_OP1; } break; case ZEND_PRE_INC: if ((res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG)) { - spec = 4346 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4421 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if ((op1_info == MAY_BE_LONG)) { - spec = 4356 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4431 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if ((op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE))) { - spec = 4366 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4441 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } break; case ZEND_PRE_DEC: if ((res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG)) { - spec = 4376 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4451 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if ((op1_info == MAY_BE_LONG)) { - spec = 4386 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4461 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if ((op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE))) { - spec = 4396 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4471 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } break; case ZEND_POST_INC: if ((res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG)) { - spec = 4406 | SPEC_RULE_OP1; + spec = 4481 | SPEC_RULE_OP1; } else if ((op1_info == MAY_BE_LONG)) { - spec = 4411 | SPEC_RULE_OP1; + spec = 4486 | SPEC_RULE_OP1; } else if ((op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE))) { - spec = 4416 | SPEC_RULE_OP1; + spec = 4491 | SPEC_RULE_OP1; } break; case ZEND_POST_DEC: if ((res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG)) { - spec = 4421 | SPEC_RULE_OP1; + spec = 4496 | SPEC_RULE_OP1; } else if ((op1_info == MAY_BE_LONG)) { - spec = 4426 | SPEC_RULE_OP1; + spec = 4501 | SPEC_RULE_OP1; } else if ((op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE))) { - spec = 4431 | SPEC_RULE_OP1; + spec = 4506 | SPEC_RULE_OP1; } break; case ZEND_FETCH_DIM_R: if ((!(op2_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)))) { - spec = 4446 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 4521 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; default: diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index 180b745fb25..7cc80bf6e16 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -21,7 +21,7 @@ #include #include -static const char *zend_vm_opcodes_names[184] = { +static const char *zend_vm_opcodes_names[187] = { "ZEND_NOP", "ZEND_ADD", "ZEND_SUB", @@ -206,9 +206,12 @@ static const char *zend_vm_opcodes_names[184] = { "ZEND_FETCH_CLASS_CONSTANT", "ZEND_BIND_LEXICAL", "ZEND_BIND_STATIC", + "ZEND_FETCH_THIS", + "ZEND_FETCH_THIS_IS", + "ZEND_ISSET_ISEMPTY_THIS", }; -static uint32_t zend_vm_opcodes_flags[184] = { +static uint32_t zend_vm_opcodes_flags[187] = { 0x00000000, 0x00000707, 0x00000707, @@ -393,6 +396,9 @@ static uint32_t zend_vm_opcodes_flags[184] = { 0x00000373, 0x00100101, 0x00100301, + 0x00000101, + 0x00000101, + 0x00000101, }; ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) { diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 00aa20ea37b..e05bcd1dbf8 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -250,7 +250,10 @@ END_EXTERN_C() #define ZEND_FETCH_CLASS_CONSTANT 181 #define ZEND_BIND_LEXICAL 182 #define ZEND_BIND_STATIC 183 +#define ZEND_FETCH_THIS 184 +#define ZEND_FETCH_THIS_IS 185 +#define ZEND_ISSET_ISEMPTY_THIS 186 -#define ZEND_VM_LAST_OPCODE 183 +#define ZEND_VM_LAST_OPCODE 186 #endif diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c index 76c89fe828c..68178f58733 100644 --- a/ext/opcache/Optimizer/compact_literals.c +++ b/ext/opcache/Optimizer/compact_literals.c @@ -72,9 +72,9 @@ typedef struct _literal_info { info[n].u.num = (_num); \ } while (0) -#define LITERAL_INFO_OBJ(n, kind, merge, slots, related, _num) do { \ +#define LITERAL_INFO_OBJ(n, kind, merge, slots, related) do { \ info[n].flags = (LITERAL_EX_OBJ | ((merge) ? LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \ - info[n].u.num = (_num); \ + info[n].u.num = (uint32_t)-1; \ } while (0) static void optimizer_literal_obj_info(literal_info *info, @@ -92,7 +92,7 @@ static void optimizer_literal_obj_info(literal_info *info, */ if (Z_TYPE(op_array->literals[constant]) == IS_STRING && op_type == IS_UNUSED) { - LITERAL_INFO_OBJ(constant, kind, 1, slots, related, op_array->this_var); + LITERAL_INFO_OBJ(constant, kind, 1, slots, related); } else { LITERAL_INFO(constant, kind, 0, slots, related); } @@ -421,9 +421,11 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx case IS_CONSTANT: if (info[i].flags & LITERAL_MAY_MERGE) { if (info[i].flags & LITERAL_EX_OBJ) { - int key_len = MAX_LENGTH_OF_LONG + sizeof("->") - 1 + Z_STRLEN(op_array->literals[i]); + int key_len = sizeof("$this->") - 1 + Z_STRLEN(op_array->literals[i]); key = zend_string_alloc(key_len, 0); - ZSTR_LEN(key) = snprintf(ZSTR_VAL(key), ZSTR_LEN(key)-1, "%d->%s", info[i].u.num, Z_STRVAL(op_array->literals[i])); + memcpy(ZSTR_VAL(key), "$this->", sizeof("$this->") - 1); + memcpy(ZSTR_VAL(key) + sizeof("$this->") - 1, Z_STRVAL(op_array->literals[i]), Z_STRLEN(op_array->literals[i]) + 1); + ZSTR_LEN(key) = key_len; } else if (info[i].flags & LITERAL_EX_CLASS) { int key_len; zval *class_name = &op_array->literals[(info[i].u.num < i) ? map[info[i].u.num] : info[i].u.num]; diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index fd39baf749e..e002cf499c4 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -601,7 +601,6 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int return (tmp->min <= tmp->max); } else if (ssa->vars[var].definition < 0) { if (var < op_array->last_var && - var != EX_VAR_TO_NUM(op_array->this_var) && op_array->function_name) { tmp->min = 0; @@ -3842,13 +3841,7 @@ int zend_ssa_inference(zend_arena **arena, const zend_op_array *op_array, const } } else { for (i = 0; i < op_array->last_var; i++) { - if (i == EX_VAR_TO_NUM(op_array->this_var)) { - ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_OBJECT; - ssa_var_info[i].ce = op_array->scope; - ssa_var_info[i].is_instanceof = 1; - } else { - ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RCN; - } + ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RCN; ssa_var_info[i].has_range = 0; } } diff --git a/tests/classes/__call_007.phpt b/tests/classes/__call_007.phpt index b061d17d85c..cc7a2773bd8 100644 --- a/tests/classes/__call_007.phpt +++ b/tests/classes/__call_007.phpt @@ -54,21 +54,25 @@ try { --EXPECTF-- Warning: The magic method __call() must have public visibility and cannot be static in %s on line 3 ---> Invoke __call via simple method call. -NULL +object(A)#1 (0) { +} Exception caught OK; continuing. ---> Invoke __call via scope resolution operator within instance. -NULL +object(A)#1 (0) { +} Exception caught OK; continuing. ---> Invoke __call via scope resolution operator within child instance. -NULL +object(B)#2 (0) { +} Exception caught OK; continuing. ---> Invoke __call via callback. -NULL +object(B)#2 (0) { +} Exception caught OK; continuing. ==DONE== diff --git a/tests/classes/static_this.phpt b/tests/classes/static_this.phpt index 91b02871950..f7a11f54817 100644 --- a/tests/classes/static_this.phpt +++ b/tests/classes/static_this.phpt @@ -28,12 +28,4 @@ TestClass::Test2(new stdClass); ?> ===DONE=== --EXPECTF-- - -Notice: Undefined variable: this in %sstatic_this.php on line %d -NULL - -Notice: Undefined variable: this in %sstatic_this.php on line %d -NULL -object(stdClass)#%d (0) { -} -===DONE=== +Fatal error: Cannot use $this as parameter in %sstatic_this.php on line 16