From 15052048600eaa0ed48cc37f037b5012a0f3f078 Mon Sep 17 00:00:00 2001 From: David Walker Date: Fri, 6 Oct 2017 17:30:58 -0600 Subject: [PATCH 01/11] New attempt at list-reference Add unit tests Update opcode name Remove obsolete test Apply changes requested - Make _w fetch from list a ref - Raise compiler error when assigning to a known non referencable value Remove unused condition in VM Fix logic for compile error, drop const from LIST_W op1 Add additional make ref, for write access Add ZEND_FETCH_LIST_W to switches and places DIM_W exists --- Zend/tests/list/list_reference_001.phpt | 88 +++++ Zend/tests/list/list_reference_002.phpt | 20 ++ Zend/tests/list/list_reference_003.phpt | 73 ++++ Zend/tests/list/list_reference_004.phpt | 28 ++ Zend/tests/list/list_reference_005.phpt | 73 ++++ Zend/tests/list/list_reference_006.phpt | 58 +++ Zend/tests/list/list_reference_007.phpt | 75 ++++ Zend/tests/list/list_reference_008.phpt | 60 ++++ Zend/tests/list/list_reference_009.phpt | 47 +++ Zend/tests/list/list_reference_010.phpt | 8 + Zend/tests/list/list_reference_011.phpt | 9 + Zend/tests/list_009.phpt | 14 - Zend/zend_compile.c | 85 ++++- Zend/zend_execute.c | 9 +- Zend/zend_vm_def.h | 33 +- Zend/zend_vm_execute.h | 451 ++++++++++++++++++------ Zend/zend_vm_opcodes.c | 8 +- Zend/zend_vm_opcodes.h | 5 +- ext/opcache/Optimizer/block_pass.c | 2 +- ext/opcache/Optimizer/sccp.c | 7 +- ext/opcache/Optimizer/zend_dfg.c | 1 + ext/opcache/Optimizer/zend_inference.c | 16 +- ext/opcache/Optimizer/zend_optimizer.c | 13 +- ext/opcache/Optimizer/zend_ssa.c | 1 + 24 files changed, 1027 insertions(+), 157 deletions(-) create mode 100644 Zend/tests/list/list_reference_001.phpt create mode 100644 Zend/tests/list/list_reference_002.phpt create mode 100644 Zend/tests/list/list_reference_003.phpt create mode 100644 Zend/tests/list/list_reference_004.phpt create mode 100644 Zend/tests/list/list_reference_005.phpt create mode 100644 Zend/tests/list/list_reference_006.phpt create mode 100644 Zend/tests/list/list_reference_007.phpt create mode 100644 Zend/tests/list/list_reference_008.phpt create mode 100644 Zend/tests/list/list_reference_009.phpt create mode 100644 Zend/tests/list/list_reference_010.phpt create mode 100644 Zend/tests/list/list_reference_011.phpt delete mode 100644 Zend/tests/list_009.phpt diff --git a/Zend/tests/list/list_reference_001.phpt b/Zend/tests/list/list_reference_001.phpt new file mode 100644 index 0000000000000..a173c7103e086 --- /dev/null +++ b/Zend/tests/list/list_reference_001.phpt @@ -0,0 +1,88 @@ +--TEST-- +"Reference Unpacking - General" list() +--FILE-- + 1, "two" => array(2)); +["one" => &$a, "two" => [&$b], "three" => &$c] = $arr; +var_dump($a, $b, $c); +var_dump($arr); +?> +--EXPECTF-- +int(1) +int(2) +array(2) { + [0]=> + &int(1) + [1]=> + array(1) { + [0]=> + &int(2) + } +} +array(2) { + [0]=> + int(1) + [1]=> + &array(1) { + [0]=> + int(2) + } +} +int(1) +int(2) +array(2) { + [0]=> + &int(1) + [1]=> + array(1) { + [0]=> + &int(2) + } +} +int(1) +int(2) +NULL +array(3) { + [0]=> + &int(1) + [1]=> + array(1) { + [0]=> + &int(2) + } + [2]=> + &NULL +} +int(1) +int(2) +NULL +array(3) { + ["one"]=> + &int(1) + ["two"]=> + array(1) { + [0]=> + &int(2) + } + ["three"]=> + &NULL +} diff --git a/Zend/tests/list/list_reference_002.phpt b/Zend/tests/list/list_reference_002.phpt new file mode 100644 index 0000000000000..32aad686d1eb8 --- /dev/null +++ b/Zend/tests/list/list_reference_002.phpt @@ -0,0 +1,20 @@ +--TEST-- +"Reference Unpacking - New Reference" list() +--FILE-- + +--EXPECTF-- +object(stdClass)#%d (0) { +} +NULL +array(2) { + [0]=> + &object(stdClass)#%d (0) { + } + [1]=> + &NULL +} diff --git a/Zend/tests/list/list_reference_003.phpt b/Zend/tests/list/list_reference_003.phpt new file mode 100644 index 0000000000000..9c903407d50e0 --- /dev/null +++ b/Zend/tests/list/list_reference_003.phpt @@ -0,0 +1,73 @@ +--TEST-- +"Reference Unpacking - From Functions" list() +--FILE-- + +--EXPECTF-- +Notice: Attempting to set reference to non referenceable value in %s on line %d +int(1) +array(2) { + [0]=> + int(1) + [1]=> + int(2) +} + +Notice: Attempting to set reference to non referenceable value in %s on line %d +int(1) +array(2) { + [0]=> + int(1) + [1]=> + int(2) +} +int(1) +array(2) { + [0]=> + &int(1) + [1]=> + int(2) +} +int(2) +array(2) { + [0]=> + int(1) + [1]=> + &int(2) +} diff --git a/Zend/tests/list/list_reference_004.phpt b/Zend/tests/list/list_reference_004.phpt new file mode 100644 index 0000000000000..fc9955e28a084 --- /dev/null +++ b/Zend/tests/list/list_reference_004.phpt @@ -0,0 +1,28 @@ +--TEST-- +"Reference Unpacking - Foreach" list() +--FILE-- + +--EXPECTF-- +array(2) { + [0]=> + array(2) { + [0]=> + int(2) + [1]=> + int(2) + } + [1]=> + array(2) { + [0]=> + &int(4) + [1]=> + int(4) + } +} diff --git a/Zend/tests/list/list_reference_005.phpt b/Zend/tests/list/list_reference_005.phpt new file mode 100644 index 0000000000000..397f9013b5c46 --- /dev/null +++ b/Zend/tests/list/list_reference_005.phpt @@ -0,0 +1,73 @@ +--TEST-- +"Reference Unpacking - Class Property and Methods" list() +--FILE-- +a; + } + + public function &getVarRef() { + return $this->a; + } +} + +class B { + static $a = [['world']]; +} + +$a = new A(); +[&$var] = $a->a; +[&$var_too] = $a->b; +var_dump($a->a); +var_dump($a->b); + +$a = new A(); +[&$var] = $a->getVar(); +var_dump($a->a); + +$a = new A(); +[&$var] = $a->getVarRef(); +var_dump($a->a); + +[&$var] = B::$a; +var_dump(B::$a); +?> +--EXPECTF-- +array(1) { + [0]=> + &array(1) { + [0]=> + string(5) "hello" + } +} +array(1) { + [0]=> + &string(5) "world" +} + +Notice: Attempting to set reference to non referenceable value in %s on line %d +array(1) { + [0]=> + array(1) { + [0]=> + string(5) "hello" + } +} +array(1) { + [0]=> + &array(1) { + [0]=> + string(5) "hello" + } +} +array(1) { + [0]=> + &array(1) { + [0]=> + string(5) "world" + } +} diff --git a/Zend/tests/list/list_reference_006.phpt b/Zend/tests/list/list_reference_006.phpt new file mode 100644 index 0000000000000..f85edf04a49ad --- /dev/null +++ b/Zend/tests/list/list_reference_006.phpt @@ -0,0 +1,58 @@ +--TEST-- +"Reference Unpacking - Class ArrayAccess No Reference" list() +--FILE-- +s = $a; } + function offsetSet ($k, $v) { $this->s[$k] = $v; } + function offsetGet ($k) { return $this->s[$k]; } + function offsetExists ($k) { return isset($this->s[$k]); } + function offsetUnset ($k) { unset($this->s[$k]); } +} + +$a = new StorageNoRef([1, 2]); +list(&$one, $two) = $a; +var_dump($a); + +$a = new StorageNoRef([1, 2]); +list(,,list($var)) = $a; +var_dump($a); + +$a = new StorageNoRef(['one' => 1, 'two' => 2]); +['one' => &$one, 'two' => $two] = $a; +var_dump($a); +?> +--EXPECTF-- +Notice: Indirect modification of overloaded element of %s has no effect in %s on line %d +object(StorageNoRef)#1 (1) { + ["s":"StorageNoRef":private]=> + array(2) { + [0]=> + int(1) + [1]=> + int(2) + } +} + +Notice: Undefined offset: 2 in %s on line %d +object(StorageNoRef)#2 (1) { + ["s":"StorageNoRef":private]=> + array(2) { + [0]=> + int(1) + [1]=> + int(2) + } +} + +Notice: Indirect modification of overloaded element of %s has no effect in %s on line %d +object(StorageNoRef)#1 (1) { + ["s":"StorageNoRef":private]=> + array(2) { + ["one"]=> + int(1) + ["two"]=> + int(2) + } +} diff --git a/Zend/tests/list/list_reference_007.phpt b/Zend/tests/list/list_reference_007.phpt new file mode 100644 index 0000000000000..51f1cac4960aa --- /dev/null +++ b/Zend/tests/list/list_reference_007.phpt @@ -0,0 +1,75 @@ +--TEST-- +"Reference Unpacking - Class ArrayAccess With Reference" list() +--FILE-- +s = $a; } + function offsetSet ($k, $v) { $this->s[$k] = $v; } + function &offsetGet ($k) { return $this->s[$k]; } + function offsetExists ($k) { return isset($this->s[$k]); } + function offsetUnset ($k) { unset($this->s[$k]); } +} + +$a = new StorageRef([1, 2]); +list(&$one, $two) = $a; +var_dump($a); + +$a = new StorageRef([1, 2]); +list(,,list($var)) = $a; +var_dump($a); + +$a = new StorageRef([1, 2]); +list(,,list(&$var)) = $a; +var_dump($a); + +$a = new StorageRef(['one' => 1, 'two' => 2]); +['one' => &$one, 'two' => $two] = $a; +var_dump($a); + +?> +--EXPECTF-- +object(StorageRef)#1 (1) { + ["s":"StorageRef":private]=> + array(2) { + [0]=> + &int(1) + [1]=> + int(2) + } +} +object(StorageRef)#2 (1) { + ["s":"StorageRef":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + NULL + } +} +object(StorageRef)#1 (1) { + ["s":"StorageRef":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + array(1) { + [0]=> + &NULL + } + } +} +object(StorageRef)#2 (1) { + ["s":"StorageRef":private]=> + array(2) { + ["one"]=> + &int(1) + ["two"]=> + int(2) + } +} diff --git a/Zend/tests/list/list_reference_008.phpt b/Zend/tests/list/list_reference_008.phpt new file mode 100644 index 0000000000000..dea63546d2d96 --- /dev/null +++ b/Zend/tests/list/list_reference_008.phpt @@ -0,0 +1,60 @@ +--TEST-- +"Reference Unpacking - Oddities" list() +--FILE-- + +--EXPECTF-- +int(1) +int(1) +array(2) { + [0]=> + &int(1) + [1]=> + &int(1) +} +int(2) +int(2) +array(2) { + [0]=> + &int(2) + [1]=> + &int(2) +} +int(2) +array(2) { + [0]=> + &int(3) + [1]=> + int(2) +} + +Notice: Attempting to set reference to non referenceable value in %s on line %d +int(2) diff --git a/Zend/tests/list/list_reference_009.phpt b/Zend/tests/list/list_reference_009.phpt new file mode 100644 index 0000000000000..f0adc1f088ee0 --- /dev/null +++ b/Zend/tests/list/list_reference_009.phpt @@ -0,0 +1,47 @@ +--TEST-- +"Reference Unpacking - VM Safety" list() +--FILE-- + &$a, + ($ary["foo"] = 1) => &$b +]] = $ary; + +var_dump($ary, $a, $b); +unset($ary, $a, $b); + +$ary = [[0, 1]]; +[ + 0 => &$a, + ($ary["foo"] = 1) => &$b +] = $ary[0]; +var_dump($ary, $a, $b); +?> +--EXPECTF-- +array(2) { + [0]=> + array(2) { + [0]=> + &int(0) + [1]=> + &int(1) + } + ["foo"]=> + int(1) +} +int(0) +int(1) +array(2) { + [0]=> + array(2) { + [0]=> + &int(0) + [1]=> + &int(1) + } + ["foo"]=> + int(1) +} +int(0) +int(1) diff --git a/Zend/tests/list/list_reference_010.phpt b/Zend/tests/list/list_reference_010.phpt new file mode 100644 index 0000000000000..8ceb344a33b7a --- /dev/null +++ b/Zend/tests/list/list_reference_010.phpt @@ -0,0 +1,8 @@ +--TEST-- +"Reference Unpacking - Compile Error (scalar)" list() +--FILE-- + +--EXPECTF-- +Fatal error: Cannot assign reference to non referencable value in %s on line %d diff --git a/Zend/tests/list/list_reference_011.phpt b/Zend/tests/list/list_reference_011.phpt new file mode 100644 index 0000000000000..405f34f22737e --- /dev/null +++ b/Zend/tests/list/list_reference_011.phpt @@ -0,0 +1,9 @@ +--TEST-- +"Reference Unpacking - Compile Error (const)" list() +--FILE-- + +--EXPECTF-- +Fatal error: Cannot assign reference to non referencable value in %s on line %d diff --git a/Zend/tests/list_009.phpt b/Zend/tests/list_009.phpt deleted file mode 100644 index c28ca8000a2fa..0000000000000 --- a/Zend/tests/list_009.phpt +++ /dev/null @@ -1,14 +0,0 @@ ---TEST-- -list with by-reference assignment should fail ---FILE-- - ---EXPECTF-- -Fatal error: [] and list() assignments cannot be by reference in %s on line %d diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 75bee6708d139..42d90dff61db9 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -772,7 +772,8 @@ void zend_do_free(znode *op1) /* {{{ */ } } else { while (opline >= CG(active_op_array)->opcodes) { - if (opline->opcode == ZEND_FETCH_LIST && + if ((opline->opcode == ZEND_FETCH_LIST_R || + opline->opcode == ZEND_FETCH_LIST_W) && opline->op1_type == IS_VAR && opline->op1.var == op1->u.op.var) { zend_emit_op(NULL, ZEND_FREE, op1, NULL); @@ -2074,7 +2075,8 @@ static void zend_check_live_ranges(zend_op *opline) /* {{{ */ opline->opcode == ZEND_ROPE_ADD || opline->opcode == ZEND_ROPE_END || opline->opcode == ZEND_END_SILENCE || - opline->opcode == ZEND_FETCH_LIST || + opline->opcode == ZEND_FETCH_LIST_R || + opline->opcode == ZEND_FETCH_LIST_W || opline->opcode == ZEND_VERIFY_RETURN_TYPE || opline->opcode == ZEND_BIND_LEXICAL) { /* these opcodes are handled separately */ @@ -2789,6 +2791,41 @@ static void zend_verify_list_assign_target(zend_ast *var_ast, zend_bool old_styl } /* }}} */ +static inline void zend_emit_assign_ref_znode(zend_ast *var_ast, znode *value_node); + +static zend_bool zend_compile_list_assign_requires_w(zend_ast *ast) { /* {{{ */ + zend_bool require_w = 0; + zend_ast_list *list; + uint32_t i; + + if (ast->kind != ZEND_AST_ARRAY) { + return 0; + } + + list = zend_ast_get_list(ast); + + for (i = 0; i < list->children; ++i) { + zend_ast *elem_ast = list->child[i]; + + if (elem_ast) { + zend_ast *var_ast = elem_ast->child[0]; + + if (elem_ast->kind == ZEND_AST_ARRAY_ELEM && elem_ast->attr) { + require_w = 1; + } else if (elem_ast->kind == ZEND_AST_ARRAY_ELEM && var_ast->kind == ZEND_AST_ARRAY) { + require_w = zend_compile_list_assign_requires_w(var_ast); + } + + if (require_w) { + break; + } + } + } + + return require_w; +} +/* }}} */ + static void zend_compile_list_assign( znode *result, zend_ast *ast, znode *expr_node, zend_bool old_style) /* {{{ */ { @@ -2816,10 +2853,6 @@ static void zend_compile_list_assign( } } - if (elem_ast->attr) { - zend_error(E_COMPILE_ERROR, "[] and list() assignments cannot be by reference"); - } - var_ast = elem_ast->child[0]; key_ast = elem_ast->child[1]; has_elems = 1; @@ -2847,8 +2880,18 @@ static void zend_compile_list_assign( zend_verify_list_assign_target(var_ast, old_style); - zend_emit_op(&fetch_result, ZEND_FETCH_LIST, expr_node, &dim_node); - zend_emit_assign_znode(var_ast, &fetch_result); + if (elem_ast->attr || zend_compile_list_assign_requires_w(var_ast)) { + zend_emit_op(&fetch_result, ZEND_FETCH_LIST_W, expr_node, &dim_node); + zend_emit_op(&fetch_result, ZEND_MAKE_REF, &fetch_result, NULL); + } else { + zend_emit_op(&fetch_result, ZEND_FETCH_LIST_R, expr_node, &dim_node); + } + + if (elem_ast->attr) { + zend_emit_assign_ref_znode(var_ast, &fetch_result); + } else { + zend_emit_assign_znode(var_ast, &fetch_result); + } } if (has_elems == 0) { @@ -3011,7 +3054,16 @@ void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */ zend_emit_op(&expr_node, ZEND_QM_ASSIGN, &cv_node, NULL); } } else { - zend_compile_expr(&expr_node, expr_ast); + if (zend_compile_list_assign_requires_w(var_ast)) { + if (zend_is_variable(expr_ast)) { + zend_compile_var(&expr_node, expr_ast, BP_VAR_W); + zend_emit_op(&expr_node, ZEND_MAKE_REF, &expr_node, NULL); + } else { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot assign reference to non referencable value"); + } + } else { + zend_compile_expr(&expr_node, expr_ast); + } } zend_compile_list_assign(result, var_ast, &expr_node, var_ast->attr); @@ -4727,6 +4779,7 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ zend_ast *key_ast = ast->child[2]; zend_ast *stmt_ast = ast->child[3]; zend_bool by_ref = value_ast->kind == ZEND_AST_REF; + zend_bool list_ref = 0; zend_bool is_variable = zend_is_variable(expr_ast) && !zend_is_call(expr_ast) && zend_can_write_to_variable(expr_ast); @@ -4747,28 +4800,32 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ value_ast = value_ast->child[0]; } - if (by_ref && is_variable) { + if (value_ast->kind == ZEND_AST_ARRAY && zend_compile_list_assign_requires_w(value_ast)) { + list_ref = 1; + } + + if ((by_ref || list_ref) && is_variable) { zend_compile_var(&expr_node, expr_ast, BP_VAR_W); } else { zend_compile_expr(&expr_node, expr_ast); } - if (by_ref) { + if (by_ref || list_ref) { zend_separate_if_call_and_write(&expr_node, expr_ast, BP_VAR_W); } opnum_reset = get_next_op_number(CG(active_op_array)); - opline = zend_emit_op(&reset_node, by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL); + opline = zend_emit_op(&reset_node, (by_ref || list_ref) ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL); zend_begin_loop(ZEND_FE_FREE, &reset_node); 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); + opline = zend_emit_op(NULL, (by_ref || list_ref) ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL); 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) { + zend_try_compile_cv(&value_node, value_ast) == SUCCESS) { SET_NODE(opline->op2, &value_node); } else { opline->op2_type = IS_VAR; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index b44922f395279..d30c02cb0a1bc 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1130,6 +1130,7 @@ static zend_never_inline ZEND_COLD void zend_wrong_string_offset(EXECUTE_DATA_D) case ZEND_FETCH_DIM_RW: case ZEND_FETCH_DIM_FUNC_ARG: case ZEND_FETCH_DIM_UNSET: + case ZEND_FETCH_LIST_W: /* TODO: Encode the "reason" into opline->extended_value??? */ var = opline->result.var; opline++; @@ -1172,6 +1173,7 @@ static zend_never_inline ZEND_COLD void zend_wrong_string_offset(EXECUTE_DATA_D) case ZEND_FETCH_DIM_RW: case ZEND_FETCH_DIM_FUNC_ARG: case ZEND_FETCH_DIM_UNSET: + case ZEND_FETCH_LIST_W: case ZEND_ASSIGN_DIM: msg = "Cannot use string offset as an array"; break; @@ -1837,7 +1839,12 @@ static zend_never_inline void zend_fetch_dimension_address_read_IS(zval *result, zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS, 1, 0 EXECUTE_DATA_CC); } -static zend_never_inline void zend_fetch_dimension_address_read_LIST(zval *result, zval *container, zval *dim EXECUTE_DATA_DC) +static zend_never_inline void zend_fetch_dimension_address_LIST_w(zval *result, zval *container, zval *dim EXECUTE_DATA_DC) +{ + zend_fetch_dimension_address(result, container, dim, IS_TMP_VAR, BP_VAR_W EXECUTE_DATA_CC); +} + +static zend_never_inline void zend_fetch_dimension_address_LIST_r(zval *result, zval *container, zval *dim EXECUTE_DATA_DC) { zend_fetch_dimension_address_read(result, container, dim, IS_TMP_VAR, BP_VAR_R, 0, 0 EXECUTE_DATA_CC); } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index ebdca64f95cbc..d42b7548f68c3 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2047,7 +2047,7 @@ ZEND_VM_HANDLER(97, ZEND_FETCH_OBJ_UNSET, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(98, ZEND_FETCH_LIST, CONST|TMPVAR|CV, CONST|TMPVAR|CV) +ZEND_VM_HANDLER(98, ZEND_FETCH_LIST_R, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -2055,7 +2055,36 @@ ZEND_VM_HANDLER(98, ZEND_FETCH_LIST, CONST|TMPVAR|CV, CONST|TMPVAR|CV) SAVE_OPLINE(); container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); - zend_fetch_dimension_address_read_LIST(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R) EXECUTE_DATA_CC); + zend_fetch_dimension_address_LIST_r(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R) EXECUTE_DATA_CC); + FREE_OP2(); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +ZEND_VM_HANDLER(198, ZEND_FETCH_LIST_W, TMPVAR|CV, CONST|TMPVAR|CV) +{ + USE_OPLINE + zend_free_op free_op1, free_op2; + zval *retval, *container, *dim; + + SAVE_OPLINE(); + retval = EX_VAR(opline->result.var); + container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_W); + dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); + + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { + container = Z_INDIRECT_P(container); + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } else if (UNEXPECTED(!Z_ISREF_P(container))) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + FREE_OP2(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 6f1a607a1e935..5193a3e980ef7 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -5205,7 +5205,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_ } } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_R_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -5213,7 +5213,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CONST_CONST_HA SAVE_OPLINE(); container = RT_CONSTANT(opline, opline->op1); - zend_fetch_dimension_address_read_LIST(EX_VAR(opline->result.var), container, RT_CONSTANT(opline, opline->op2) EXECUTE_DATA_CC); + zend_fetch_dimension_address_LIST_r(EX_VAR(opline->result.var), container, RT_CONSTANT(opline, opline->op2) EXECUTE_DATA_CC); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -9300,7 +9300,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_ } } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_R_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -9308,7 +9308,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CONST_CV_HANDL SAVE_OPLINE(); container = RT_CONSTANT(opline, opline->op1); - zend_fetch_dimension_address_read_LIST(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_undef(opline->op2.var EXECUTE_DATA_CC) EXECUTE_DATA_CC); + zend_fetch_dimension_address_LIST_r(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_undef(opline->op2.var EXECUTE_DATA_CC) EXECUTE_DATA_CC); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -11365,7 +11365,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_ } } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_R_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op2; @@ -11373,7 +11373,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CONST_TMPVAR_H SAVE_OPLINE(); container = RT_CONSTANT(opline, opline->op1); - zend_fetch_dimension_address_read_LIST(EX_VAR(opline->result.var), container, _get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC) EXECUTE_DATA_CC); + zend_fetch_dimension_address_LIST_r(EX_VAR(opline->result.var), container, _get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC) EXECUTE_DATA_CC); zval_ptr_dtor_nogc(free_op2); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -36574,7 +36574,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_CV_CONST_ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_R_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -36582,7 +36582,35 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CV_CONST_HANDL SAVE_OPLINE(); container = _get_zval_ptr_cv_undef(opline->op1.var EXECUTE_DATA_CC); - zend_fetch_dimension_address_read_LIST(EX_VAR(opline->result.var), container, RT_CONSTANT(opline, opline->op2) EXECUTE_DATA_CC); + zend_fetch_dimension_address_LIST_r(EX_VAR(opline->result.var), container, RT_CONSTANT(opline, opline->op2) EXECUTE_DATA_CC); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *retval, *container, *dim; + + SAVE_OPLINE(); + retval = EX_VAR(opline->result.var); + container = _get_zval_ptr_cv_undef(opline->op1.var EXECUTE_DATA_CC); + dim = RT_CONSTANT(opline, opline->op2); + + if (IS_CV & (IS_TMP_VAR|IS_VAR)) { + if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { + container = Z_INDIRECT_P(container); + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } else if (UNEXPECTED(!Z_ISREF_P(container))) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -43049,7 +43077,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_CV_CV_HAN ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_R_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -43057,7 +43085,35 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CV_CV_HANDLER( SAVE_OPLINE(); container = _get_zval_ptr_cv_undef(opline->op1.var EXECUTE_DATA_CC); - zend_fetch_dimension_address_read_LIST(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_undef(opline->op2.var EXECUTE_DATA_CC) EXECUTE_DATA_CC); + zend_fetch_dimension_address_LIST_r(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_undef(opline->op2.var EXECUTE_DATA_CC) EXECUTE_DATA_CC); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *retval, *container, *dim; + + SAVE_OPLINE(); + retval = EX_VAR(opline->result.var); + container = _get_zval_ptr_cv_undef(opline->op1.var EXECUTE_DATA_CC); + dim = _get_zval_ptr_cv_undef(opline->op2.var EXECUTE_DATA_CC); + + if (IS_CV & (IS_TMP_VAR|IS_VAR)) { + if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { + container = Z_INDIRECT_P(container); + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } else if (UNEXPECTED(!Z_ISREF_P(container))) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -46748,7 +46804,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_CV_TMPVAR ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_R_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op2; @@ -46756,7 +46812,36 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CV_TMPVAR_HAND SAVE_OPLINE(); container = _get_zval_ptr_cv_undef(opline->op1.var EXECUTE_DATA_CC); - zend_fetch_dimension_address_read_LIST(EX_VAR(opline->result.var), container, _get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC) EXECUTE_DATA_CC); + zend_fetch_dimension_address_LIST_r(EX_VAR(opline->result.var), container, _get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC) EXECUTE_DATA_CC); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op2; + zval *retval, *container, *dim; + + SAVE_OPLINE(); + retval = EX_VAR(opline->result.var); + container = _get_zval_ptr_cv_undef(opline->op1.var EXECUTE_DATA_CC); + dim = _get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC); + + if (IS_CV & (IS_TMP_VAR|IS_VAR)) { + if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { + container = Z_INDIRECT_P(container); + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } else if (UNEXPECTED(!Z_ISREF_P(container))) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + zval_ptr_dtor_nogc(free_op2); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -49933,7 +50018,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMPVAR_CONST ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_R_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op1; @@ -49941,7 +50026,35 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_TMPVAR_CONST_H SAVE_OPLINE(); container = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); - zend_fetch_dimension_address_read_LIST(EX_VAR(opline->result.var), container, RT_CONSTANT(opline, opline->op2) EXECUTE_DATA_CC); + zend_fetch_dimension_address_LIST_r(EX_VAR(opline->result.var), container, RT_CONSTANT(opline, opline->op2) EXECUTE_DATA_CC); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *retval, *container, *dim; + + SAVE_OPLINE(); + retval = EX_VAR(opline->result.var); + container = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); + dim = RT_CONSTANT(opline, opline->op2); + + if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { + if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { + container = Z_INDIRECT_P(container); + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } else if (UNEXPECTED(!Z_ISREF_P(container))) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -52318,7 +52431,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMPVAR_CV_HA ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_R_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op1; @@ -52326,7 +52439,35 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_TMPVAR_CV_HAND SAVE_OPLINE(); container = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); - zend_fetch_dimension_address_read_LIST(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_undef(opline->op2.var EXECUTE_DATA_CC) EXECUTE_DATA_CC); + zend_fetch_dimension_address_LIST_r(EX_VAR(opline->result.var), container, _get_zval_ptr_cv_undef(opline->op2.var EXECUTE_DATA_CC) EXECUTE_DATA_CC); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *retval, *container, *dim; + + SAVE_OPLINE(); + retval = EX_VAR(opline->result.var); + container = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); + dim = _get_zval_ptr_cv_undef(opline->op2.var EXECUTE_DATA_CC); + + if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { + if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { + container = Z_INDIRECT_P(container); + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } else if (UNEXPECTED(!Z_ISREF_P(container))) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -53677,7 +53818,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMPVAR_TMPVA ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_R_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -53685,7 +53826,36 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_ SAVE_OPLINE(); container = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); - zend_fetch_dimension_address_read_LIST(EX_VAR(opline->result.var), container, _get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC) EXECUTE_DATA_CC); + zend_fetch_dimension_address_LIST_r(EX_VAR(opline->result.var), container, _get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC) EXECUTE_DATA_CC); + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1, free_op2; + zval *retval, *container, *dim; + + SAVE_OPLINE(); + retval = EX_VAR(opline->result.var); + container = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); + dim = _get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC); + + if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { + if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { + container = Z_INDIRECT_P(container); + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } else if (UNEXPECTED(!Z_ISREF_P(container))) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + zval_ptr_dtor_nogc(free_op2); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -57451,31 +57621,31 @@ ZEND_API void execute_ex(zend_execute_data *ex) (void*)&&ZEND_FETCH_OBJ_UNSET_SPEC_CV_TMPVAR_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_FETCH_OBJ_UNSET_SPEC_CV_CV_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_CONST_CONST_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_CONST_TMPVAR_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_CONST_TMPVAR_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_CONST_CONST_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_CONST_TMPVAR_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_CONST_TMPVAR_LABEL, (void*)&&ZEND_NULL_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_CONST_CV_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_TMPVAR_CONST_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_CONST_CV_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_TMPVAR_CONST_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_TMPVAR_TMPVAR_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_TMPVAR_TMPVAR_LABEL, (void*)&&ZEND_NULL_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_TMPVAR_CV_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_TMPVAR_CONST_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_TMPVAR_CV_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_TMPVAR_CONST_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_TMPVAR_TMPVAR_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_TMPVAR_TMPVAR_LABEL, (void*)&&ZEND_NULL_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_TMPVAR_CV_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_TMPVAR_CV_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_CV_CONST_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_CV_TMPVAR_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_CV_TMPVAR_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_CV_CONST_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_CV_TMPVAR_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_CV_TMPVAR_LABEL, (void*)&&ZEND_NULL_LABEL, - (void*)&&ZEND_FETCH_LIST_SPEC_CV_CV_LABEL, + (void*)&&ZEND_FETCH_LIST_R_SPEC_CV_CV_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, @@ -59076,6 +59246,31 @@ ZEND_API void execute_ex(zend_execute_data *ex) (void*)&&ZEND_ISSET_ISEMPTY_CV_SPEC_CV_UNUSED_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_CONST_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_CV_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_CONST_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_CV_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_CV_CONST_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_CV_TMPVAR_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_CV_TMPVAR_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_CV_CV_LABEL, + (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_ADD_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV_LABEL, (void*)&&ZEND_ADD_LONG_NO_OVERFLOW_SPEC_CONST_TMPVARCV_LABEL, (void*)&&ZEND_NULL_LABEL, @@ -60463,8 +60658,8 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_CONST): ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); - HYBRID_CASE(ZEND_FETCH_LIST_SPEC_CONST_CONST): - ZEND_FETCH_LIST_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_CASE(ZEND_FETCH_LIST_R_SPEC_CONST_CONST): + ZEND_FETCH_LIST_R_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); HYBRID_CASE(ZEND_FAST_CONCAT_SPEC_CONST_CONST): ZEND_FAST_CONCAT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -60721,8 +60916,8 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_CV): ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); - HYBRID_CASE(ZEND_FETCH_LIST_SPEC_CONST_CV): - ZEND_FETCH_LIST_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_CASE(ZEND_FETCH_LIST_R_SPEC_CONST_CV): + ZEND_FETCH_LIST_R_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); HYBRID_CASE(ZEND_FAST_CONCAT_SPEC_CONST_CV): ZEND_FAST_CONCAT_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -60832,8 +61027,8 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_TMPVAR): ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); - HYBRID_CASE(ZEND_FETCH_LIST_SPEC_CONST_TMPVAR): - ZEND_FETCH_LIST_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_CASE(ZEND_FETCH_LIST_R_SPEC_CONST_TMPVAR): + ZEND_FETCH_LIST_R_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); HYBRID_CASE(ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR): ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -62644,8 +62839,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_FETCH_OBJ_UNSET_SPEC_CV_CONST): ZEND_FETCH_OBJ_UNSET_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); - HYBRID_CASE(ZEND_FETCH_LIST_SPEC_CV_CONST): - ZEND_FETCH_LIST_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_CASE(ZEND_FETCH_LIST_R_SPEC_CV_CONST): + ZEND_FETCH_LIST_R_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); + HYBRID_CASE(ZEND_FETCH_LIST_W_SPEC_CV_CONST): + ZEND_FETCH_LIST_W_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); HYBRID_CASE(ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DATA_CONST): ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DATA_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -63151,8 +63349,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_FETCH_OBJ_UNSET_SPEC_CV_CV): ZEND_FETCH_OBJ_UNSET_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); - HYBRID_CASE(ZEND_FETCH_LIST_SPEC_CV_CV): - ZEND_FETCH_LIST_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_CASE(ZEND_FETCH_LIST_R_SPEC_CV_CV): + ZEND_FETCH_LIST_R_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); + HYBRID_CASE(ZEND_FETCH_LIST_W_SPEC_CV_CV): + ZEND_FETCH_LIST_W_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); HYBRID_CASE(ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_CONST): ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -63430,8 +63631,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_FETCH_OBJ_UNSET_SPEC_CV_TMPVAR): ZEND_FETCH_OBJ_UNSET_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); - HYBRID_CASE(ZEND_FETCH_LIST_SPEC_CV_TMPVAR): - ZEND_FETCH_LIST_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_CASE(ZEND_FETCH_LIST_R_SPEC_CV_TMPVAR): + ZEND_FETCH_LIST_R_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); + HYBRID_CASE(ZEND_FETCH_LIST_W_SPEC_CV_TMPVAR): + ZEND_FETCH_LIST_W_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); HYBRID_CASE(ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_DATA_CONST): ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_DATA_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -63616,8 +63820,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_FETCH_OBJ_IS_SPEC_TMPVAR_CONST): ZEND_FETCH_OBJ_IS_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); - HYBRID_CASE(ZEND_FETCH_LIST_SPEC_TMPVAR_CONST): - ZEND_FETCH_LIST_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_CASE(ZEND_FETCH_LIST_R_SPEC_TMPVAR_CONST): + ZEND_FETCH_LIST_R_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); + HYBRID_CASE(ZEND_FETCH_LIST_W_SPEC_TMPVAR_CONST): + ZEND_FETCH_LIST_W_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); HYBRID_CASE(ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST): ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -63793,8 +64000,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_FETCH_OBJ_IS_SPEC_TMPVAR_CV): ZEND_FETCH_OBJ_IS_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); - HYBRID_CASE(ZEND_FETCH_LIST_SPEC_TMPVAR_CV): - ZEND_FETCH_LIST_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_CASE(ZEND_FETCH_LIST_R_SPEC_TMPVAR_CV): + ZEND_FETCH_LIST_R_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); + HYBRID_CASE(ZEND_FETCH_LIST_W_SPEC_TMPVAR_CV): + ZEND_FETCH_LIST_W_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); HYBRID_CASE(ZEND_FAST_CONCAT_SPEC_TMPVAR_CV): ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -63877,8 +64087,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_FETCH_OBJ_IS_SPEC_TMPVAR_TMPVAR): ZEND_FETCH_OBJ_IS_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); - HYBRID_CASE(ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR): - ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_CASE(ZEND_FETCH_LIST_R_SPEC_TMPVAR_TMPVAR): + ZEND_FETCH_LIST_R_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); + HYBRID_CASE(ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR): + ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); HYBRID_CASE(ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR): ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -66441,31 +66654,31 @@ void zend_init_opcodes_handlers(void) ZEND_FETCH_OBJ_UNSET_SPEC_CV_TMPVAR_HANDLER, ZEND_NULL_HANDLER, ZEND_FETCH_OBJ_UNSET_SPEC_CV_CV_HANDLER, - ZEND_FETCH_LIST_SPEC_CONST_CONST_HANDLER, - ZEND_FETCH_LIST_SPEC_CONST_TMPVAR_HANDLER, - ZEND_FETCH_LIST_SPEC_CONST_TMPVAR_HANDLER, + ZEND_FETCH_LIST_R_SPEC_CONST_CONST_HANDLER, + ZEND_FETCH_LIST_R_SPEC_CONST_TMPVAR_HANDLER, + ZEND_FETCH_LIST_R_SPEC_CONST_TMPVAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_FETCH_LIST_SPEC_CONST_CV_HANDLER, - ZEND_FETCH_LIST_SPEC_TMPVAR_CONST_HANDLER, - ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_HANDLER, - ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_HANDLER, + ZEND_FETCH_LIST_R_SPEC_CONST_CV_HANDLER, + ZEND_FETCH_LIST_R_SPEC_TMPVAR_CONST_HANDLER, + ZEND_FETCH_LIST_R_SPEC_TMPVAR_TMPVAR_HANDLER, + ZEND_FETCH_LIST_R_SPEC_TMPVAR_TMPVAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_FETCH_LIST_SPEC_TMPVAR_CV_HANDLER, - ZEND_FETCH_LIST_SPEC_TMPVAR_CONST_HANDLER, - ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_HANDLER, - ZEND_FETCH_LIST_SPEC_TMPVAR_TMPVAR_HANDLER, + ZEND_FETCH_LIST_R_SPEC_TMPVAR_CV_HANDLER, + ZEND_FETCH_LIST_R_SPEC_TMPVAR_CONST_HANDLER, + ZEND_FETCH_LIST_R_SPEC_TMPVAR_TMPVAR_HANDLER, + ZEND_FETCH_LIST_R_SPEC_TMPVAR_TMPVAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_FETCH_LIST_SPEC_TMPVAR_CV_HANDLER, + ZEND_FETCH_LIST_R_SPEC_TMPVAR_CV_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_FETCH_LIST_SPEC_CV_CONST_HANDLER, - ZEND_FETCH_LIST_SPEC_CV_TMPVAR_HANDLER, - ZEND_FETCH_LIST_SPEC_CV_TMPVAR_HANDLER, + ZEND_FETCH_LIST_R_SPEC_CV_CONST_HANDLER, + ZEND_FETCH_LIST_R_SPEC_CV_TMPVAR_HANDLER, + ZEND_FETCH_LIST_R_SPEC_CV_TMPVAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_FETCH_LIST_SPEC_CV_CV_HANDLER, + ZEND_FETCH_LIST_R_SPEC_CV_CV_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, @@ -68066,6 +68279,31 @@ void zend_init_opcodes_handlers(void) ZEND_ISSET_ISEMPTY_CV_SPEC_CV_UNUSED_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_FETCH_LIST_W_SPEC_TMPVAR_CONST_HANDLER, + ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_HANDLER, + ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_FETCH_LIST_W_SPEC_TMPVAR_CV_HANDLER, + ZEND_FETCH_LIST_W_SPEC_TMPVAR_CONST_HANDLER, + ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_HANDLER, + ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_FETCH_LIST_W_SPEC_TMPVAR_CV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_FETCH_LIST_W_SPEC_CV_CONST_HANDLER, + ZEND_FETCH_LIST_W_SPEC_CV_TMPVAR_HANDLER, + ZEND_FETCH_LIST_W_SPEC_CV_TMPVAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_FETCH_LIST_W_SPEC_CV_CV_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, @@ -69183,7 +69421,7 @@ void zend_init_opcodes_handlers(void) 2257 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2282 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2307 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 4921, + 4946, 2332, 2333, 2334, @@ -69268,7 +69506,7 @@ void zend_init_opcodes_handlers(void) 3531 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3556 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3581 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 4921, + 4946, 3606 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3631 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3656 | SPEC_RULE_OP1 | SPEC_RULE_OP2, @@ -69281,7 +69519,8 @@ void zend_init_opcodes_handlers(void) 3831 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3856 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 3881 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 4921 + 3906 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 4946 }; #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) zend_opcode_handler_funcs = labels; @@ -69476,7 +69715,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 = 3906 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3931 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -69484,7 +69723,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 = 3931 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3956 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -69492,7 +69731,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 = 3956 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3981 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -69503,17 +69742,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 = 3981 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 4006 | 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 = 4006 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 4031 | 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 = 4031 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 4056 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; case ZEND_MUL: @@ -69521,7 +69760,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 = 4056 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 4081 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -69529,7 +69768,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 = 4081 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 4106 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -69537,7 +69776,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 = 4106 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 4131 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -69548,7 +69787,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 = 4131 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4156 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -69556,7 +69795,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 = 4206 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4231 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -69567,7 +69806,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 = 4281 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4306 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -69575,7 +69814,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 = 4356 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4381 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -69586,12 +69825,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 = 4431 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4456 | 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 = 4506 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4531 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_IS_SMALLER_OR_EQUAL: @@ -69599,75 +69838,75 @@ 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 = 4581 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4606 | 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 = 4656 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4681 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_QM_ASSIGN: if (op1_info == MAY_BE_DOUBLE) { - spec = 4821 | SPEC_RULE_OP1; + spec = 4846 | 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 = 4826 | SPEC_RULE_OP1; + spec = 4851 | SPEC_RULE_OP1; } break; case ZEND_PRE_INC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 4731 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4756 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if (op1_info == MAY_BE_LONG) { - spec = 4741 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4766 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)) { - spec = 4751 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4776 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } break; case ZEND_PRE_DEC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 4761 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4786 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if (op1_info == MAY_BE_LONG) { - spec = 4771 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4796 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)) { - spec = 4781 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4806 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } break; case ZEND_POST_INC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 4791 | SPEC_RULE_OP1; + spec = 4816 | SPEC_RULE_OP1; } else if (op1_info == MAY_BE_LONG) { - spec = 4796 | SPEC_RULE_OP1; + spec = 4821 | SPEC_RULE_OP1; } else if (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)) { - spec = 4801 | SPEC_RULE_OP1; + spec = 4826 | SPEC_RULE_OP1; } break; case ZEND_POST_DEC: if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { - spec = 4806 | SPEC_RULE_OP1; + spec = 4831 | SPEC_RULE_OP1; } else if (op1_info == MAY_BE_LONG) { - spec = 4811 | SPEC_RULE_OP1; + spec = 4836 | SPEC_RULE_OP1; } else if (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)) { - spec = 4816 | SPEC_RULE_OP1; + spec = 4841 | SPEC_RULE_OP1; } break; case ZEND_SEND_VAR_EX: if ((op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 4861 | SPEC_RULE_OP1 | SPEC_RULE_QUICK_ARG; + spec = 4886 | SPEC_RULE_OP1 | SPEC_RULE_QUICK_ARG; } break; case ZEND_FE_FETCH_R: if (op->op2_type == IS_CV && (op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY) { - spec = 4871 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_RETVAL; + spec = 4896 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_RETVAL; } 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 = 4831 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 4856 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; case ZEND_SEND_VAR: if ((op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 4856 | SPEC_RULE_OP1; + spec = 4881 | SPEC_RULE_OP1; } break; default: diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index ecfe4645fa05e..f60dec7345ee7 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[198] = { +static const char *zend_vm_opcodes_names[199] = { "ZEND_NOP", "ZEND_ADD", "ZEND_SUB", @@ -120,7 +120,7 @@ static const char *zend_vm_opcodes_names[198] = { "ZEND_FETCH_UNSET", "ZEND_FETCH_DIM_UNSET", "ZEND_FETCH_OBJ_UNSET", - "ZEND_FETCH_LIST", + "ZEND_FETCH_LIST_R", "ZEND_FETCH_CONSTANT", NULL, "ZEND_EXT_STMT", @@ -220,9 +220,10 @@ static const char *zend_vm_opcodes_names[198] = { "ZEND_FUNC_GET_ARGS", "ZEND_UNSET_CV", "ZEND_ISSET_ISEMPTY_CV", + "ZEND_FETCH_LIST_W", }; -static uint32_t zend_vm_opcodes_flags[198] = { +static uint32_t zend_vm_opcodes_flags[199] = { 0x00000000, 0x00000707, 0x00000707, @@ -421,6 +422,7 @@ static uint32_t zend_vm_opcodes_flags[198] = { 0x00000103, 0x00000101, 0x00020101, + 0x00000705, }; 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 3be364150f939..577ecb667a05e 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -171,7 +171,7 @@ END_EXTERN_C() #define ZEND_FETCH_UNSET 95 #define ZEND_FETCH_DIM_UNSET 96 #define ZEND_FETCH_OBJ_UNSET 97 -#define ZEND_FETCH_LIST 98 +#define ZEND_FETCH_LIST_R 98 #define ZEND_FETCH_CONSTANT 99 #define ZEND_EXT_STMT 101 #define ZEND_EXT_FCALL_BEGIN 102 @@ -269,7 +269,8 @@ END_EXTERN_C() #define ZEND_FUNC_GET_ARGS 195 #define ZEND_UNSET_CV 196 #define ZEND_ISSET_ISEMPTY_CV 197 +#define ZEND_FETCH_LIST_W 198 -#define ZEND_VM_LAST_OPCODE 197 +#define ZEND_VM_LAST_OPCODE 198 #endif diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index fcd20c86fe104..8a9ce893cfce0 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -410,7 +410,7 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array } #endif - case ZEND_FETCH_LIST: + case ZEND_FETCH_LIST_R: if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { /* LIST variable will be deleted later by FREE */ Tsource[VAR_NUM(opline->op1.var)] = NULL; diff --git a/ext/opcache/Optimizer/sccp.c b/ext/opcache/Optimizer/sccp.c index 347e1cc77abce..07c2896af57ef 100644 --- a/ext/opcache/Optimizer/sccp.c +++ b/ext/opcache/Optimizer/sccp.c @@ -220,6 +220,7 @@ static zend_bool can_replace_op1( case ZEND_FETCH_OBJ_RW: case ZEND_FETCH_OBJ_UNSET: case ZEND_FETCH_OBJ_FUNC_ARG: + case ZEND_FETCH_LIST_W: case ZEND_UNSET_DIM: case ZEND_UNSET_OBJ: case ZEND_SEND_REF: @@ -285,7 +286,7 @@ static zend_bool try_replace_op1( } else { // TODO: check the following special cases ??? switch (opline->opcode) { - case ZEND_FETCH_LIST: + case ZEND_FETCH_LIST_R: case ZEND_CASE: case ZEND_SWITCH_STRING: case ZEND_SWITCH_LONG: @@ -1525,11 +1526,11 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o break; case ZEND_FETCH_DIM_R: case ZEND_FETCH_DIM_IS: - case ZEND_FETCH_LIST: + case ZEND_FETCH_LIST_R: SKIP_IF_TOP(op1); SKIP_IF_TOP(op2); - if (ct_eval_fetch_dim(&zv, op1, op2, (opline->opcode != ZEND_FETCH_LIST)) == SUCCESS) { + if (ct_eval_fetch_dim(&zv, op1, op2, (opline->opcode != ZEND_FETCH_LIST_R)) == SUCCESS) { SET_RESULT(result, &zv); zval_ptr_dtor_nogc(&zv); break; diff --git a/ext/opcache/Optimizer/zend_dfg.c b/ext/opcache/Optimizer/zend_dfg.c index 49be85c6b87af..2ac060ba7e4b4 100644 --- a/ext/opcache/Optimizer/zend_dfg.c +++ b/ext/opcache/Optimizer/zend_dfg.c @@ -127,6 +127,7 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg case ZEND_FETCH_OBJ_RW: case ZEND_FETCH_OBJ_FUNC_ARG: case ZEND_FETCH_OBJ_UNSET: + case ZEND_FETCH_LIST_W: case ZEND_VERIFY_RETURN_TYPE: case ZEND_PRE_INC_OBJ: case ZEND_PRE_DEC_OBJ: diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 0246c5070a8ca..aebebb1f0c5f9 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -2994,12 +2994,14 @@ static int zend_update_type_info(const zend_op_array *op_array, case ZEND_FETCH_DIM_W: case ZEND_FETCH_DIM_UNSET: case ZEND_FETCH_DIM_FUNC_ARG: - case ZEND_FETCH_LIST: + case ZEND_FETCH_LIST_R: + case ZEND_FETCH_LIST_W: if (ssa_ops[i].op1_def >= 0) { tmp = t1 & ~(MAY_BE_RC1|MAY_BE_RCN); if (opline->opcode == ZEND_FETCH_DIM_W || opline->opcode == ZEND_FETCH_DIM_RW || - opline->opcode == ZEND_FETCH_DIM_FUNC_ARG) { + opline->opcode == ZEND_FETCH_DIM_FUNC_ARG || + opline->opcode == ZEND_FETCH_LIST_W) { if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) { if (opline->opcode != ZEND_FETCH_DIM_FUNC_ARG) { tmp &= ~(MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE); @@ -3046,6 +3048,7 @@ static int zend_update_type_info(const zend_op_array *op_array, case ZEND_FETCH_DIM_W: case ZEND_FETCH_DIM_RW: case ZEND_FETCH_DIM_FUNC_ARG: + case ZEND_FETCH_LIST_W: case ZEND_ASSIGN_ADD: case ZEND_ASSIGN_SUB: case ZEND_ASSIGN_MUL: @@ -3115,13 +3118,14 @@ static int zend_update_type_info(const zend_op_array *op_array, } /* FETCH_LIST on a string behaves like FETCH_R on null */ tmp = zend_array_element_type( - opline->opcode != ZEND_FETCH_LIST ? t1 : ((t1 & ~MAY_BE_STRING) | MAY_BE_NULL), + opline->opcode != ZEND_FETCH_LIST_R ? t1 : ((t1 & ~MAY_BE_STRING) | MAY_BE_NULL), opline->opcode != ZEND_FETCH_DIM_R && opline->opcode != ZEND_FETCH_DIM_IS - && opline->opcode != ZEND_FETCH_LIST, + && opline->opcode != ZEND_FETCH_LIST_R, opline->op2_type == IS_UNUSED); if (opline->opcode == ZEND_FETCH_DIM_W || opline->opcode == ZEND_FETCH_DIM_RW || - opline->opcode == ZEND_FETCH_DIM_FUNC_ARG) { + opline->opcode == ZEND_FETCH_DIM_FUNC_ARG || + opline->opcode == ZEND_FETCH_LIST_W) { if (t1 & (MAY_BE_ERROR|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE|MAY_BE_OBJECT)) { tmp |= MAY_BE_ERROR; } else if (opline->op2_type == IS_UNUSED) { @@ -4006,7 +4010,7 @@ int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa case ZEND_CASE: case ZEND_FE_FETCH_R: case ZEND_FE_FETCH_RW: - case ZEND_FETCH_LIST: + case ZEND_FETCH_LIST_R: case ZEND_QM_ASSIGN: case ZEND_SEND_VAL: case ZEND_SEND_VAL_EX: diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 1e5b4a2a7358d..f63c2c038391e 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -269,6 +269,7 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array, case ZEND_FETCH_DIM_RW: case ZEND_FETCH_DIM_FUNC_ARG: case ZEND_FETCH_DIM_UNSET: + case ZEND_FETCH_LIST_W: case ZEND_ASSIGN_DIM: case ZEND_RETURN_BY_REF: return 0; @@ -307,7 +308,7 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array, * zend_optimizer_replace_by_const() supports this. */ return 0; case ZEND_CASE: - case ZEND_FETCH_LIST: + case ZEND_FETCH_LIST_R: return 0; case ZEND_CONCAT: case ZEND_FAST_CONCAT: @@ -450,7 +451,8 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array, case ZEND_FETCH_DIM_IS: case ZEND_FETCH_DIM_FUNC_ARG: case ZEND_FETCH_DIM_UNSET: - case ZEND_FETCH_LIST: + case ZEND_FETCH_LIST_R: + case ZEND_FETCH_LIST_W: if (Z_TYPE_P(val) == IS_STRING) { zend_ulong index; if (ZEND_HANDLE_NUMERIC(Z_STR_P(val), index)) { @@ -571,6 +573,7 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, case ZEND_FETCH_DIM_RW: case ZEND_FETCH_DIM_FUNC_ARG: case ZEND_FETCH_DIM_UNSET: + case ZEND_FETCH_LIST_W: case ZEND_ASSIGN_DIM: case ZEND_SEPARATE: case ZEND_RETURN_BY_REF: @@ -593,15 +596,15 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array, break; /* In most cases IS_TMP_VAR operand may be used only once. * The operands are usually destroyed by the opcode handler. - * ZEND_CASE and ZEND_FETCH_LIST are exceptions, they keeps operand + * ZEND_CASE and ZEND_FETCH_LIST_R are exceptions, they keeps operand * unchanged, and allows its reuse. these instructions * usually terminated by ZEND_FREE that finally kills the value. */ - case ZEND_FETCH_LIST: { + case ZEND_FETCH_LIST_R: { zend_op *m = opline; do { - if (m->opcode == ZEND_FETCH_LIST && + if (m->opcode == ZEND_FETCH_LIST_R && m->op1_type == type && m->op1.var == var) { zval v; diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index 7eb1333eeff95..ebd03a3b12327 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -739,6 +739,7 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags, case ZEND_FETCH_OBJ_RW: case ZEND_FETCH_OBJ_FUNC_ARG: case ZEND_FETCH_OBJ_UNSET: + case ZEND_FETCH_LIST_W: if (opline->op1_type == IS_CV) { ssa_ops[k].op1_def = ssa_vars_count; var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count; From 196dd1db58f3fbf3d355b59843a9a7ae15e95fbf Mon Sep 17 00:00:00 2001 From: David Walker Date: Mon, 20 Nov 2017 08:32:02 -0700 Subject: [PATCH 02/11] Add check in assign-to-self branch --- Zend/zend_compile.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 42d90dff61db9..c7767ef1a66da 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3049,7 +3049,12 @@ void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */ znode cv_node; if (zend_try_compile_cv(&cv_node, expr_ast) == FAILURE) { - zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0); + if (zend_compile_list_assign_requires_w(var_ast)) { + zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_W, 0); + zend_emit_op(&expr_node, ZEND_MAKE_REF, &expr_node, NULL); + } else { + zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0); + } } else { zend_emit_op(&expr_node, ZEND_QM_ASSIGN, &cv_node, NULL); } From 3c72064f30bc7d43073820d96344a4df60ccb249 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 21 Nov 2017 17:51:35 +0100 Subject: [PATCH 03/11] Fix by-ref list self-assign * Don't generate MAKE_REF for CVs normally * But do generate it for self-assign CVs --- Zend/tests/list/list_reference_008.phpt | 16 +++++++++--- Zend/zend_compile.c | 34 ++++++++++++------------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/Zend/tests/list/list_reference_008.phpt b/Zend/tests/list/list_reference_008.phpt index dea63546d2d96..9c754a698d6cb 100644 --- a/Zend/tests/list/list_reference_008.phpt +++ b/Zend/tests/list/list_reference_008.phpt @@ -28,8 +28,11 @@ unset($a, $arr); * We do not allow references to the same variable of rhs. */ $a = [1, 2]; -list(&$a, $a) = $a; -var_dump($a); +$ref =& $a; +list(&$a, &$b) = $a; +var_dump($a, $b); +$a++; $b++; +var_dump($ref); ?> --EXPECTF-- int(1) @@ -55,6 +58,11 @@ array(2) { [1]=> int(2) } - -Notice: Attempting to set reference to non referenceable value in %s on line %d +int(1) int(2) +array(2) { + [0]=> + &int(2) + [1]=> + &int(3) +} diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index c7767ef1a66da..c8341fe1fcfc8 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3044,27 +3044,27 @@ void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */ zend_emit_op_data(&expr_node); return; case ZEND_AST_ARRAY: - if (zend_list_has_assign_to_self(var_ast, expr_ast)) { - /* list($a, $b) = $a should evaluate the right $a first */ - znode cv_node; + if (zend_compile_list_assign_requires_w(var_ast)) { + if (!zend_is_variable(expr_ast)) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot assign reference to non referencable value"); + } - if (zend_try_compile_cv(&cv_node, expr_ast) == FAILURE) { - if (zend_compile_list_assign_requires_w(var_ast)) { - zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_W, 0); - zend_emit_op(&expr_node, ZEND_MAKE_REF, &expr_node, NULL); - } else { - zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0); - } - } else { - zend_emit_op(&expr_node, ZEND_QM_ASSIGN, &cv_node, NULL); + zend_compile_var(&expr_node, expr_ast, BP_VAR_W); + /* MAKE_REF is usually not necessary for CVs. However, if there are + * self-assignments, this forces the RHS to evaluate first. */ + if (expr_node.op_type != IS_CV + || zend_list_has_assign_to_self(var_ast, expr_ast)) { + zend_emit_op(&expr_node, ZEND_MAKE_REF, &expr_node, NULL); } } else { - if (zend_compile_list_assign_requires_w(var_ast)) { - if (zend_is_variable(expr_ast)) { - zend_compile_var(&expr_node, expr_ast, BP_VAR_W); - zend_emit_op(&expr_node, ZEND_MAKE_REF, &expr_node, NULL); + if (zend_list_has_assign_to_self(var_ast, expr_ast)) { + /* list($a, $b) = $a should evaluate the right $a first */ + znode cv_node; + + if (zend_try_compile_cv(&cv_node, expr_ast) == FAILURE) { + zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0); } else { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot assign reference to non referencable value"); + zend_emit_op(&expr_node, ZEND_QM_ASSIGN, &cv_node, NULL); } } else { zend_compile_expr(&expr_node, expr_ast); From 28157db0560f0917ed13b58896427481380da2a7 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 21 Nov 2017 18:18:39 +0100 Subject: [PATCH 04/11] Handle FETCH_LIST_W in block pass --- ext/opcache/Optimizer/block_pass.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 8a9ce893cfce0..78b5176dd7801 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -411,6 +411,7 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array #endif case ZEND_FETCH_LIST_R: + case ZEND_FETCH_LIST_W: if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { /* LIST variable will be deleted later by FREE */ Tsource[VAR_NUM(opline->op1.var)] = NULL; From 32653a7b8eb662548b5da3bc242e7e55722958a3 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 21 Nov 2017 18:25:24 +0100 Subject: [PATCH 05/11] Handle MAKE_REF with CV operand in SSA --- ext/opcache/Optimizer/zend_inference.c | 7 +++++++ ext/opcache/Optimizer/zend_ssa.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index aebebb1f0c5f9..3320166656d96 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -3261,6 +3261,13 @@ static int zend_update_type_info(const zend_op_array *op_array, } } break; + case ZEND_MAKE_REF: + tmp = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; + UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + if (ssa_ops[i].op1_def >= 0) { + UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + } + break; case ZEND_CATCH: case ZEND_INCLUDE_OR_EVAL: /* Forbidden opcodes */ diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index ebd03a3b12327..b464e554397f6 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -685,7 +685,7 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags, case ZEND_SEND_REF: case ZEND_SEND_UNPACK: case ZEND_FE_RESET_RW: -//TODO: ??? + case ZEND_MAKE_REF: if (opline->op1_type == IS_CV) { ssa_ops[k].op1_def = ssa_vars_count; var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count; From 34f2d8804aa466d0b8df8d703535a782906077c4 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 21 Nov 2017 21:11:52 +0100 Subject: [PATCH 06/11] Simplify code a bit --- Zend/zend_compile.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index c8341fe1fcfc8..321d09955bc05 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2794,7 +2794,6 @@ static void zend_verify_list_assign_target(zend_ast *var_ast, zend_bool old_styl static inline void zend_emit_assign_ref_znode(zend_ast *var_ast, znode *value_node); static zend_bool zend_compile_list_assign_requires_w(zend_ast *ast) { /* {{{ */ - zend_bool require_w = 0; zend_ast_list *list; uint32_t i; @@ -2803,26 +2802,18 @@ static zend_bool zend_compile_list_assign_requires_w(zend_ast *ast) { /* {{{ */ } list = zend_ast_get_list(ast); - for (i = 0; i < list->children; ++i) { zend_ast *elem_ast = list->child[i]; if (elem_ast) { zend_ast *var_ast = elem_ast->child[0]; - - if (elem_ast->kind == ZEND_AST_ARRAY_ELEM && elem_ast->attr) { - require_w = 1; - } else if (elem_ast->kind == ZEND_AST_ARRAY_ELEM && var_ast->kind == ZEND_AST_ARRAY) { - require_w = zend_compile_list_assign_requires_w(var_ast); - } - - if (require_w) { - break; + if (elem_ast->attr || zend_compile_list_assign_requires_w(var_ast)) { + return 1; } } } - return require_w; + return 0; } /* }}} */ From 6c32740ded60b664cf492887c866304bf2e07a95 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 9 Dec 2017 12:26:17 +0100 Subject: [PATCH 07/11] LIST_W op1 cannot be TMP --- Zend/zend_vm_def.h | 4 +- Zend/zend_vm_execute.h | 226 ++++++++++++++++++++--------------------- Zend/zend_vm_opcodes.c | 2 +- 3 files changed, 116 insertions(+), 116 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index d42b7548f68c3..3507fc79ceb48 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2060,7 +2060,7 @@ ZEND_VM_HANDLER(98, ZEND_FETCH_LIST_R, CONST|TMPVAR|CV, CONST|TMPVAR|CV) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(198, ZEND_FETCH_LIST_W, TMPVAR|CV, CONST|TMPVAR|CV) +ZEND_VM_HANDLER(198, ZEND_FETCH_LIST_W, VAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -2071,7 +2071,7 @@ ZEND_VM_HANDLER(198, ZEND_FETCH_LIST_W, TMPVAR|CV, CONST|TMPVAR|CV) container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_W); dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + if (OP1_TYPE & IS_VAR) { if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { container = Z_INDIRECT_P(container); zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 5193a3e980ef7..a48a6f4899042 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -18598,6 +18598,34 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_VAR_CONST ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *retval, *container, *dim; + + SAVE_OPLINE(); + retval = EX_VAR(opline->result.var); + container = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); + dim = RT_CONSTANT(opline, opline->op2); + + if (IS_VAR & IS_VAR) { + if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { + container = Z_INDIRECT_P(container); + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } else if (UNEXPECTED(!Z_ISREF_P(container))) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_DATA_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -22902,6 +22930,34 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_VAR_CV_HA ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *retval, *container, *dim; + + SAVE_OPLINE(); + retval = EX_VAR(opline->result.var); + container = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); + dim = _get_zval_ptr_cv_undef(opline->op2.var EXECUTE_DATA_CC); + + if (IS_VAR & IS_VAR) { + if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { + container = Z_INDIRECT_P(container); + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } else if (UNEXPECTED(!Z_ISREF_P(container))) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -25504,6 +25560,35 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_UNSET_SPEC_VAR_TMPVA ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_VAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1, free_op2; + zval *retval, *container, *dim; + + SAVE_OPLINE(); + retval = EX_VAR(opline->result.var); + container = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); + dim = _get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC); + + if (IS_VAR & IS_VAR) { + if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { + container = Z_INDIRECT_P(container); + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } else if (UNEXPECTED(!Z_ISREF_P(container))) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + } else { + zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); + } + + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_DATA_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -36598,7 +36683,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_CV_CONST_HAN container = _get_zval_ptr_cv_undef(opline->op1.var EXECUTE_DATA_CC); dim = RT_CONSTANT(opline, opline->op2); - if (IS_CV & (IS_TMP_VAR|IS_VAR)) { + if (IS_CV & IS_VAR) { if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { container = Z_INDIRECT_P(container); zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); @@ -43101,7 +43186,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_CV_CV_HANDLE container = _get_zval_ptr_cv_undef(opline->op1.var EXECUTE_DATA_CC); dim = _get_zval_ptr_cv_undef(opline->op2.var EXECUTE_DATA_CC); - if (IS_CV & (IS_TMP_VAR|IS_VAR)) { + if (IS_CV & IS_VAR) { if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { container = Z_INDIRECT_P(container); zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); @@ -46828,7 +46913,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_CV_TMPVAR_HA container = _get_zval_ptr_cv_undef(opline->op1.var EXECUTE_DATA_CC); dim = _get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC); - if (IS_CV & (IS_TMP_VAR|IS_VAR)) { + if (IS_CV & IS_VAR) { if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { container = Z_INDIRECT_P(container); zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); @@ -50031,34 +50116,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_R_SPEC_TMPVAR_CONST ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_free_op free_op1; - zval *retval, *container, *dim; - - SAVE_OPLINE(); - retval = EX_VAR(opline->result.var); - container = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); - dim = RT_CONSTANT(opline, opline->op2); - - if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { - if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { - container = Z_INDIRECT_P(container); - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } else if (UNEXPECTED(!Z_ISREF_P(container))) { - zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); - zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); - } else { - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } - } else { - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } - - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -52444,34 +52501,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_R_SPEC_TMPVAR_CV_HA ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_free_op free_op1; - zval *retval, *container, *dim; - - SAVE_OPLINE(); - retval = EX_VAR(opline->result.var); - container = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); - dim = _get_zval_ptr_cv_undef(opline->op2.var EXECUTE_DATA_CC); - - if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { - if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { - container = Z_INDIRECT_P(container); - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } else if (UNEXPECTED(!Z_ISREF_P(container))) { - zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); - zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); - } else { - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } - } else { - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } - - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -53831,35 +53860,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_R_SPEC_TMPVAR_TMPVA ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_free_op free_op1, free_op2; - zval *retval, *container, *dim; - - SAVE_OPLINE(); - retval = EX_VAR(opline->result.var); - container = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); - dim = _get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC); - - if ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) { - if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { - container = Z_INDIRECT_P(container); - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } else if (UNEXPECTED(!Z_ISREF_P(container))) { - zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); - zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); - } else { - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } - } else { - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } - - zval_ptr_dtor_nogc(free_op2); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -59250,16 +59250,16 @@ ZEND_API void execute_ex(zend_execute_data *ex) (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, - (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_CONST_LABEL, - (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_LABEL, - (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_LABEL, (void*)&&ZEND_NULL_LABEL, - (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_CV_LABEL, - (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_CONST_LABEL, - (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_LABEL, - (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_LABEL, (void*)&&ZEND_NULL_LABEL, - (void*)&&ZEND_FETCH_LIST_W_SPEC_TMPVAR_CV_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_VAR_CONST_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_VAR_TMPVAR_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_VAR_TMPVAR_LABEL, + (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_FETCH_LIST_W_SPEC_VAR_CV_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, @@ -61585,6 +61585,9 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_FETCH_OBJ_UNSET_SPEC_VAR_CONST): ZEND_FETCH_OBJ_UNSET_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_FETCH_LIST_W_SPEC_VAR_CONST): + ZEND_FETCH_LIST_W_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_DATA_CONST): ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_DATA_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); @@ -61912,6 +61915,9 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_FETCH_OBJ_UNSET_SPEC_VAR_CV): ZEND_FETCH_OBJ_UNSET_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_FETCH_LIST_W_SPEC_VAR_CV): + ZEND_FETCH_LIST_W_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA_CONST): ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); @@ -62116,6 +62122,9 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_FETCH_OBJ_UNSET_SPEC_VAR_TMPVAR): ZEND_FETCH_OBJ_UNSET_SPEC_VAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_FETCH_LIST_W_SPEC_VAR_TMPVAR): + ZEND_FETCH_LIST_W_SPEC_VAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_DATA_CONST): ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_DATA_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); @@ -63823,9 +63832,6 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_FETCH_LIST_R_SPEC_TMPVAR_CONST): ZEND_FETCH_LIST_R_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); - HYBRID_CASE(ZEND_FETCH_LIST_W_SPEC_TMPVAR_CONST): - ZEND_FETCH_LIST_W_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - HYBRID_BREAK(); HYBRID_CASE(ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST): ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); @@ -64003,9 +64009,6 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_FETCH_LIST_R_SPEC_TMPVAR_CV): ZEND_FETCH_LIST_R_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); - HYBRID_CASE(ZEND_FETCH_LIST_W_SPEC_TMPVAR_CV): - ZEND_FETCH_LIST_W_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - HYBRID_BREAK(); HYBRID_CASE(ZEND_FAST_CONCAT_SPEC_TMPVAR_CV): ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); @@ -64090,9 +64093,6 @@ ZEND_API void execute_ex(zend_execute_data *ex) HYBRID_CASE(ZEND_FETCH_LIST_R_SPEC_TMPVAR_TMPVAR): ZEND_FETCH_LIST_R_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); - HYBRID_CASE(ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR): - ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - HYBRID_BREAK(); HYBRID_CASE(ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR): ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); @@ -68283,16 +68283,16 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_FETCH_LIST_W_SPEC_TMPVAR_CONST_HANDLER, - ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_HANDLER, - ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_FETCH_LIST_W_SPEC_TMPVAR_CV_HANDLER, - ZEND_FETCH_LIST_W_SPEC_TMPVAR_CONST_HANDLER, - ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_HANDLER, - ZEND_FETCH_LIST_W_SPEC_TMPVAR_TMPVAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_FETCH_LIST_W_SPEC_TMPVAR_CV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_FETCH_LIST_W_SPEC_VAR_CONST_HANDLER, + ZEND_FETCH_LIST_W_SPEC_VAR_TMPVAR_HANDLER, + ZEND_FETCH_LIST_W_SPEC_VAR_TMPVAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_FETCH_LIST_W_SPEC_VAR_CV_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index f60dec7345ee7..2fb9fd589399a 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -422,7 +422,7 @@ static uint32_t zend_vm_opcodes_flags[199] = { 0x00000103, 0x00000101, 0x00020101, - 0x00000705, + 0x00000701, }; ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) { From 113fbbeaa1a459264204a0c02e7982aad90de99a Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 9 Dec 2017 12:31:21 +0100 Subject: [PATCH 08/11] Simplify LIST_W implementation --- Zend/zend_vm_def.h | 18 +++---- Zend/zend_vm_execute.h | 108 ++++++++++++++++------------------------- 2 files changed, 49 insertions(+), 77 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 3507fc79ceb48..986d069147272 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2068,19 +2068,15 @@ ZEND_VM_HANDLER(198, ZEND_FETCH_LIST_W, VAR|CV, CONST|TMPVAR|CV) SAVE_OPLINE(); retval = EX_VAR(opline->result.var); - container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_W); + container = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - if (OP1_TYPE & IS_VAR) { - if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { - container = Z_INDIRECT_P(container); - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } else if (UNEXPECTED(!Z_ISREF_P(container))) { - zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); - zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); - } else { - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } + if (OP1_TYPE == IS_VAR + && Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT + && UNEXPECTED(!Z_ISREF_P(container)) + ) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); } else { zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index a48a6f4899042..b90618a8ae97d 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -18606,19 +18606,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_VAR_CONST_HA SAVE_OPLINE(); retval = EX_VAR(opline->result.var); - container = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); + container = _get_zval_ptr_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); dim = RT_CONSTANT(opline, opline->op2); - if (IS_VAR & IS_VAR) { - if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { - container = Z_INDIRECT_P(container); - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } else if (UNEXPECTED(!Z_ISREF_P(container))) { - zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); - zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); - } else { - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } + if (IS_VAR == IS_VAR + && Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT + && UNEXPECTED(!Z_ISREF_P(container)) + ) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); } else { zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); } @@ -22938,19 +22934,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_VAR_CV_HANDL SAVE_OPLINE(); retval = EX_VAR(opline->result.var); - container = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); + container = _get_zval_ptr_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); dim = _get_zval_ptr_cv_undef(opline->op2.var EXECUTE_DATA_CC); - if (IS_VAR & IS_VAR) { - if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { - container = Z_INDIRECT_P(container); - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } else if (UNEXPECTED(!Z_ISREF_P(container))) { - zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); - zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); - } else { - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } + if (IS_VAR == IS_VAR + && Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT + && UNEXPECTED(!Z_ISREF_P(container)) + ) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); } else { zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); } @@ -25568,19 +25560,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_VAR_TMPVAR_H SAVE_OPLINE(); retval = EX_VAR(opline->result.var); - container = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); + container = _get_zval_ptr_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC); dim = _get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC); - if (IS_VAR & IS_VAR) { - if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { - container = Z_INDIRECT_P(container); - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } else if (UNEXPECTED(!Z_ISREF_P(container))) { - zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); - zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); - } else { - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } + if (IS_VAR == IS_VAR + && Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT + && UNEXPECTED(!Z_ISREF_P(container)) + ) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); } else { zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); } @@ -36680,19 +36668,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_CV_CONST_HAN SAVE_OPLINE(); retval = EX_VAR(opline->result.var); - container = _get_zval_ptr_cv_undef(opline->op1.var EXECUTE_DATA_CC); + container = _get_zval_ptr_cv_undef_BP_VAR_W(opline->op1.var EXECUTE_DATA_CC); dim = RT_CONSTANT(opline, opline->op2); - if (IS_CV & IS_VAR) { - if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { - container = Z_INDIRECT_P(container); - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } else if (UNEXPECTED(!Z_ISREF_P(container))) { - zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); - zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); - } else { - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } + if (IS_CV == IS_VAR + && Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT + && UNEXPECTED(!Z_ISREF_P(container)) + ) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); } else { zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); } @@ -43183,19 +43167,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_CV_CV_HANDLE SAVE_OPLINE(); retval = EX_VAR(opline->result.var); - container = _get_zval_ptr_cv_undef(opline->op1.var EXECUTE_DATA_CC); + container = _get_zval_ptr_cv_undef_BP_VAR_W(opline->op1.var EXECUTE_DATA_CC); dim = _get_zval_ptr_cv_undef(opline->op2.var EXECUTE_DATA_CC); - if (IS_CV & IS_VAR) { - if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { - container = Z_INDIRECT_P(container); - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } else if (UNEXPECTED(!Z_ISREF_P(container))) { - zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); - zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); - } else { - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } + if (IS_CV == IS_VAR + && Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT + && UNEXPECTED(!Z_ISREF_P(container)) + ) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); } else { zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); } @@ -46910,19 +46890,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_W_SPEC_CV_TMPVAR_HA SAVE_OPLINE(); retval = EX_VAR(opline->result.var); - container = _get_zval_ptr_cv_undef(opline->op1.var EXECUTE_DATA_CC); + container = _get_zval_ptr_cv_undef_BP_VAR_W(opline->op1.var EXECUTE_DATA_CC); dim = _get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC); - if (IS_CV & IS_VAR) { - if (Z_TYPE_P(EX_VAR(opline->op1.var)) == IS_INDIRECT) { - container = Z_INDIRECT_P(container); - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } else if (UNEXPECTED(!Z_ISREF_P(container))) { - zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); - zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); - } else { - zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); - } + if (IS_CV == IS_VAR + && Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT + && UNEXPECTED(!Z_ISREF_P(container)) + ) { + zend_error(E_NOTICE, "Attempting to set reference to non referenceable value"); + zend_fetch_dimension_address_LIST_r(retval, container, dim EXECUTE_DATA_CC); } else { zend_fetch_dimension_address_LIST_w(retval, container, dim EXECUTE_DATA_CC); } From a4f654614afbc5a2640d2f7a59c7ceac1bc0aa95 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 9 Dec 2017 12:44:30 +0100 Subject: [PATCH 09/11] Avoid unnecessary MAKE_REF when assigning to CV Let assign_ref handle the MAKE_REF emission. Only explicitly emit the MAKE_REF if it's for a (non-leaf) list() assignment. --- Zend/zend_compile.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 321d09955bc05..f1bcfd85042f6 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2873,14 +2873,15 @@ static void zend_compile_list_assign( if (elem_ast->attr || zend_compile_list_assign_requires_w(var_ast)) { zend_emit_op(&fetch_result, ZEND_FETCH_LIST_W, expr_node, &dim_node); - zend_emit_op(&fetch_result, ZEND_MAKE_REF, &fetch_result, NULL); - } else { - zend_emit_op(&fetch_result, ZEND_FETCH_LIST_R, expr_node, &dim_node); - } - if (elem_ast->attr) { - zend_emit_assign_ref_znode(var_ast, &fetch_result); + if (elem_ast->attr) { + zend_emit_assign_ref_znode(var_ast, &fetch_result); + } else { + zend_emit_op(&fetch_result, ZEND_MAKE_REF, &fetch_result, NULL); + zend_emit_assign_znode(var_ast, &fetch_result); + } } else { + zend_emit_op(&fetch_result, ZEND_FETCH_LIST_R, expr_node, &dim_node); zend_emit_assign_znode(var_ast, &fetch_result); } } From 548ede944ce247db8c4784eb49dedf0f4d64a80c Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 9 Dec 2017 13:00:52 +0100 Subject: [PATCH 10/11] Propagate list() refness only once Rather than recomputing it on every access, propagate only once and store it in elem_ast->attr, consistently with direct references. --- Zend/zend_compile.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index f1bcfd85042f6..0bc52d3f9eb52 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2793,27 +2793,25 @@ static void zend_verify_list_assign_target(zend_ast *var_ast, zend_bool old_styl static inline void zend_emit_assign_ref_znode(zend_ast *var_ast, znode *value_node); -static zend_bool zend_compile_list_assign_requires_w(zend_ast *ast) { /* {{{ */ - zend_ast_list *list; +/* Propagate refs used on leaf elements to the surrounding list() structures. */ +static zend_bool zend_propagate_list_refs(zend_ast *ast) { /* {{{ */ + zend_ast_list *list = zend_ast_get_list(ast); + zend_bool has_refs = 0; uint32_t i; - if (ast->kind != ZEND_AST_ARRAY) { - return 0; - } - - list = zend_ast_get_list(ast); for (i = 0; i < list->children; ++i) { zend_ast *elem_ast = list->child[i]; if (elem_ast) { zend_ast *var_ast = elem_ast->child[0]; - if (elem_ast->attr || zend_compile_list_assign_requires_w(var_ast)) { - return 1; + if (var_ast->kind == ZEND_AST_ARRAY) { + elem_ast->attr = zend_propagate_list_refs(var_ast); } + has_refs |= elem_ast->attr; } } - return 0; + return has_refs; } /* }}} */ @@ -2871,14 +2869,14 @@ static void zend_compile_list_assign( zend_verify_list_assign_target(var_ast, old_style); - if (elem_ast->attr || zend_compile_list_assign_requires_w(var_ast)) { + if (elem_ast->attr) { zend_emit_op(&fetch_result, ZEND_FETCH_LIST_W, expr_node, &dim_node); - if (elem_ast->attr) { - zend_emit_assign_ref_znode(var_ast, &fetch_result); - } else { + if (var_ast->kind == ZEND_AST_ARRAY) { zend_emit_op(&fetch_result, ZEND_MAKE_REF, &fetch_result, NULL); zend_emit_assign_znode(var_ast, &fetch_result); + } else { + zend_emit_assign_ref_znode(var_ast, &fetch_result); } } else { zend_emit_op(&fetch_result, ZEND_FETCH_LIST_R, expr_node, &dim_node); @@ -3036,9 +3034,10 @@ void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */ zend_emit_op_data(&expr_node); return; case ZEND_AST_ARRAY: - if (zend_compile_list_assign_requires_w(var_ast)) { + if (zend_propagate_list_refs(var_ast)) { if (!zend_is_variable(expr_ast)) { - zend_error_noreturn(E_COMPILE_ERROR, "Cannot assign reference to non referencable value"); + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot assign reference to non referencable value"); } zend_compile_var(&expr_node, expr_ast, BP_VAR_W); @@ -4797,7 +4796,7 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ value_ast = value_ast->child[0]; } - if (value_ast->kind == ZEND_AST_ARRAY && zend_compile_list_assign_requires_w(value_ast)) { + if (value_ast->kind == ZEND_AST_ARRAY && zend_propagate_list_refs(value_ast)) { list_ref = 1; } From 45da2f1795bcf4ef18c396328ede6888aca3eabc Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 9 Dec 2017 13:20:58 +0100 Subject: [PATCH 11/11] Make list() handling more explicit Make all compile_list_assign() calls explicit, instead of automatically calling it from assign_znode(). I did not like the asymmetry between assign_znode() and assign_ref_znode() here. --- Zend/zend_compile.c | 46 ++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0bc52d3f9eb52..c321932092ec3 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2654,18 +2654,13 @@ 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_compile_assign(znode *result, zend_ast *ast); -static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_node, zend_bool old_style); static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node) /* {{{ */ { znode dummy_node; - if (var_ast->kind == ZEND_AST_ARRAY) { - zend_compile_list_assign(&dummy_node, var_ast, value_node, var_ast->attr); - } else { - zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN, var_ast, - zend_ast_create_znode(value_node)); - zend_compile_assign(&dummy_node, assign_ast); - } + zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN, var_ast, + zend_ast_create_znode(value_node)); + zend_compile_assign(&dummy_node, assign_ast); zend_do_free(&dummy_node); } /* }}} */ @@ -2869,17 +2864,17 @@ static void zend_compile_list_assign( zend_verify_list_assign_target(var_ast, old_style); - if (elem_ast->attr) { - zend_emit_op(&fetch_result, ZEND_FETCH_LIST_W, expr_node, &dim_node); + zend_emit_op(&fetch_result, + elem_ast->attr ? ZEND_FETCH_LIST_W : ZEND_FETCH_LIST_R, expr_node, &dim_node); - if (var_ast->kind == ZEND_AST_ARRAY) { + if (var_ast->kind == ZEND_AST_ARRAY) { + if (elem_ast->attr) { zend_emit_op(&fetch_result, ZEND_MAKE_REF, &fetch_result, NULL); - zend_emit_assign_znode(var_ast, &fetch_result); - } else { - zend_emit_assign_ref_znode(var_ast, &fetch_result); } + zend_compile_list_assign(NULL, var_ast, &fetch_result, var_ast->attr); + } else if (elem_ast->attr) { + zend_emit_assign_ref_znode(var_ast, &fetch_result); } else { - zend_emit_op(&fetch_result, ZEND_FETCH_LIST_R, expr_node, &dim_node); zend_emit_assign_znode(var_ast, &fetch_result); } } @@ -2888,7 +2883,11 @@ static void zend_compile_list_assign( zend_error_noreturn(E_COMPILE_ERROR, "Cannot use empty list"); } - *result = *expr_node; + if (result) { + *result = *expr_node; + } else { + zend_do_free(expr_node); + } } /* }}} */ @@ -4775,7 +4774,6 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ zend_ast *key_ast = ast->child[2]; zend_ast *stmt_ast = ast->child[3]; zend_bool by_ref = value_ast->kind == ZEND_AST_REF; - zend_bool list_ref = 0; zend_bool is_variable = zend_is_variable(expr_ast) && !zend_is_call(expr_ast) && zend_can_write_to_variable(expr_ast); @@ -4797,26 +4795,26 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ } if (value_ast->kind == ZEND_AST_ARRAY && zend_propagate_list_refs(value_ast)) { - list_ref = 1; + by_ref = 1; } - if ((by_ref || list_ref) && is_variable) { + if (by_ref && is_variable) { zend_compile_var(&expr_node, expr_ast, BP_VAR_W); } else { zend_compile_expr(&expr_node, expr_ast); } - if (by_ref || list_ref) { + if (by_ref) { zend_separate_if_call_and_write(&expr_node, expr_ast, BP_VAR_W); } opnum_reset = get_next_op_number(CG(active_op_array)); - opline = zend_emit_op(&reset_node, (by_ref || list_ref) ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL); + opline = zend_emit_op(&reset_node, by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL); zend_begin_loop(ZEND_FE_FREE, &reset_node); opnum_fetch = get_next_op_number(CG(active_op_array)); - opline = zend_emit_op(NULL, (by_ref || list_ref) ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL); + opline = zend_emit_op(NULL, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL); if (is_this_fetch(value_ast)) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this"); @@ -4827,7 +4825,9 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ opline->op2_type = IS_VAR; opline->op2.var = get_temporary_variable(CG(active_op_array)); GET_NODE(&value_node, opline->op2); - if (by_ref) { + if (value_ast->kind == ZEND_AST_ARRAY) { + zend_compile_list_assign(NULL, value_ast, &value_node, value_ast->attr); + } else if (by_ref) { zend_emit_assign_ref_znode(value_ast, &value_node); } else { zend_emit_assign_znode(value_ast, &value_node);