From 37c8bb58686b2d86f145ebe4fe39854f5951dcd7 Mon Sep 17 00:00:00 2001 From: Andrea Faulds Date: Fri, 25 Mar 2016 17:18:42 +0000 Subject: [PATCH] Allow specifying keys on list() elements Squashed commit of the following: commit 0361dbe35616722fbe51b446ab7b43a9ca01f455 Author: Andrea Faulds Date: Fri Mar 25 16:59:20 2016 +0000 UPGRADING and NEWS commit dca9d4a36c845bfe4fbcb9db18e184469110ea5a Author: Andrea Faulds Date: Fri Mar 25 16:45:18 2016 +0000 Add tests contributed by @jesseschalken commit e557f77eab692ed8bb18dbdff48777d80b6f6cbd Author: Andrea Faulds Date: Fri Mar 25 16:44:51 2016 +0000 Rebuild VM commit 70942e4c3cbb6b4fe6305b27e1e1b2bed78e76df Author: Andrea Faulds Date: Wed Feb 24 13:12:26 2016 +0000 Add test for evaluation order of nested list() keys commit ed3592e80c5231d9e9a95558aa768a42b75bdebc Author: Andrea Faulds Date: Wed Feb 24 12:42:04 2016 +0000 Add test for evaluation order commit 589756cbcccbb4702c90b5aa9c091af446058ca1 Author: Andrea Faulds Date: Tue Jan 19 17:29:34 2016 +0000 Allow arbitrary expressions for key commit 3f622077c32fcd82fcf27a41bd0f22e2552ec4c5 Author: Andrea Faulds Date: Tue Jan 19 17:45:10 2016 +0000 Remove compile-time HANDLE_NUMERIC (see bug #63217) commit bab758119aec63289a2c5bef6a5f90a7bc6441a2 Author: Andrea Faulds Date: Sun Jan 17 01:20:26 2016 +0000 Handle numeric strings commit 14bfe93ddc34d1175bccb42a158be8842c472a9c Author: Andrea Faulds Date: Sun Jan 17 01:09:36 2016 +0000 Allow trailing comma commit f4c8b2cb30fc074b15b5f7aabef5444382403b5d Author: Andrea Faulds Date: Sat Jan 16 23:47:11 2016 +0000 Add tests commit 0085884a6176c3a981b53131fbb4fa0c44db2670 Author: Andrea Faulds Date: Sat Jan 16 22:24:23 2016 +0000 Handle non-integer/string opcodes commit e572d2d0ada6a64b36a2c6f5e8cb57439f51b55e Author: Andrea Faulds Date: Sat Jan 16 21:10:33 2016 +0000 Disallow mixing keyed and unkeyed list() elements commit cede13ccfe0c486591fa84764271ac1b8cb90d0b Author: Andrea Faulds Date: Sun Jan 10 20:46:44 2016 +0000 list() with keys (no foreach or tests) --- NEWS | 1 + UPGRADING | 2 + Zend/tests/foreach_list_keyed.phpt | 36 + Zend/tests/list_keyed.phpt | 71 ++ Zend/tests/list_keyed_ArrayAccess.phpt | 54 ++ Zend/tests/list_keyed_conversions.phpt | 32 + Zend/tests/list_keyed_evaluation_order.inc | 60 ++ Zend/tests/list_keyed_evaluation_order.phpt | 35 + Zend/tests/list_keyed_evaluation_order_2.phpt | 77 ++ Zend/tests/list_keyed_evaluation_order_3.phpt | 24 + .../list_keyed_evaluation_order_nested.phpt | 77 ++ Zend/tests/list_keyed_non_literals.phpt | 30 + Zend/tests/list_keyed_trailing_comma.phpt | 38 + Zend/tests/list_keyed_undefined.phpt | 22 + Zend/tests/list_mixed_keyed_unkeyed.phpt | 16 + .../list_mixed_nested_keyed_unkeyed.phpt | 34 + Zend/zend_compile.c | 37 +- Zend/zend_language_parser.y | 33 +- Zend/zend_vm_def.h | 65 +- Zend/zend_vm_execute.h | 783 +++++++++++++++++- Zend/zend_vm_opcodes.c | 2 +- 21 files changed, 1484 insertions(+), 45 deletions(-) create mode 100644 Zend/tests/foreach_list_keyed.phpt create mode 100644 Zend/tests/list_keyed.phpt create mode 100644 Zend/tests/list_keyed_ArrayAccess.phpt create mode 100644 Zend/tests/list_keyed_conversions.phpt create mode 100644 Zend/tests/list_keyed_evaluation_order.inc create mode 100644 Zend/tests/list_keyed_evaluation_order.phpt create mode 100644 Zend/tests/list_keyed_evaluation_order_2.phpt create mode 100644 Zend/tests/list_keyed_evaluation_order_3.phpt create mode 100644 Zend/tests/list_keyed_evaluation_order_nested.phpt create mode 100644 Zend/tests/list_keyed_non_literals.phpt create mode 100644 Zend/tests/list_keyed_trailing_comma.phpt create mode 100644 Zend/tests/list_keyed_undefined.phpt create mode 100644 Zend/tests/list_mixed_keyed_unkeyed.phpt create mode 100644 Zend/tests/list_mixed_nested_keyed_unkeyed.phpt diff --git a/NEWS b/NEWS index fe4640391560e..604cf485dd7a3 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,7 @@ PHP NEWS . Added void return type. (Andrea) . Added support for negative string offsets in string offset syntax and various string functions. (Francois) + . Added a form of the list() construct where keys can be specified. (Andrea) - FTP: . Implemented FR #55651 (Option to ignore the returned FTP PASV address). diff --git a/UPGRADING b/UPGRADING index fc23e3676f10a..a938978d7bf7f 100644 --- a/UPGRADING +++ b/UPGRADING @@ -35,6 +35,8 @@ PHP 7.1 UPGRADE NOTES . String offset access now supports negative references, which will be counted from the end of the string. (RFC: https://wiki.php.net/rfc/negative-string-offsets) + . Added a form of the list() construct where keys can be specified. + (RFC: https://wiki.php.net/rfc/list_keys) ======================================== 3. Changes in SAPI modules diff --git a/Zend/tests/foreach_list_keyed.phpt b/Zend/tests/foreach_list_keyed.phpt new file mode 100644 index 0000000000000..f5fab4e342e75 --- /dev/null +++ b/Zend/tests/foreach_list_keyed.phpt @@ -0,0 +1,36 @@ +--TEST-- +foreach with list syntax, keyed +--FILE-- + 1, "y" => 2], + ["x" => 2, "y" => 1] +]; + +foreach ($points as list("x" => $x, "y" => $y)) { + var_dump($x, $y); +} + +echo PHP_EOL; + +$invertedPoints = [ + "x" => [1, 2], + "y" => [2, 1] +]; + +foreach ($invertedPoints as list(0 => $row1, 1 => $row2)) { + var_dump($row1, $row2); +} + +?> +--EXPECT-- +int(1) +int(2) +int(2) +int(1) + +int(1) +int(2) +int(2) +int(1) diff --git a/Zend/tests/list_keyed.phpt b/Zend/tests/list_keyed.phpt new file mode 100644 index 0000000000000..b549ed9bf5018 --- /dev/null +++ b/Zend/tests/list_keyed.phpt @@ -0,0 +1,71 @@ +--TEST-- +list() with keys +--FILE-- + "bad", + "happy" => "sad", +]; + +list("good" => $good_antonym, "happy" => $happy_antonym) = $antonyms; +var_dump($good_antonym, $happy_antonym); + +echo PHP_EOL; + +$powersOfTwo = [ + 1 => 2, + 2 => 4, + 3 => 8 +]; + +list(1 => $two_1, 2 => $two_2, 3 => $two_3) = $powersOfTwo; +var_dump($two_1, $two_2, $two_3); + +echo PHP_EOL; + +$contrivedMixedKeyTypesExample = [ + 7 => "the best PHP version", + "elePHPant" => "the cutest mascot" +]; + +list(7 => $seven, "elePHPant" => $elePHPant) = $contrivedMixedKeyTypesExample; +var_dump($seven, $elePHPant); + +echo PHP_EOL; + +$allTogetherNow = [ + "antonyms" => $antonyms, + "powersOfTwo" => $powersOfTwo, + "contrivedMixedKeyTypesExample" => $contrivedMixedKeyTypesExample +]; + +list( + "antonyms" => list("good" => $good_antonym, "happy" => $happy_antonym), + "powersOfTwo" => list(1 => $two_1, 2 => $two_2, 3 => $two_3), + "contrivedMixedKeyTypesExample" => list(7 => $seven, "elePHPant" => $elePHPant) +) = $allTogetherNow; + +var_dump($good_antonym, $happy_antonym); +var_dump($two_1, $two_2, $two_3); +var_dump($seven, $elePHPant); + +?> +--EXPECT-- +string(3) "bad" +string(3) "sad" + +int(2) +int(4) +int(8) + +string(20) "the best PHP version" +string(17) "the cutest mascot" + +string(3) "bad" +string(3) "sad" +int(2) +int(4) +int(8) +string(20) "the best PHP version" +string(17) "the cutest mascot" diff --git a/Zend/tests/list_keyed_ArrayAccess.phpt b/Zend/tests/list_keyed_ArrayAccess.phpt new file mode 100644 index 0000000000000..1bb20130365d0 --- /dev/null +++ b/Zend/tests/list_keyed_ArrayAccess.phpt @@ -0,0 +1,54 @@ +--TEST-- +list() with keys and ArrayAccess +--FILE-- + $good, "happy" => $happy) = $antonymObject; +var_dump($good, $happy); + +echo PHP_EOL; + +$stdClassCollection = new SplObjectStorage; +$foo = new StdClass; +$stdClassCollection[$foo] = "foo"; +$bar = new StdClass; +$stdClassCollection[$bar] = "bar"; + +list($foo => $fooStr, $bar => $barStr) = $stdClassCollection; +var_dump($fooStr, $barStr); + +echo PHP_EOL; + +class IndexPrinter implements ArrayAccess +{ + public function offsetGet($offset) { + echo "GET "; + var_dump($offset); + } + public function offsetSet($offset, $value) { + } + public function offsetExists($offset) { + } + public function offsetUnset($offset) { + } +} + +$op = new IndexPrinter; +list(123 => $x) = $op; +// PHP shouldn't convert this to an integer offset, because it's ArrayAccess +list("123" => $x) = $op; + +?> +--EXPECT-- +string(3) "bad" +string(3) "sad" + +string(3) "foo" +string(3) "bar" + +GET int(123) +GET string(3) "123" diff --git a/Zend/tests/list_keyed_conversions.phpt b/Zend/tests/list_keyed_conversions.phpt new file mode 100644 index 0000000000000..e2cf91a27d2de --- /dev/null +++ b/Zend/tests/list_keyed_conversions.phpt @@ -0,0 +1,32 @@ +--TEST-- +list() with non-integer-or-string keys +--FILE-- + 0, + 1 => 1, + "" => "" +]; + +list(NULL => $NULL, 1.5 => $float, FALSE => $FALSE, TRUE => $TRUE) = $results; +var_dump($NULL, $float, $FALSE, $TRUE); + +echo PHP_EOL; + +list("0" => $zeroString, "1" => $oneString) = $results; +var_dump($zeroString, $oneString); + +list(STDIN => $resource) = []; + +?> +--EXPECTF-- +string(0) "" +int(1) +int(0) +int(1) + +int(0) +int(1) + +Notice: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d diff --git a/Zend/tests/list_keyed_evaluation_order.inc b/Zend/tests/list_keyed_evaluation_order.inc new file mode 100644 index 0000000000000..490a6d84fe97b --- /dev/null +++ b/Zend/tests/list_keyed_evaluation_order.inc @@ -0,0 +1,60 @@ +name = $name; + } + + public function __toString(): string { + echo "$this->name evaluated.", PHP_EOL; + return $this->name; + } +} + +class Indexable implements ArrayAccess +{ + private $array; + public function __construct(array $array) { + $this->array = $array; + } + + public function offsetExists($offset): bool { + echo "Existence of offset $offset checked for.", PHP_EOL; + return isset($this->array[$offset]); + } + + public function offsetUnset($offset): void { + unset($this->array[$offset]); + echo "Offset $offset removed.", PHP_EOL; + } + + public function offsetGet($offset) { + echo "Offset $offset retrieved.", PHP_EOL; + return $this->array[$offset]; + } + + public function offsetSet($offset, $value): void { + $this->array[$offset] = $value; + echo "Offset $offset set to $value.", PHP_EOL; + } +} + +class IndexableRetrievable +{ + private $label; + private $indexable; + + public function __construct(string $label, Indexable $indexable) { + $this->label = $label; + $this->indexable = $indexable; + } + + public function getIndexable(): Indexable { + echo "Indexable $this->label retrieved.", PHP_EOL; + return $this->indexable; + } +} diff --git a/Zend/tests/list_keyed_evaluation_order.phpt b/Zend/tests/list_keyed_evaluation_order.phpt new file mode 100644 index 0000000000000..0f0652b6a9b43 --- /dev/null +++ b/Zend/tests/list_keyed_evaluation_order.phpt @@ -0,0 +1,35 @@ +--TEST-- +list() with keys, evaluation order +--FILE-- + "value for offset A", "C" => "value for offset C"])); + +$store = new Indexable([]); + +// list($a => $b, $c => $d) = $e; +// Should be evaluated in the order: +// 1. Evaluate $e +// 2. Evaluate $a +// 3. Evaluate $e[$a] +// 4. Assign $b from $e[$a] +// 5. Evaluate $c +// 6. Evaluate $e[$c] +// 7. Assign $c from $e[$a] + +list((string)$a => $store["B"], (string)$c => $store["D"]) = $e->getIndexable(); + +?> +--EXPECT-- +Indexable E retrieved. +A evaluated. +Offset A retrieved. +Offset B set to value for offset A. +C evaluated. +Offset C retrieved. +Offset D set to value for offset C. diff --git a/Zend/tests/list_keyed_evaluation_order_2.phpt b/Zend/tests/list_keyed_evaluation_order_2.phpt new file mode 100644 index 0000000000000..ddfba68c464de --- /dev/null +++ b/Zend/tests/list_keyed_evaluation_order_2.phpt @@ -0,0 +1,77 @@ +--TEST-- +list() with keys, evaluation order #2 +--FILE-- + $a, 1 => $b) = ['a', 'b']; +var_dump($a); +var_dump($b); + +list(1 => $b, 0 => $a) = ['a', 'b']; +var_dump($a); +var_dump($b); + +$arr = []; +list($arr[], $arr[]) = ['a', 'b']; +var_dump($arr[0]); +var_dump($arr[1]); + +$arr = []; +list(0 => $arr[], 1 => $arr[]) = ['a', 'b']; +var_dump($arr[0]); +var_dump($arr[1]); + +$arr = []; +list(1 => $arr[], 0 => $arr[]) = ['b', 'a']; +var_dump($arr[0]); +var_dump($arr[1]); + +$arr = []; +list(list(1 => $arr[], 0 => $arr[])) = [['b', 'a']]; +var_dump($arr[0]); +var_dump($arr[1]); + +$arr = []; +list('key1' => $arr[], 'key2' => $arr[]) = ['key2' => 'b', 'key1' => 'a']; +var_dump($arr[0]); +var_dump($arr[1]); + +// This should print 'foo' +$a = 0; +list($a => $a) = ['foo', 'bar']; +var_dump($a); + +// This should print 'bar' then 'foo' +$a = 0; +$b = 1; +list($b => $a, $a => $c) = ['bar' => 'foo', 1 => 'bar']; +var_dump($a); +var_dump($c); + +?> +--EXPECT-- +string(1) "a" +string(1) "b" +string(1) "a" +string(1) "b" +string(1) "a" +string(1) "b" +string(1) "a" +string(1) "b" +string(1) "a" +string(1) "b" +string(1) "a" +string(1) "b" +string(1) "a" +string(1) "b" +string(1) "a" +string(1) "b" +string(3) "foo" +string(3) "bar" +string(3) "foo" diff --git a/Zend/tests/list_keyed_evaluation_order_3.phpt b/Zend/tests/list_keyed_evaluation_order_3.phpt new file mode 100644 index 0000000000000..7850834c3b2b0 --- /dev/null +++ b/Zend/tests/list_keyed_evaluation_order_3.phpt @@ -0,0 +1,24 @@ +--TEST-- +list() with keys, evaluation order #3 +--FILE-- + [ + 'b' => 'bar', + 'a' => 'foo', + ], + 1 => 'a', + 3 => 'b', +]; +list($a[$i++] => $a[$i++], $a[$i++] => $a[$i++]) = $a[$i++]; +var_dump($i); // should be 5 +var_dump($a[2]); // should be 'foo' +var_dump($a[4]); // should be 'bar' + +?> +--EXPECT-- +int(5) +string(3) "foo" +string(3) "bar" diff --git a/Zend/tests/list_keyed_evaluation_order_nested.phpt b/Zend/tests/list_keyed_evaluation_order_nested.phpt new file mode 100644 index 0000000000000..8a7725d4eaaae --- /dev/null +++ b/Zend/tests/list_keyed_evaluation_order_nested.phpt @@ -0,0 +1,77 @@ +--TEST-- +list() with keys, evaluation order: nested +--FILE-- + "offset value for A", + "C" => new Indexable([ + 0 => "offset value for 0", + 1 => "offset value for 1" + ]), + "F" => new Indexable([ + "G" => "offset value for G", + "I" => "offset value for I" + ]) +])); + +$store = new Indexable([]); + +// list($a => $b, $c => list($d, $e), $f => list($g => $h, $i => $j)) = $k; +// Should be evaluated in the order: +// 1. Evaluate $k +// 2. Evaluate $a +// 3. Evaluate $k[$a] +// 4. Assign $b from $k[$a] +// 5. Evaluate $c +// 6. Evaluate $k[$c] +// 7. Evaluate $k[$c][0] +// 8. Assign $d from $k[$c][0] +// 9. Evaluate $k[$c][1] +// 10. Assign $e from $k[$c][1] +// 11. Evaluate $f +// 12. Evaluate $k[$f] +// 13. Evaluate $g +// 14. Evaluate $k[$f][$g] +// 15. Assign $h from $k[$f][$g] +// 16. Evaluate $i +// 17. Evaluate $k[$f][$i] +// 18. Assign $j from $k[$f][$i] + +list( + (string)$a => $store["B"], + (string)$c => list($store["D"], $store["E"]), + (string)$f => list( + (string)$g => $store["H"], + (string)$i => $store["J"] + ) +) = $k->getIndexable(); + +?> +--EXPECT-- +Indexable K retrieved. +A evaluated. +Offset A retrieved. +Offset B set to offset value for A. +C evaluated. +Offset C retrieved. +Offset 0 retrieved. +Offset D set to offset value for 0. +Offset 1 retrieved. +Offset E set to offset value for 1. +F evaluated. +Offset F retrieved. +G evaluated. +Offset G retrieved. +Offset H set to offset value for G. +I evaluated. +Offset I retrieved. +Offset J set to offset value for I. diff --git a/Zend/tests/list_keyed_non_literals.phpt b/Zend/tests/list_keyed_non_literals.phpt new file mode 100644 index 0000000000000..80f22eda22594 --- /dev/null +++ b/Zend/tests/list_keyed_non_literals.phpt @@ -0,0 +1,30 @@ +--TEST-- +list() with constant keys +--FILE-- + "one", + 2 => "two", + 3 => "three" +]; + +const COMPILE_TIME_RESOLVABLE = 1; + +define('PROBABLY_NOT_COMPILE_TIME_RESOLVABLE', file_get_contents("data:text/plain,2")); + +$probablyNotCompileTimeResolvable3 = cos(0) * 3; + +list( + COMPILE_TIME_RESOLVABLE => $one, + PROBABLY_NOT_COMPILE_TIME_RESOLVABLE => $two, + $probablyNotCompileTimeResolvable3 => $three +) = $arr; + +var_dump($one, $two, $three); + +?> +--EXPECTF-- +string(3) "one" +string(3) "two" +string(5) "three" diff --git a/Zend/tests/list_keyed_trailing_comma.phpt b/Zend/tests/list_keyed_trailing_comma.phpt new file mode 100644 index 0000000000000..e0af0aed21192 --- /dev/null +++ b/Zend/tests/list_keyed_trailing_comma.phpt @@ -0,0 +1,38 @@ +--TEST-- +list() with keys and a trailing comma +--FILE-- + "bad", + "happy" => "sad", +]; + +list( + "good" => $good, + "happy" => $happy +) = $antonyms; + +var_dump($good, $happy); + +echo PHP_EOL; + +$antonyms = [ + "good" => "bad", + "happy" => "sad", +]; + +list( + "good" => $good, + "happy" => $happy, +) = $antonyms; + +var_dump($good, $happy); + +?> +--EXPECT-- +string(3) "bad" +string(3) "sad" + +string(3) "bad" +string(3) "sad" diff --git a/Zend/tests/list_keyed_undefined.phpt b/Zend/tests/list_keyed_undefined.phpt new file mode 100644 index 0000000000000..a18e3b4d20650 --- /dev/null +++ b/Zend/tests/list_keyed_undefined.phpt @@ -0,0 +1,22 @@ +--TEST-- +list() with undefined keys +--FILE-- + "the best PHP version", + "elePHPant" => "the cutest mascot" +]; + +list(5 => $five, "duke" => $duke) = $contrivedMixedKeyTypesExample; + +var_dump($five, $duke); + +?> +--EXPECTF-- + +Notice: Undefined offset: 5 in %s on line %d + +Notice: Undefined index: duke in %s on line %d +NULL +NULL diff --git a/Zend/tests/list_mixed_keyed_unkeyed.phpt b/Zend/tests/list_mixed_keyed_unkeyed.phpt new file mode 100644 index 0000000000000..5562479fc387d --- /dev/null +++ b/Zend/tests/list_mixed_keyed_unkeyed.phpt @@ -0,0 +1,16 @@ +--TEST-- +list() with both keyed and unkeyed elements +--FILE-- + 1, + "foo" => "bar" +]; + +list($zero, 1 => $one, "foo" => $foo) = $contrivedKeyedAndUnkeyedArrayExample; + +?> +--EXPECTF-- +Parse error: syntax error, unexpected %s in %s on line %d diff --git a/Zend/tests/list_mixed_nested_keyed_unkeyed.phpt b/Zend/tests/list_mixed_nested_keyed_unkeyed.phpt new file mode 100644 index 0000000000000..3087775b76ab2 --- /dev/null +++ b/Zend/tests/list_mixed_nested_keyed_unkeyed.phpt @@ -0,0 +1,34 @@ +--TEST-- +list() with nested unkeyed and keyed list() +--FILE-- + 1, "y" => 2], + ["x" => 2, "y" => 1] +]; + +list(list("x" => $x1, "y" => $y1), list("x" => $x2, "y" => $y2)) = $points; +var_dump($x1, $y1, $x2, $y2); + +echo PHP_EOL; + +$invertedPoints = [ + "x" => [1, 2], + "y" => [2, 1] +]; + +list("x" => list($x1, $x2), "y" => list($y1, $y2)) = $invertedPoints; +var_dump($x1, $y1, $x2, $y2); + +?> +--EXPECT-- +int(1) +int(2) +int(2) +int(1) + +int(1) +int(2) +int(2) +int(1) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 9b79202014dff..0b871ed52a25a 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2709,9 +2709,8 @@ void zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type, int d } /* }}} */ -static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_node) /* {{{ */ +static void zend_compile_unkeyed_list_assign(zend_ast_list *list, znode *expr_node) /* {{{ */ { - zend_ast_list *list = zend_ast_get_list(ast); uint32_t i; zend_bool has_elems = 0; @@ -2738,6 +2737,40 @@ static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_n if (!has_elems) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot use empty list"); } +} +/* }}} */ + +static void zend_compile_keyed_list_assign(zend_ast_list *list, znode *expr_node) /* {{{ */ +{ + uint32_t i; + + for (i = 0; i < list->children; ++i) { + zend_ast *pair_ast = list->child[i]; + zend_ast *var_ast = pair_ast->child[0]; + zend_ast *key_ast = pair_ast->child[1]; + znode fetch_result, dim_node; + + zend_compile_expr(&dim_node, key_ast); + + if (expr_node->op_type == IS_CONST) { + Z_TRY_ADDREF(expr_node->u.constant); + } + + zend_emit_op(&fetch_result, ZEND_FETCH_LIST, expr_node, &dim_node); + zend_emit_assign_znode(var_ast, &fetch_result); + } +} +/* }}} */ + +static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_node) /* {{{ */ +{ + zend_ast_list *list = zend_ast_get_list(ast); + + if (list->children > 0 && list->child[0] != NULL && list->child[0]->kind == ZEND_AST_ARRAY_ELEM) { + zend_compile_keyed_list_assign(list, expr_node); + } else { + zend_compile_unkeyed_list_assign(list, expr_node); + } *result = *expr_node; } diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 754c50215dac5..0ec991e9086fa 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -241,7 +241,8 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type exit_expr scalar backticks_expr lexical_var function_call member_name property_name %type variable_class_name dereferencable_scalar constant dereferencable %type callable_expr callable_variable static_member new_variable -%type assignment_list_element array_pair encaps_var encaps_var_offset isset_variables +%type unkeyed_assignment_list_element keyed_assignment_list_element array_pair +%type encaps_var encaps_var_offset isset_variables %type top_statement_list use_declarations const_list inner_statement_list if_stmt %type alt_if_stmt for_exprs switch_case_list global_var_list static_var_list %type echo_expr_list unset_variables catch_list parameter_list class_statement_list @@ -250,7 +251,8 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type class_const_list class_const_decl name_list trait_adaptations method_body non_empty_for_exprs %type ctor_arguments alt_if_stmt_without_else trait_adaptation_list lexical_vars %type lexical_var_list encaps_list array_pair_list non_empty_array_pair_list -%type assignment_list isset_variable type return_type +%type assignment_list unkeyed_assignment_list keyed_assignment_list +%type isset_variable type return_type %type identifier %type returns_ref function is_reference is_variadic variable_modifiers @@ -1170,18 +1172,39 @@ property_name: ; assignment_list: - assignment_list ',' assignment_list_element + unkeyed_assignment_list + { $$ = $1; } + | keyed_assignment_list possible_comma + { $$ = $1; } +; + +unkeyed_assignment_list: + unkeyed_assignment_list ',' unkeyed_assignment_list_element { $$ = zend_ast_list_add($1, $3); } - | assignment_list_element + | unkeyed_assignment_list_element { $$ = zend_ast_create_list(1, ZEND_AST_LIST, $1); } ; -assignment_list_element: +unkeyed_assignment_list_element: variable { $$ = $1; } | T_LIST '(' assignment_list ')' { $$ = $3; } | /* empty */ { $$ = NULL; } ; +keyed_assignment_list: + keyed_assignment_list ',' keyed_assignment_list_element + { $$ = zend_ast_list_add($1, $3); } + | keyed_assignment_list_element + { $$ = zend_ast_create_list(1, ZEND_AST_LIST, $1); } +; + +keyed_assignment_list_element: + expr T_DOUBLE_ARROW variable + { $$ = zend_ast_create(ZEND_AST_ARRAY_ELEM, $3, $1); } + | expr T_DOUBLE_ARROW T_LIST '(' assignment_list ')' + { $$ = zend_ast_create(ZEND_AST_ARRAY_ELEM, $5, $1); } +; + array_pair_list: /* empty */ { $$ = zend_ast_create_list(0, ZEND_AST_ARRAY); } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index af9daa89b1d19..e2ee420f89e5d 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2062,30 +2062,80 @@ 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) +ZEND_VM_HANDLER(98, ZEND_FETCH_LIST, CONST|TMPVAR|CV, CONST|TMPVAR|CV) { USE_OPLINE zend_free_op free_op1; + zend_free_op free_op2; zval *container; + zval *offset = GET_OP2_ZVAL_PTR(BP_VAR_R); SAVE_OPLINE(); container = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); ZEND_VM_C_LABEL(try_fetch_list): if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - zval *value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2))); + zval *value; + zend_string *str; + zend_ulong hval; - if (UNEXPECTED(value == NULL)) { - zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2))); - ZVAL_NULL(EX_VAR(opline->result.var)); +ZEND_VM_C_LABEL(assign_again_list): + if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { + hval = Z_LVAL_P(offset); +ZEND_VM_C_LABEL(num_index_list): + value = zend_hash_index_find(Z_ARRVAL_P(container), hval); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) { + str = Z_STR_P(offset); + + if (ZEND_HANDLE_NUMERIC(str, hval)) { + ZEND_VM_C_GOTO(num_index_list); + } + +ZEND_VM_C_LABEL(str_index_list): + value = zend_hash_find(Z_ARRVAL_P(container), str); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str)); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (UNEXPECTED(str != Z_STR_P(offset))) { + zend_string_release(str); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) { + offset = Z_REFVAL_P(offset); + ZEND_VM_C_GOTO(assign_again_list); + } else if (Z_TYPE_P(offset) == IS_NULL) { + str = ZSTR_EMPTY_ALLOC(); + ZEND_VM_C_GOTO(str_index_list); + } else if (Z_TYPE_P(offset) == IS_DOUBLE) { + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + ZEND_VM_C_GOTO(num_index_list); + } else if (Z_TYPE_P(offset) == IS_FALSE) { + hval = 0; + ZEND_VM_C_GOTO(num_index_list); + } else if (Z_TYPE_P(offset) == IS_TRUE) { + hval = 1; + ZEND_VM_C_GOTO(num_index_list); + } else if (Z_TYPE_P(offset) == IS_RESOURCE) { + zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset)); + hval = Z_RES_HANDLE_P(offset); } else { - ZVAL_COPY(EX_VAR(opline->result.var), value); + zend_error(E_WARNING, "Illegal offset type"); } } else if (OP1_TYPE != IS_CONST && UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) && EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) { zval *result = EX_VAR(opline->result.var); - zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, EX_CONSTANT(opline->op2), BP_VAR_R, result); + zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result); if (retval) { if (result != retval) { @@ -2103,6 +2153,7 @@ ZEND_VM_C_LABEL(try_fetch_list): } ZVAL_NULL(EX_VAR(opline->result.var)); } + FREE_OP2(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index a4edfd0f98e89..612feb9e9c8f9 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -5746,26 +5746,76 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CONST_CONST_HA { USE_OPLINE + zval *container; + zval *offset = EX_CONSTANT(opline->op2); SAVE_OPLINE(); container = EX_CONSTANT(opline->op1); try_fetch_list: if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - zval *value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2))); + zval *value; + zend_string *str; + zend_ulong hval; - if (UNEXPECTED(value == NULL)) { - zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2))); - ZVAL_NULL(EX_VAR(opline->result.var)); +assign_again_list: + if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { + hval = Z_LVAL_P(offset); +num_index_list: + value = zend_hash_index_find(Z_ARRVAL_P(container), hval); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) { + str = Z_STR_P(offset); + + if (ZEND_HANDLE_NUMERIC(str, hval)) { + goto num_index_list; + } + +str_index_list: + value = zend_hash_find(Z_ARRVAL_P(container), str); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str)); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (UNEXPECTED(str != Z_STR_P(offset))) { + zend_string_release(str); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) { + offset = Z_REFVAL_P(offset); + goto assign_again_list; + } else if (Z_TYPE_P(offset) == IS_NULL) { + str = ZSTR_EMPTY_ALLOC(); + goto str_index_list; + } else if (Z_TYPE_P(offset) == IS_DOUBLE) { + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_FALSE) { + hval = 0; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_TRUE) { + hval = 1; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_RESOURCE) { + zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset)); + hval = Z_RES_HANDLE_P(offset); } else { - ZVAL_COPY(EX_VAR(opline->result.var), value); + zend_error(E_WARNING, "Illegal offset type"); } } else if (IS_CONST != IS_CONST && UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) && EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) { zval *result = EX_VAR(opline->result.var); - zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, EX_CONSTANT(opline->op2), BP_VAR_R, result); + zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result); if (retval) { if (result != retval) { @@ -5783,6 +5833,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CONST_CONST_HA } ZVAL_NULL(EX_VAR(opline->result.var)); } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -9499,6 +9550,101 @@ 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) +{ + USE_OPLINE + + + zval *container; + zval *offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var); + + SAVE_OPLINE(); + container = EX_CONSTANT(opline->op1); + +try_fetch_list: + if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { + zval *value; + zend_string *str; + zend_ulong hval; + +assign_again_list: + if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { + hval = Z_LVAL_P(offset); +num_index_list: + value = zend_hash_index_find(Z_ARRVAL_P(container), hval); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) { + str = Z_STR_P(offset); + + if (ZEND_HANDLE_NUMERIC(str, hval)) { + goto num_index_list; + } + +str_index_list: + value = zend_hash_find(Z_ARRVAL_P(container), str); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str)); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (UNEXPECTED(str != Z_STR_P(offset))) { + zend_string_release(str); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) { + offset = Z_REFVAL_P(offset); + goto assign_again_list; + } else if (Z_TYPE_P(offset) == IS_NULL) { + str = ZSTR_EMPTY_ALLOC(); + goto str_index_list; + } else if (Z_TYPE_P(offset) == IS_DOUBLE) { + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_FALSE) { + hval = 0; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_TRUE) { + hval = 1; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_RESOURCE) { + zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset)); + hval = Z_RES_HANDLE_P(offset); + } else { + zend_error(E_WARNING, "Illegal offset type"); + } + } else if (IS_CONST != IS_CONST && + UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) && + EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) { + zval *result = EX_VAR(opline->result.var); + zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result); + + if (retval) { + if (result != retval) { + ZVAL_COPY(result, retval); + } + } else { + ZVAL_NULL(result); + } + } else if ((IS_CONST & (IS_VAR|IS_CV)) && Z_TYPE_P(container) == IS_REFERENCE) { + container = Z_REFVAL_P(container); + goto try_fetch_list; + } else { + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { + GET_OP1_UNDEF_CV(container, BP_VAR_R); + } + ZVAL_NULL(EX_VAR(opline->result.var)); + } + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -11310,6 +11456,101 @@ 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) +{ + USE_OPLINE + + zend_free_op free_op2; + zval *container; + zval *offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + + SAVE_OPLINE(); + container = EX_CONSTANT(opline->op1); + +try_fetch_list: + if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { + zval *value; + zend_string *str; + zend_ulong hval; + +assign_again_list: + if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { + hval = Z_LVAL_P(offset); +num_index_list: + value = zend_hash_index_find(Z_ARRVAL_P(container), hval); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) { + str = Z_STR_P(offset); + + if (ZEND_HANDLE_NUMERIC(str, hval)) { + goto num_index_list; + } + +str_index_list: + value = zend_hash_find(Z_ARRVAL_P(container), str); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str)); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (UNEXPECTED(str != Z_STR_P(offset))) { + zend_string_release(str); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) { + offset = Z_REFVAL_P(offset); + goto assign_again_list; + } else if (Z_TYPE_P(offset) == IS_NULL) { + str = ZSTR_EMPTY_ALLOC(); + goto str_index_list; + } else if (Z_TYPE_P(offset) == IS_DOUBLE) { + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_FALSE) { + hval = 0; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_TRUE) { + hval = 1; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_RESOURCE) { + zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset)); + hval = Z_RES_HANDLE_P(offset); + } else { + zend_error(E_WARNING, "Illegal offset type"); + } + } else if (IS_CONST != IS_CONST && + UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) && + EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) { + zval *result = EX_VAR(opline->result.var); + zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result); + + if (retval) { + if (result != retval) { + ZVAL_COPY(result, retval); + } + } else { + ZVAL_NULL(result); + } + } else if ((IS_CONST & (IS_VAR|IS_CV)) && Z_TYPE_P(container) == IS_REFERENCE) { + container = Z_REFVAL_P(container); + goto try_fetch_list; + } else { + if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { + GET_OP1_UNDEF_CV(container, BP_VAR_R); + } + ZVAL_NULL(EX_VAR(opline->result.var)); + } + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -37859,26 +38100,76 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CV_CONST_HANDL { USE_OPLINE + zval *container; + zval *offset = EX_CONSTANT(opline->op2); SAVE_OPLINE(); container = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); try_fetch_list: if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - zval *value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2))); + zval *value; + zend_string *str; + zend_ulong hval; - if (UNEXPECTED(value == NULL)) { - zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2))); - ZVAL_NULL(EX_VAR(opline->result.var)); +assign_again_list: + if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { + hval = Z_LVAL_P(offset); +num_index_list: + value = zend_hash_index_find(Z_ARRVAL_P(container), hval); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) { + str = Z_STR_P(offset); + + if (ZEND_HANDLE_NUMERIC(str, hval)) { + goto num_index_list; + } + +str_index_list: + value = zend_hash_find(Z_ARRVAL_P(container), str); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str)); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (UNEXPECTED(str != Z_STR_P(offset))) { + zend_string_release(str); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) { + offset = Z_REFVAL_P(offset); + goto assign_again_list; + } else if (Z_TYPE_P(offset) == IS_NULL) { + str = ZSTR_EMPTY_ALLOC(); + goto str_index_list; + } else if (Z_TYPE_P(offset) == IS_DOUBLE) { + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_FALSE) { + hval = 0; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_TRUE) { + hval = 1; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_RESOURCE) { + zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset)); + hval = Z_RES_HANDLE_P(offset); } else { - ZVAL_COPY(EX_VAR(opline->result.var), value); + zend_error(E_WARNING, "Illegal offset type"); } } else if (IS_CV != IS_CONST && UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) && EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) { zval *result = EX_VAR(opline->result.var); - zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, EX_CONSTANT(opline->op2), BP_VAR_R, result); + zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result); if (retval) { if (result != retval) { @@ -37896,6 +38187,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CV_CONST_HANDL } ZVAL_NULL(EX_VAR(opline->result.var)); } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -44238,6 +44530,101 @@ 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) +{ + USE_OPLINE + + + zval *container; + zval *offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var); + + SAVE_OPLINE(); + container = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + +try_fetch_list: + if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { + zval *value; + zend_string *str; + zend_ulong hval; + +assign_again_list: + if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { + hval = Z_LVAL_P(offset); +num_index_list: + value = zend_hash_index_find(Z_ARRVAL_P(container), hval); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) { + str = Z_STR_P(offset); + + if (ZEND_HANDLE_NUMERIC(str, hval)) { + goto num_index_list; + } + +str_index_list: + value = zend_hash_find(Z_ARRVAL_P(container), str); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str)); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (UNEXPECTED(str != Z_STR_P(offset))) { + zend_string_release(str); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) { + offset = Z_REFVAL_P(offset); + goto assign_again_list; + } else if (Z_TYPE_P(offset) == IS_NULL) { + str = ZSTR_EMPTY_ALLOC(); + goto str_index_list; + } else if (Z_TYPE_P(offset) == IS_DOUBLE) { + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_FALSE) { + hval = 0; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_TRUE) { + hval = 1; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_RESOURCE) { + zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset)); + hval = Z_RES_HANDLE_P(offset); + } else { + zend_error(E_WARNING, "Illegal offset type"); + } + } else if (IS_CV != IS_CONST && + UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) && + EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) { + zval *result = EX_VAR(opline->result.var); + zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result); + + if (retval) { + if (result != retval) { + ZVAL_COPY(result, retval); + } + } else { + ZVAL_NULL(result); + } + } else if ((IS_CV & (IS_VAR|IS_CV)) && Z_TYPE_P(container) == IS_REFERENCE) { + container = Z_REFVAL_P(container); + goto try_fetch_list; + } else { + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { + GET_OP1_UNDEF_CV(container, BP_VAR_R); + } + ZVAL_NULL(EX_VAR(opline->result.var)); + } + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -47793,6 +48180,101 @@ 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) +{ + USE_OPLINE + + zend_free_op free_op2; + zval *container; + zval *offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + + SAVE_OPLINE(); + container = _get_zval_ptr_cv_undef(execute_data, opline->op1.var); + +try_fetch_list: + if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { + zval *value; + zend_string *str; + zend_ulong hval; + +assign_again_list: + if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { + hval = Z_LVAL_P(offset); +num_index_list: + value = zend_hash_index_find(Z_ARRVAL_P(container), hval); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) { + str = Z_STR_P(offset); + + if (ZEND_HANDLE_NUMERIC(str, hval)) { + goto num_index_list; + } + +str_index_list: + value = zend_hash_find(Z_ARRVAL_P(container), str); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str)); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (UNEXPECTED(str != Z_STR_P(offset))) { + zend_string_release(str); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) { + offset = Z_REFVAL_P(offset); + goto assign_again_list; + } else if (Z_TYPE_P(offset) == IS_NULL) { + str = ZSTR_EMPTY_ALLOC(); + goto str_index_list; + } else if (Z_TYPE_P(offset) == IS_DOUBLE) { + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_FALSE) { + hval = 0; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_TRUE) { + hval = 1; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_RESOURCE) { + zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset)); + hval = Z_RES_HANDLE_P(offset); + } else { + zend_error(E_WARNING, "Illegal offset type"); + } + } else if (IS_CV != IS_CONST && + UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) && + EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) { + zval *result = EX_VAR(opline->result.var); + zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result); + + if (retval) { + if (result != retval) { + ZVAL_COPY(result, retval); + } + } else { + ZVAL_NULL(result); + } + } else if ((IS_CV & (IS_VAR|IS_CV)) && Z_TYPE_P(container) == IS_REFERENCE) { + container = Z_REFVAL_P(container); + goto try_fetch_list; + } else { + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { + GET_OP1_UNDEF_CV(container, BP_VAR_R); + } + ZVAL_NULL(EX_VAR(opline->result.var)); + } + zval_ptr_dtor_nogc(free_op2); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_DATA_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -51010,26 +51492,76 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_TMPVAR_CONST_H { USE_OPLINE zend_free_op free_op1; + zval *container; + zval *offset = EX_CONSTANT(opline->op2); SAVE_OPLINE(); container = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); try_fetch_list: if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - zval *value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2))); + zval *value; + zend_string *str; + zend_ulong hval; - if (UNEXPECTED(value == NULL)) { - zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2))); - ZVAL_NULL(EX_VAR(opline->result.var)); +assign_again_list: + if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { + hval = Z_LVAL_P(offset); +num_index_list: + value = zend_hash_index_find(Z_ARRVAL_P(container), hval); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) { + str = Z_STR_P(offset); + + if (ZEND_HANDLE_NUMERIC(str, hval)) { + goto num_index_list; + } + +str_index_list: + value = zend_hash_find(Z_ARRVAL_P(container), str); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str)); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (UNEXPECTED(str != Z_STR_P(offset))) { + zend_string_release(str); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) { + offset = Z_REFVAL_P(offset); + goto assign_again_list; + } else if (Z_TYPE_P(offset) == IS_NULL) { + str = ZSTR_EMPTY_ALLOC(); + goto str_index_list; + } else if (Z_TYPE_P(offset) == IS_DOUBLE) { + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_FALSE) { + hval = 0; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_TRUE) { + hval = 1; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_RESOURCE) { + zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset)); + hval = Z_RES_HANDLE_P(offset); } else { - ZVAL_COPY(EX_VAR(opline->result.var), value); + zend_error(E_WARNING, "Illegal offset type"); } } else if ((IS_TMP_VAR|IS_VAR) != IS_CONST && UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) && EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) { zval *result = EX_VAR(opline->result.var); - zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, EX_CONSTANT(opline->op2), BP_VAR_R, result); + zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result); if (retval) { if (result != retval) { @@ -51047,6 +51579,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_TMPVAR_CONST_H } ZVAL_NULL(EX_VAR(opline->result.var)); } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -53295,6 +53828,101 @@ 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) +{ + USE_OPLINE + zend_free_op free_op1; + + zval *container; + zval *offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var); + + SAVE_OPLINE(); + container = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + +try_fetch_list: + if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { + zval *value; + zend_string *str; + zend_ulong hval; + +assign_again_list: + if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { + hval = Z_LVAL_P(offset); +num_index_list: + value = zend_hash_index_find(Z_ARRVAL_P(container), hval); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) { + str = Z_STR_P(offset); + + if (ZEND_HANDLE_NUMERIC(str, hval)) { + goto num_index_list; + } + +str_index_list: + value = zend_hash_find(Z_ARRVAL_P(container), str); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str)); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (UNEXPECTED(str != Z_STR_P(offset))) { + zend_string_release(str); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) { + offset = Z_REFVAL_P(offset); + goto assign_again_list; + } else if (Z_TYPE_P(offset) == IS_NULL) { + str = ZSTR_EMPTY_ALLOC(); + goto str_index_list; + } else if (Z_TYPE_P(offset) == IS_DOUBLE) { + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_FALSE) { + hval = 0; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_TRUE) { + hval = 1; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_RESOURCE) { + zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset)); + hval = Z_RES_HANDLE_P(offset); + } else { + zend_error(E_WARNING, "Illegal offset type"); + } + } else if ((IS_TMP_VAR|IS_VAR) != IS_CONST && + UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) && + EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) { + zval *result = EX_VAR(opline->result.var); + zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result); + + if (retval) { + if (result != retval) { + ZVAL_COPY(result, retval); + } + } else { + ZVAL_NULL(result); + } + } else if (((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_CV)) && Z_TYPE_P(container) == IS_REFERENCE) { + container = Z_REFVAL_P(container); + goto try_fetch_list; + } else { + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { + GET_OP1_UNDEF_CV(container, BP_VAR_R); + } + ZVAL_NULL(EX_VAR(opline->result.var)); + } + + 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 @@ -54444,6 +55072,101 @@ 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) +{ + USE_OPLINE + zend_free_op free_op1; + zend_free_op free_op2; + zval *container; + zval *offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); + + SAVE_OPLINE(); + container = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + +try_fetch_list: + if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { + zval *value; + zend_string *str; + zend_ulong hval; + +assign_again_list: + if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) { + hval = Z_LVAL_P(offset); +num_index_list: + value = zend_hash_index_find(Z_ARRVAL_P(container), hval); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined offset: " ZEND_ULONG_FMT, hval); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_STRING)) { + str = Z_STR_P(offset); + + if (ZEND_HANDLE_NUMERIC(str, hval)) { + goto num_index_list; + } + +str_index_list: + value = zend_hash_find(Z_ARRVAL_P(container), str); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(str)); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (UNEXPECTED(str != Z_STR_P(offset))) { + zend_string_release(str); + } + } else if (EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) { + offset = Z_REFVAL_P(offset); + goto assign_again_list; + } else if (Z_TYPE_P(offset) == IS_NULL) { + str = ZSTR_EMPTY_ALLOC(); + goto str_index_list; + } else if (Z_TYPE_P(offset) == IS_DOUBLE) { + hval = zend_dval_to_lval(Z_DVAL_P(offset)); + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_FALSE) { + hval = 0; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_TRUE) { + hval = 1; + goto num_index_list; + } else if (Z_TYPE_P(offset) == IS_RESOURCE) { + zend_error(E_NOTICE, "Resource ID#%pd used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(offset), Z_RES_HANDLE_P(offset)); + hval = Z_RES_HANDLE_P(offset); + } else { + zend_error(E_WARNING, "Illegal offset type"); + } + } else if ((IS_TMP_VAR|IS_VAR) != IS_CONST && + UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) && + EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) { + zval *result = EX_VAR(opline->result.var); + zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, offset, BP_VAR_R, result); + + if (retval) { + if (result != retval) { + ZVAL_COPY(result, retval); + } + } else { + ZVAL_NULL(result); + } + } else if (((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_CV)) && Z_TYPE_P(container) == IS_REFERENCE) { + container = Z_REFVAL_P(container); + goto try_fetch_list; + } else { + if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { + GET_OP1_UNDEF_CV(container, BP_VAR_R); + } + ZVAL_NULL(EX_VAR(opline->result.var)); + } + 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 @@ -57495,30 +58218,30 @@ void zend_init_opcodes_handlers(void) 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_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_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_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_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_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_FETCH_LIST_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_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_FETCH_LIST_SPEC_CV_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 37ba8d411ba34..ac5f0d6a32eee 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -307,7 +307,7 @@ static uint32_t zend_vm_opcodes_flags[184] = { 0x00010107, 0x00000701, 0x00000751, - 0x00000307, + 0x00000707, 0x06000301, 0x00000000, 0x00000000,