mirror of
https://github.com/bdnugget/php-src.git
synced 2026-11-13 04:00:50 +00:00
Compare commits
20
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74b85316ea | ||
|
|
1e41295097 | ||
|
|
5406f21b11 | ||
|
|
b37f1d58d2 | ||
|
|
fb2d079645 | ||
|
|
08302c0d6d | ||
|
|
cc4b7be41e | ||
|
|
5aa9712b0a | ||
|
|
4c5b385ff5 | ||
|
|
621fd74c01 | ||
|
|
721fc9e80d | ||
|
|
15a23b1218 | ||
|
|
10a3260b1f | ||
|
|
2705d17c93 | ||
|
|
994d4350d3 | ||
|
|
eef80c5837 | ||
|
|
61e7391873 | ||
|
|
92e90c09f0 | ||
|
|
dd2a36a207 | ||
|
|
4638f7b914 |
No files matched your search
@@ -23,4 +23,4 @@ var_dump(key($arr["v"]));
|
||||
int(0)
|
||||
int(0)
|
||||
int(0)
|
||||
NULL
|
||||
int(0)
|
||||
@@ -23,4 +23,4 @@ int(0)
|
||||
int(0)
|
||||
int(1)
|
||||
int(2)
|
||||
NULL
|
||||
int(0)
|
||||
@@ -0,0 +1,71 @@
|
||||
--TEST--
|
||||
Iterator exceptions in foreach by value
|
||||
--FILE--
|
||||
<?php
|
||||
class IT implements Iterator {
|
||||
private $n = 0;
|
||||
private $count = 0;
|
||||
private $trap = null;
|
||||
|
||||
function __construct($count, $trap = null) {
|
||||
$this->count = $count;
|
||||
$this->trap = $trap;
|
||||
}
|
||||
|
||||
function trap($trap) {
|
||||
if ($trap === $this->trap) {
|
||||
throw new Exception($trap);
|
||||
}
|
||||
}
|
||||
|
||||
function rewind() {$this->trap(__FUNCTION__); $this->n = 0;}
|
||||
function valid() {$this->trap(__FUNCTION__); return $this->n < $this->count;}
|
||||
function key() {$this->trap(__FUNCTION__); return $this->n;}
|
||||
function current() {$this->trap(__FUNCTION__); return $this->n;}
|
||||
function next() {$this->trap(__FUNCTION__); $this->n++;}
|
||||
}
|
||||
|
||||
foreach(['rewind', 'valid', 'key', 'current', 'next'] as $trap) {
|
||||
$obj = new IT(3, $trap);
|
||||
try {
|
||||
// IS_CV
|
||||
foreach ($obj as $key => $val) echo "$val\n";
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
unset($obj);
|
||||
|
||||
try {
|
||||
// IS_VAR
|
||||
foreach (new IT(3, $trap) as $key => $val) echo "$val\n";
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
// IS_TMP_VAR
|
||||
foreach ((object)new IT(2, $trap) as $key => $val) echo "$val\n";
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
rewind
|
||||
rewind
|
||||
rewind
|
||||
valid
|
||||
valid
|
||||
valid
|
||||
key
|
||||
key
|
||||
key
|
||||
current
|
||||
current
|
||||
current
|
||||
0
|
||||
next
|
||||
0
|
||||
next
|
||||
0
|
||||
next
|
||||
@@ -0,0 +1,65 @@
|
||||
--TEST--
|
||||
Iterator exceptions in foreach by reference
|
||||
--FILE--
|
||||
<?php
|
||||
class IT extends ArrayIterator {
|
||||
private $n = 0;
|
||||
|
||||
function __construct($trap = null) {
|
||||
parent::__construct([0, 1]);
|
||||
$this->trap = $trap;
|
||||
}
|
||||
|
||||
function trap($trap) {
|
||||
if ($trap === $this->trap) {
|
||||
throw new Exception($trap);
|
||||
}
|
||||
}
|
||||
|
||||
function rewind() {$this->trap(__FUNCTION__); return parent::rewind();}
|
||||
function valid() {$this->trap(__FUNCTION__); return parent::valid();}
|
||||
function key() {$this->trap(__FUNCTION__); return parent::key();}
|
||||
function next() {$this->trap(__FUNCTION__); return parent::next();}
|
||||
}
|
||||
|
||||
foreach(['rewind', 'valid', 'key', 'next'] as $trap) {
|
||||
$obj = new IT($trap);
|
||||
try {
|
||||
// IS_CV
|
||||
foreach ($obj as $key => &$val) echo "$val\n";
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
unset($obj);
|
||||
|
||||
try {
|
||||
// IS_VAR
|
||||
foreach (new IT($trap) as $key => &$val) echo "$val\n";
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
// IS_TMP_VAR
|
||||
foreach ((object)new IT($trap) as $key => &$val) echo "$val\n";
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
rewind
|
||||
rewind
|
||||
rewind
|
||||
valid
|
||||
valid
|
||||
valid
|
||||
key
|
||||
key
|
||||
key
|
||||
0
|
||||
next
|
||||
0
|
||||
next
|
||||
0
|
||||
next
|
||||
@@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
Nested foreach by reference on the same array
|
||||
--FILE--
|
||||
<?php
|
||||
$a = [1,2,3];
|
||||
foreach($a as &$x) {
|
||||
foreach($a as &$y) {
|
||||
echo "$x-$y\n";
|
||||
$y++;
|
||||
}
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
1-1
|
||||
2-2
|
||||
2-3
|
||||
3-2
|
||||
3-3
|
||||
4-4
|
||||
5-3
|
||||
5-4
|
||||
5-5
|
||||
@@ -0,0 +1,20 @@
|
||||
--TEST--
|
||||
Foreach by reference on constant
|
||||
--FILE--
|
||||
<?php
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
foreach ([1,2,3] as &$val) {
|
||||
echo "$val\n";
|
||||
}
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
1
|
||||
2
|
||||
3
|
||||
1
|
||||
2
|
||||
3
|
||||
1
|
||||
2
|
||||
3
|
||||
@@ -0,0 +1,13 @@
|
||||
--TEST--
|
||||
Foreach by reference and inserting new element when we are already at the end
|
||||
--FILE--
|
||||
<?php
|
||||
$a = [1];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
$a[1]=2;
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
1
|
||||
2
|
||||
@@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Nested foreach by reference and array modification
|
||||
--FILE--
|
||||
<?php
|
||||
$a = [0, 1, 2, 3];
|
||||
foreach ($a as &$x) {
|
||||
foreach ($a as &$y) {
|
||||
echo "$x - $y\n";
|
||||
if ($x == 0 && $y == 1) {
|
||||
unset($a[2]);
|
||||
unset($a[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
0 - 0
|
||||
0 - 1
|
||||
0 - 3
|
||||
3 - 0
|
||||
3 - 3
|
||||
@@ -0,0 +1,40 @@
|
||||
--TEST--
|
||||
Nested foreach by reference and array modification with resize
|
||||
--FILE--
|
||||
<?php
|
||||
$a = [0, 1, 2, 3, 4, 5, 6, 7];
|
||||
unset($a[0], $a[1], $a[2], $a[3]);
|
||||
foreach ($a as &$ref) {
|
||||
foreach ($a as &$ref2) {
|
||||
echo "$ref-$ref2\n";
|
||||
if ($ref == 5 && $ref2 == 6) {
|
||||
$a[42] = 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
4-4
|
||||
4-5
|
||||
4-6
|
||||
4-7
|
||||
5-4
|
||||
5-5
|
||||
5-6
|
||||
5-7
|
||||
5-8
|
||||
6-4
|
||||
6-5
|
||||
6-6
|
||||
6-7
|
||||
6-8
|
||||
7-4
|
||||
7-5
|
||||
7-6
|
||||
7-7
|
||||
7-8
|
||||
8-4
|
||||
8-5
|
||||
8-6
|
||||
8-7
|
||||
8-8
|
||||
@@ -0,0 +1,40 @@
|
||||
--TEST--
|
||||
Nested foreach by value over object and object modification with resize
|
||||
--FILE--
|
||||
<?php
|
||||
$o = (object)['a'=>0, 'b'=>1, 'c'=>2, 'd'=>3, 'e'=>4, 'f'=>5, 'g'=>6, 'h'=>7];
|
||||
unset($o->a, $o->b, $o->c, $o->d);
|
||||
foreach ($o as $v1) {
|
||||
foreach ($o as $v2) {
|
||||
echo "$v1-$v2\n";
|
||||
if ($v1 == 5 && $v2 == 6) {
|
||||
$o->i = 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
4-4
|
||||
4-5
|
||||
4-6
|
||||
4-7
|
||||
5-4
|
||||
5-5
|
||||
5-6
|
||||
5-7
|
||||
5-8
|
||||
6-4
|
||||
6-5
|
||||
6-6
|
||||
6-7
|
||||
6-8
|
||||
7-4
|
||||
7-5
|
||||
7-6
|
||||
7-7
|
||||
7-8
|
||||
8-4
|
||||
8-5
|
||||
8-6
|
||||
8-7
|
||||
8-8
|
||||
@@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
sort() functions precerve foreach by reference iterator pointer
|
||||
--FILE--
|
||||
<?php
|
||||
$a = [1,2,3,4,5,0];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if ($v == 3) {
|
||||
rsort($a);
|
||||
}
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
1
|
||||
2
|
||||
3
|
||||
2
|
||||
1
|
||||
0
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
array_walk() function precerve foreach by reference iterator pointer
|
||||
--FILE--
|
||||
<?php
|
||||
$a = [1,2,3,4,5];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if ($v == 3) {
|
||||
array_walk($a, function (&$x) {$x+=10;});
|
||||
}
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
1
|
||||
2
|
||||
3
|
||||
14
|
||||
15
|
||||
@@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
array_push() function precerve foreach by reference iterator pointer
|
||||
--FILE--
|
||||
<?php
|
||||
$a = [1,2,3];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if ($v == 3) {
|
||||
array_push($a, 4);
|
||||
}
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
@@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
array_pop() function precerve foreach by reference iterator pointer
|
||||
--FILE--
|
||||
<?php
|
||||
$a = [1,2,3];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if ($v == 2) {
|
||||
array_pop($a);
|
||||
}
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
1
|
||||
2
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
array_shift() function precerve foreach by reference iterator pointer
|
||||
--FILE--
|
||||
<?php
|
||||
$a = [1,2,3,4];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
array_shift($a);
|
||||
}
|
||||
var_dump($a);
|
||||
?>
|
||||
--EXPECT--
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
array(0) {
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
array_unshift() function precerve foreach by reference iterator pointer
|
||||
--FILE--
|
||||
<?php
|
||||
$a = [1,2,3];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if ($v == 2) {
|
||||
array_unshift($a, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
var_dump(count($a));
|
||||
?>
|
||||
--EXPECT--
|
||||
1
|
||||
2
|
||||
3
|
||||
int(11)
|
||||
@@ -0,0 +1,111 @@
|
||||
--TEST--
|
||||
array_splice() function precerve foreach by reference iterator pointer
|
||||
--FILE--
|
||||
<?php
|
||||
/* remove before */
|
||||
$done = 0;
|
||||
$a = [0,1,2,3,4];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if (!$done && $v == 3) {
|
||||
$done = 1;
|
||||
array_splice($a, 1, 2);
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
/* remove after */
|
||||
$done = 0;
|
||||
$a = [0,1,2,3,4];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if (!$done && $v == 0) {
|
||||
$done = 1;
|
||||
array_splice($a, 2, 2);
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
/* remove current */
|
||||
$done = 0;
|
||||
$a = [0,1,2,3,4];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if (!$done && $v == 2) {
|
||||
$done = 1;
|
||||
array_splice($a, 1, 3);
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
$replacement = ['x', 'y', 'z'];
|
||||
|
||||
/* replace before */
|
||||
$done = 0;
|
||||
$a = [0,1,2,3,4];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if ($done && $v == 3) {
|
||||
$done = 1;
|
||||
array_splice($a, 1, 2, $replacement);
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
/* replace after */
|
||||
$done = 0;
|
||||
$a = [0,1,2,3,4];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if (!$done && $v == 0) {
|
||||
$done = 1;
|
||||
array_splice($a, 2, 2, $replacement);
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
|
||||
/* replace current */
|
||||
$done = 0;
|
||||
$a = [0,1,2,3,4];
|
||||
foreach($a as &$v) {
|
||||
echo "$v\n";
|
||||
if (!$done && $v == 2) {
|
||||
$done = 1;
|
||||
array_splice($a, 1, 3, $replacement);
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
|
||||
0
|
||||
1
|
||||
4
|
||||
|
||||
0
|
||||
1
|
||||
2
|
||||
4
|
||||
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
|
||||
0
|
||||
1
|
||||
x
|
||||
y
|
||||
z
|
||||
4
|
||||
|
||||
0
|
||||
1
|
||||
2
|
||||
4
|
||||
+6
-18
@@ -829,7 +829,7 @@ static int generate_free_loop_var(znode *var) /* {{{ */
|
||||
{
|
||||
zend_op *opline = get_next_op(CG(active_op_array));
|
||||
|
||||
opline->opcode = ZEND_FREE;
|
||||
opline->opcode = var->flag ? ZEND_FE_FREE : ZEND_FREE;
|
||||
SET_NODE(opline->op1, var);
|
||||
SET_UNUSED(opline->op2);
|
||||
}
|
||||
@@ -3396,32 +3396,19 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
|
||||
}
|
||||
|
||||
opnum_reset = get_next_op_number(CG(active_op_array));
|
||||
opline = zend_emit_op(&reset_node, ZEND_FE_RESET, &expr_node, NULL);
|
||||
if (by_ref && is_variable) {
|
||||
opline->extended_value = ZEND_FE_FETCH_BYREF;
|
||||
}
|
||||
opline = zend_emit_op(&reset_node, by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL);
|
||||
|
||||
reset_node.flag = 1; /* generate FE_FREE */
|
||||
zend_stack_push(&CG(loop_var_stack), &reset_node);
|
||||
|
||||
opnum_fetch = get_next_op_number(CG(active_op_array));
|
||||
opline = zend_emit_op(&value_node, ZEND_FE_FETCH, &reset_node, NULL);
|
||||
if (by_ref) {
|
||||
opline->extended_value |= ZEND_FE_FETCH_BYREF;
|
||||
}
|
||||
opline = zend_emit_op(&value_node, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL);
|
||||
if (key_ast) {
|
||||
opline->extended_value |= ZEND_FE_FETCH_WITH_KEY;
|
||||
opline->extended_value = 1;
|
||||
}
|
||||
|
||||
opline = zend_emit_op(NULL, ZEND_OP_DATA, NULL, NULL);
|
||||
|
||||
/* Allocate enough space to keep HashPointer on VM stack */
|
||||
opline->op1_type = IS_TMP_VAR;
|
||||
opline->op1.var = get_temporary_variable(CG(active_op_array));
|
||||
if (sizeof(HashPointer) > sizeof(zval)) {
|
||||
/* Make sure 1 zval is enough for HashPointer (2 must be enough) */
|
||||
get_temporary_variable(CG(active_op_array));
|
||||
}
|
||||
|
||||
if (key_ast) {
|
||||
zend_make_tmp_result(&key_node, opline);
|
||||
}
|
||||
@@ -3512,6 +3499,7 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */
|
||||
|
||||
zend_compile_expr(&expr_node, expr_ast);
|
||||
|
||||
expr_node.flag = 0;
|
||||
zend_stack_push(&CG(loop_var_stack), &expr_node);
|
||||
|
||||
zend_begin_loop();
|
||||
|
||||
+2
-4
@@ -95,7 +95,8 @@ typedef union _znode_op {
|
||||
} znode_op;
|
||||
|
||||
typedef struct _znode { /* used only during compilation */
|
||||
int op_type;
|
||||
zend_uchar op_type;
|
||||
zend_uchar flag;
|
||||
union {
|
||||
znode_op op;
|
||||
zval constant; /* replaced by literal/zv */
|
||||
@@ -828,9 +829,6 @@ int zend_add_literal(zend_op_array *op_array, zval *zv);
|
||||
|
||||
#define ZEND_FETCH_ARG_MASK 0x000fffff
|
||||
|
||||
#define ZEND_FE_FETCH_BYREF 1
|
||||
#define ZEND_FE_FETCH_WITH_KEY 2
|
||||
|
||||
#define EXT_TYPE_FREE_ON_RETURN (1<<2)
|
||||
|
||||
#define ZEND_MEMBER_FUNC_CALL 1<<0
|
||||
|
||||
@@ -1584,6 +1584,14 @@ static inline zend_brk_cont_element* zend_brk_cont(int nest_levels, int array_of
|
||||
if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
|
||||
zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
|
||||
}
|
||||
} else if (brk_opline->opcode == ZEND_FE_FREE) {
|
||||
if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
|
||||
zval *var = EX_VAR(brk_opline->op1.var);
|
||||
if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
|
||||
zend_hash_iterator_del(Z_FE_ITER_P(var));
|
||||
}
|
||||
zval_ptr_dtor_nogc(var);
|
||||
}
|
||||
}
|
||||
}
|
||||
array_offset = jmp_to->parent;
|
||||
|
||||
@@ -183,6 +183,11 @@ void init_executor(void) /* {{{ */
|
||||
|
||||
EG(scope) = NULL;
|
||||
|
||||
EG(ht_iterators_count) = sizeof(EG(ht_iterators_slots)) / sizeof(HashTableIterator);
|
||||
EG(ht_iterators_used) = 0;
|
||||
EG(ht_iterators) = EG(ht_iterators_slots);
|
||||
memset(EG(ht_iterators), 0, sizeof(EG(ht_iterators_slots)));
|
||||
|
||||
EG(active) = 1;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -373,6 +378,11 @@ void shutdown_executor(void) /* {{{ */
|
||||
|
||||
zend_shutdown_fpu();
|
||||
|
||||
EG(ht_iterators_used) = 0;
|
||||
if (EG(ht_iterators) != EG(ht_iterators_slots)) {
|
||||
efree(EG(ht_iterators));
|
||||
}
|
||||
|
||||
EG(active) = 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -60,6 +60,12 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato
|
||||
if (brk_opline->opcode == ZEND_FREE) {
|
||||
zval *var = EX_VAR(brk_opline->op1.var);
|
||||
zval_ptr_dtor_nogc(var);
|
||||
} else if (brk_opline->opcode == ZEND_FE_FREE) {
|
||||
zval *var = EX_VAR(brk_opline->op1.var);
|
||||
if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
|
||||
zend_hash_iterator_del(Z_FE_ITER_P(var));
|
||||
}
|
||||
zval_ptr_dtor_nogc(var);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,6 +225,11 @@ struct _zend_executor_globals {
|
||||
zend_bool active;
|
||||
zend_bool valid_symbol_table;
|
||||
|
||||
uint32_t ht_iterators_count; /* number of allocatd slots */
|
||||
uint32_t ht_iterators_used; /* number of used slots */
|
||||
HashTableIterator *ht_iterators;
|
||||
HashTableIterator ht_iterators_slots[16];
|
||||
|
||||
void *saved_fpu_cw_ptr;
|
||||
#if XPFPA_HAVE_CW
|
||||
XPFPA_CW_DATATYPE saved_fpu_cw;
|
||||
|
||||
+184
-18
@@ -193,6 +193,140 @@ ZEND_API void zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProt
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API uint32_t zend_hash_iterator_add(HashTable *ht, HashPosition pos)
|
||||
{
|
||||
HashTableIterator *iter = EG(ht_iterators);
|
||||
HashTableIterator *end = iter + EG(ht_iterators_count);
|
||||
uint32_t idx;
|
||||
|
||||
if (EXPECTED(ht->u.v.nIteratorsCount != 255)) {
|
||||
ht->u.v.nIteratorsCount++;
|
||||
}
|
||||
while (iter != end) {
|
||||
if (iter->ht == NULL) {
|
||||
iter->ht = ht;
|
||||
iter->pos = pos;
|
||||
idx = iter - EG(ht_iterators);
|
||||
if (idx + 1 > EG(ht_iterators_used)) {
|
||||
EG(ht_iterators_used) = idx + 1;
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
if (EG(ht_iterators) == EG(ht_iterators_slots)) {
|
||||
EG(ht_iterators) = emalloc(sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
|
||||
memcpy(EG(ht_iterators), EG(ht_iterators_slots), sizeof(HashTableIterator) * EG(ht_iterators_count));
|
||||
} else {
|
||||
EG(ht_iterators) = erealloc(EG(ht_iterators), sizeof(HashTableIterator) * (EG(ht_iterators_count) + 8));
|
||||
}
|
||||
iter = EG(ht_iterators) + EG(ht_iterators_count);
|
||||
EG(ht_iterators_count) += 8;
|
||||
iter->ht = ht;
|
||||
iter->pos = pos;
|
||||
memset(iter + 1, 0, sizeof(HashTableIterator) * 7);
|
||||
idx = iter - EG(ht_iterators);
|
||||
EG(ht_iterators_used) = idx + 1;
|
||||
return idx;
|
||||
}
|
||||
|
||||
ZEND_API HashPosition zend_hash_iterator_pos(uint32_t idx, HashTable *ht)
|
||||
{
|
||||
HashTableIterator *iter = EG(ht_iterators) + idx;
|
||||
|
||||
ZEND_ASSERT(idx != (uint32_t)-1);
|
||||
if (iter->pos == INVALID_IDX) {
|
||||
return INVALID_IDX;
|
||||
} else if (UNEXPECTED(iter->ht != ht)) {
|
||||
if (EXPECTED(iter->ht) && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
|
||||
iter->ht->u.v.nIteratorsCount--;
|
||||
}
|
||||
if (EXPECTED(ht->u.v.nIteratorsCount != 255)) {
|
||||
ht->u.v.nIteratorsCount++;
|
||||
}
|
||||
iter->ht = ht;
|
||||
iter->pos = ht->nInternalPointer;
|
||||
}
|
||||
return iter->pos;
|
||||
}
|
||||
|
||||
ZEND_API void zend_hash_iterator_del(uint32_t idx)
|
||||
{
|
||||
HashTableIterator *iter = EG(ht_iterators) + idx;
|
||||
|
||||
ZEND_ASSERT(idx != (uint32_t)-1);
|
||||
|
||||
if (EXPECTED(iter->ht) && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
|
||||
iter->ht->u.v.nIteratorsCount--;
|
||||
}
|
||||
iter->ht = NULL;
|
||||
|
||||
if (idx == EG(ht_iterators_used) - 1) {
|
||||
while (idx > 0 && EG(ht_iterators)[idx - 1].ht == NULL) {
|
||||
idx--;
|
||||
}
|
||||
EG(ht_iterators_used) = idx;
|
||||
}
|
||||
}
|
||||
|
||||
static zend_never_inline void _zend_hash_iterators_remove(HashTable *ht)
|
||||
{
|
||||
HashTableIterator *iter = EG(ht_iterators);
|
||||
HashTableIterator *end = iter + EG(ht_iterators_used);
|
||||
uint32_t idx;
|
||||
|
||||
while (iter != end) {
|
||||
if (iter->ht == ht) {
|
||||
iter->ht = NULL;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
|
||||
idx = EG(ht_iterators_used);
|
||||
while (idx > 0 && EG(ht_iterators)[idx - 1].ht == NULL) {
|
||||
idx--;
|
||||
}
|
||||
EG(ht_iterators_used) = idx;
|
||||
}
|
||||
|
||||
static zend_always_inline void zend_hash_iterators_remove(HashTable *ht)
|
||||
{
|
||||
if (UNEXPECTED(ht->u.v.nIteratorsCount)) {
|
||||
_zend_hash_iterators_remove(ht);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API HashPosition zend_hash_iterators_lower_pos(HashTable *ht, HashPosition start)
|
||||
{
|
||||
HashTableIterator *iter = EG(ht_iterators);
|
||||
HashTableIterator *end = iter + EG(ht_iterators_used);
|
||||
HashPosition res = INVALID_IDX;
|
||||
uint32_t idx;
|
||||
|
||||
while (iter != end) {
|
||||
if (iter->ht == ht) {
|
||||
if (iter->pos >= start && iter->pos < res) {
|
||||
res = iter->pos;
|
||||
}
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
ZEND_API void _zend_hash_iterators_update(HashTable *ht, HashPosition from, HashPosition to)
|
||||
{
|
||||
HashTableIterator *iter = EG(ht_iterators);
|
||||
HashTableIterator *end = iter + EG(ht_iterators_used);
|
||||
|
||||
while (iter != end) {
|
||||
if (iter->ht == ht && iter->pos == from) {
|
||||
iter->pos = to;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline Bucket *zend_hash_find_bucket(const HashTable *ht, zend_string *key)
|
||||
{
|
||||
zend_ulong h;
|
||||
@@ -305,6 +439,7 @@ add_to_hash:
|
||||
if (ht->nInternalPointer == INVALID_IDX) {
|
||||
ht->nInternalPointer = idx;
|
||||
}
|
||||
zend_hash_iterators_update(ht, INVALID_IDX, idx);
|
||||
p = ht->arData + idx;
|
||||
p->h = h = zend_string_hash_val(key);
|
||||
p->key = key;
|
||||
@@ -472,6 +607,7 @@ add_to_packed:
|
||||
if (ht->nInternalPointer == INVALID_IDX) {
|
||||
ht->nInternalPointer = h;
|
||||
}
|
||||
zend_hash_iterators_update(ht, INVALID_IDX, h);
|
||||
if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
|
||||
ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
|
||||
}
|
||||
@@ -514,6 +650,7 @@ add_to_hash:
|
||||
if (ht->nInternalPointer == INVALID_IDX) {
|
||||
ht->nInternalPointer = idx;
|
||||
}
|
||||
zend_hash_iterators_update(ht, INVALID_IDX, idx);
|
||||
if ((zend_long)h >= (zend_long)ht->nNextFreeElement) {
|
||||
ht->nNextFreeElement = h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
|
||||
}
|
||||
@@ -594,19 +731,42 @@ ZEND_API int zend_hash_rehash(HashTable *ht)
|
||||
}
|
||||
|
||||
memset(ht->arHash, INVALID_IDX, ht->nTableSize * sizeof(uint32_t));
|
||||
for (i = 0, j = 0; i < ht->nNumUsed; i++) {
|
||||
p = ht->arData + i;
|
||||
if (Z_TYPE(p->val) == IS_UNDEF) continue;
|
||||
if (i != j) {
|
||||
ht->arData[j] = ht->arData[i];
|
||||
if (ht->nInternalPointer == i) {
|
||||
ht->nInternalPointer = j;
|
||||
if (EXPECTED(ht->u.v.nIteratorsCount == 0)) {
|
||||
for (i = 0, j = 0; i < ht->nNumUsed; i++) {
|
||||
p = ht->arData + i;
|
||||
if (Z_TYPE(p->val) == IS_UNDEF) continue;
|
||||
if (i != j) {
|
||||
ht->arData[j] = ht->arData[i];
|
||||
if (ht->nInternalPointer == i) {
|
||||
ht->nInternalPointer = j;
|
||||
}
|
||||
}
|
||||
nIndex = ht->arData[j].h & ht->nTableMask;
|
||||
Z_NEXT(ht->arData[j].val) = ht->arHash[nIndex];
|
||||
ht->arHash[nIndex] = j;
|
||||
j++;
|
||||
}
|
||||
} else {
|
||||
uint32_t iter_pos = zend_hash_iterators_lower_pos(ht, 0);
|
||||
|
||||
for (i = 0, j = 0; i < ht->nNumUsed; i++) {
|
||||
p = ht->arData + i;
|
||||
if (Z_TYPE(p->val) == IS_UNDEF) continue;
|
||||
if (i != j) {
|
||||
ht->arData[j] = ht->arData[i];
|
||||
if (ht->nInternalPointer == i) {
|
||||
ht->nInternalPointer = j;
|
||||
}
|
||||
if (i == iter_pos) {
|
||||
zend_hash_iterators_update(ht, i, j);
|
||||
iter_pos = zend_hash_iterators_lower_pos(ht, iter_pos + 1);
|
||||
}
|
||||
}
|
||||
nIndex = ht->arData[j].h & ht->nTableMask;
|
||||
Z_NEXT(ht->arData[j].val) = ht->arHash[nIndex];
|
||||
ht->arHash[nIndex] = j;
|
||||
j++;
|
||||
}
|
||||
nIndex = ht->arData[j].h & ht->nTableMask;
|
||||
Z_NEXT(ht->arData[j].val) = ht->arHash[nIndex];
|
||||
ht->arHash[nIndex] = j;
|
||||
j++;
|
||||
}
|
||||
ht->nNumUsed = j;
|
||||
return SUCCESS;
|
||||
@@ -628,17 +788,22 @@ static zend_always_inline void _zend_hash_del_el_ex(HashTable *ht, uint32_t idx,
|
||||
} while (ht->nNumUsed > 0 && (Z_TYPE(ht->arData[ht->nNumUsed-1].val) == IS_UNDEF));
|
||||
}
|
||||
ht->nNumOfElements--;
|
||||
if (ht->nInternalPointer == idx) {
|
||||
if (ht->nInternalPointer == idx || UNEXPECTED(ht->u.v.nIteratorsCount)) {
|
||||
uint32_t new_idx = idx;
|
||||
|
||||
while (1) {
|
||||
idx++;
|
||||
if (idx >= ht->nNumUsed) {
|
||||
ht->nInternalPointer = INVALID_IDX;
|
||||
new_idx++;
|
||||
if (new_idx >= ht->nNumUsed) {
|
||||
new_idx = INVALID_IDX;
|
||||
break;
|
||||
} else if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
|
||||
ht->nInternalPointer = idx;
|
||||
} else if (Z_TYPE(ht->arData[new_idx].val) != IS_UNDEF) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ht->nInternalPointer == idx) {
|
||||
ht->nInternalPointer = new_idx;
|
||||
}
|
||||
zend_hash_iterators_update(ht, idx, new_idx);
|
||||
}
|
||||
if (p->key) {
|
||||
zend_string_release(p->key);
|
||||
@@ -893,6 +1058,7 @@ ZEND_API void zend_hash_destroy(HashTable *ht)
|
||||
} while (++p != end);
|
||||
}
|
||||
}
|
||||
zend_hash_iterators_remove(ht);
|
||||
} else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
|
||||
return;
|
||||
}
|
||||
@@ -933,7 +1099,7 @@ ZEND_API void zend_array_destroy(HashTable *ht)
|
||||
}
|
||||
} while (++p != end);
|
||||
}
|
||||
|
||||
zend_hash_iterators_remove(ht);
|
||||
SET_INCONSISTENT(HT_DESTROYED);
|
||||
} else if (EXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) {
|
||||
return;
|
||||
|
||||
+15
-9
@@ -50,8 +50,6 @@ typedef struct _zend_hash_key {
|
||||
|
||||
typedef zend_bool (*merge_checker_func_t)(HashTable *target_ht, zval *source_data, zend_hash_key *hash_key, void *pParam);
|
||||
|
||||
typedef uint32_t HashPosition;
|
||||
|
||||
BEGIN_EXTERN_C()
|
||||
|
||||
/* startup/shutdown */
|
||||
@@ -171,13 +169,6 @@ ZEND_API zval *zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos);
|
||||
ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos);
|
||||
ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos);
|
||||
|
||||
typedef struct _HashPointer {
|
||||
HashPosition pos;
|
||||
HashTable *ht;
|
||||
zend_ulong h;
|
||||
zend_string *key;
|
||||
} HashPointer;
|
||||
|
||||
#define zend_hash_has_more_elements(ht) \
|
||||
zend_hash_has_more_elements_ex(ht, &(ht)->nInternalPointer)
|
||||
#define zend_hash_move_forward(ht) \
|
||||
@@ -234,6 +225,21 @@ void zend_hash_display(const HashTable *ht);
|
||||
|
||||
ZEND_API int _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx);
|
||||
|
||||
|
||||
ZEND_API uint32_t zend_hash_iterator_add(HashTable *ht, HashPosition pos);
|
||||
ZEND_API HashPosition zend_hash_iterator_pos(uint32_t idx, HashTable *ht);
|
||||
ZEND_API void zend_hash_iterator_del(uint32_t idx);
|
||||
ZEND_API HashPosition zend_hash_iterators_lower_pos(HashTable *ht, HashPosition start);
|
||||
ZEND_API void _zend_hash_iterators_update(HashTable *ht, HashPosition from, HashPosition to);
|
||||
|
||||
static zend_always_inline void zend_hash_iterators_update(HashTable *ht, HashPosition from, HashPosition to)
|
||||
{
|
||||
if (UNEXPECTED(ht->u.v.nIteratorsCount)) {
|
||||
_zend_hash_iterators_update(ht, from, to);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
END_EXTERN_C()
|
||||
|
||||
#define ZEND_INIT_SYMTABLE(ht) \
|
||||
|
||||
+4
-2
@@ -766,8 +766,10 @@ ZEND_API int pass_two(zend_op_array *op_array)
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
case ZEND_NEW:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
|
||||
break;
|
||||
case ZEND_VERIFY_RETURN_TYPE:
|
||||
|
||||
+18
-2
@@ -128,6 +128,8 @@ struct _zval_struct {
|
||||
uint32_t cache_slot; /* literal cache slot */
|
||||
uint32_t lineno; /* line number (for ast nodes) */
|
||||
uint32_t num_args; /* arguments number for EX(This) */
|
||||
uint32_t fe_pos; /* foreach position */
|
||||
uint32_t fe_iter_idx; /* foreach iterator index */
|
||||
} u2;
|
||||
};
|
||||
|
||||
@@ -160,10 +162,11 @@ typedef struct _Bucket {
|
||||
typedef struct _HashTable {
|
||||
union {
|
||||
struct {
|
||||
ZEND_ENDIAN_LOHI_3(
|
||||
ZEND_ENDIAN_LOHI_4(
|
||||
zend_uchar flags,
|
||||
zend_uchar nApplyCount,
|
||||
uint16_t reserve)
|
||||
zend_uchar nIteratorsCount,
|
||||
zend_uchar reserve)
|
||||
} v;
|
||||
uint32_t flags;
|
||||
} u;
|
||||
@@ -178,6 +181,13 @@ typedef struct _HashTable {
|
||||
dtor_func_t pDestructor;
|
||||
} HashTable;
|
||||
|
||||
typedef uint32_t HashPosition;
|
||||
|
||||
typedef struct _HashTableIterator {
|
||||
HashTable *ht;
|
||||
HashPosition pos;
|
||||
} HashTableIterator;
|
||||
|
||||
struct _zend_array {
|
||||
zend_refcounted gc;
|
||||
HashTable ht;
|
||||
@@ -261,6 +271,12 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
|
||||
#define Z_CACHE_SLOT(zval) (zval).u2.cache_slot
|
||||
#define Z_CACHE_SLOT_P(zval_p) Z_CACHE_SLOT(*(zval_p))
|
||||
|
||||
#define Z_FE_POS(zval) (zval).u2.fe_pos
|
||||
#define Z_FE_POS_P(zval_p) Z_FE_POS(*(zval_p))
|
||||
|
||||
#define Z_FE_ITER(zval) (zval).u2.fe_iter_idx
|
||||
#define Z_FE_ITER_P(zval_p) Z_FE_ITER(*(zval_p))
|
||||
|
||||
#define Z_COUNTED(zval) (zval).value.counted
|
||||
#define Z_COUNTED_P(zval_p) Z_COUNTED(*(zval_p))
|
||||
|
||||
|
||||
+515
-302
@@ -2138,6 +2138,21 @@ ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, ANY)
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY)
|
||||
{
|
||||
zval *var;
|
||||
USE_OPLINE
|
||||
|
||||
SAVE_OPLINE();
|
||||
var = EX_VAR(opline->op1.var);
|
||||
if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
|
||||
zend_hash_iterator_del(Z_FE_ITER_P(var));
|
||||
}
|
||||
zval_ptr_dtor_nogc(var);
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(54, ZEND_ADD_CHAR, TMP|UNUSED, CONST)
|
||||
{
|
||||
USE_OPLINE
|
||||
@@ -3821,6 +3836,14 @@ ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST)
|
||||
if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
|
||||
zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
|
||||
}
|
||||
} else if (brk_opline->opcode == ZEND_FE_FREE) {
|
||||
if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
|
||||
zval *var = EX_VAR(brk_opline->op1.var);
|
||||
if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
|
||||
zend_hash_iterator_del(Z_FE_ITER_P(var));
|
||||
}
|
||||
zval_ptr_dtor_nogc(var);
|
||||
}
|
||||
}
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op1));
|
||||
}
|
||||
@@ -4620,245 +4643,296 @@ ZEND_VM_HANDLER(76, ZEND_UNSET_OBJ, VAR|UNUSED|CV, CONST|TMPVAR|CV)
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
|
||||
ZEND_VM_HANDLER(77, ZEND_FE_RESET_R, CONST|TMP|VAR|CV, ANY)
|
||||
{
|
||||
USE_OPLINE
|
||||
zend_free_op free_op1;
|
||||
zval *array_ptr, *array_ref, iterator, tmp;
|
||||
zval *array_ptr, *result;
|
||||
HashTable *fe_ht;
|
||||
zend_object_iterator *iter = NULL;
|
||||
zend_class_entry *ce = NULL;
|
||||
zend_bool is_empty = 0;
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) &&
|
||||
(opline->extended_value & ZEND_FE_FETCH_BYREF)) {
|
||||
array_ptr = array_ref = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R);
|
||||
ZVAL_DEREF(array_ptr);
|
||||
if (Z_TYPE_P(array_ptr) == IS_ARRAY) {
|
||||
SEPARATE_ARRAY(array_ptr);
|
||||
if (!Z_ISREF_P(array_ref)) {
|
||||
array_ptr = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
|
||||
if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
|
||||
result = EX_VAR(opline->result.var);
|
||||
ZVAL_COPY_VALUE(result, array_ptr);
|
||||
if (OP1_TYPE != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(result)) {
|
||||
Z_ADDREF_P(array_ptr);
|
||||
}
|
||||
Z_FE_POS_P(result) = 0;
|
||||
|
||||
FREE_OP1_IF_VAR();
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else if (OP1_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
|
||||
if (!Z_OBJCE_P(array_ptr)->get_iterator) {
|
||||
HashPosition pos = 0;
|
||||
Bucket *p;
|
||||
|
||||
result = EX_VAR(opline->result.var);
|
||||
ZVAL_COPY_VALUE(result, array_ptr);
|
||||
if (OP1_TYPE != IS_TMP_VAR) {
|
||||
Z_ADDREF_P(array_ptr);
|
||||
}
|
||||
fe_ht = Z_OBJPROP_P(array_ptr);
|
||||
pos = 0;
|
||||
while (1) {
|
||||
if (pos >= fe_ht->nNumUsed) {
|
||||
FREE_OP1_IF_VAR();
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
if ((Z_TYPE(p->val) != IS_UNDEF &&
|
||||
(Z_TYPE(p->val) != IS_INDIRECT ||
|
||||
Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
|
||||
(!p->key ||
|
||||
zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
fe_ht->nInternalPointer = pos;
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht, pos);
|
||||
|
||||
FREE_OP1_IF_VAR();
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else {
|
||||
zend_class_entry *ce = Z_OBJCE_P(array_ptr);
|
||||
zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 0);
|
||||
zend_bool is_empty;
|
||||
|
||||
if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
|
||||
FREE_OP1();
|
||||
if (!EG(exception)) {
|
||||
zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
|
||||
}
|
||||
zend_throw_exception_internal(NULL);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
iter->index = 0;
|
||||
if (iter->funcs->rewind) {
|
||||
iter->funcs->rewind(iter);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
OBJ_RELEASE(&iter->std);
|
||||
FREE_OP1();
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
}
|
||||
|
||||
is_empty = iter->funcs->valid(iter) != SUCCESS;
|
||||
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
OBJ_RELEASE(&iter->std);
|
||||
FREE_OP1();
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
iter->index = -1; /* will be set to 0 before using next handler */
|
||||
|
||||
ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
|
||||
FREE_OP1();
|
||||
if (is_empty) {
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
} else {
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zend_error(E_WARNING, "Invalid argument supplied for foreach()");
|
||||
ZVAL_UNDEF(EX_VAR(opline->result.var));
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
FREE_OP1();
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, ANY)
|
||||
{
|
||||
USE_OPLINE
|
||||
zend_free_op free_op1;
|
||||
zval *array_ptr, *array_ref;
|
||||
HashTable *fe_ht;
|
||||
HashPosition pos = 0;
|
||||
Bucket *p;
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) {
|
||||
array_ref = array_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R);
|
||||
if (Z_ISREF_P(array_ref)) {
|
||||
array_ptr = Z_REFVAL_P(array_ref);
|
||||
}
|
||||
} else {
|
||||
array_ref = array_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
|
||||
}
|
||||
|
||||
if (EXPECTED(Z_TYPE_P(array_ptr) == IS_ARRAY)) {
|
||||
if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) {
|
||||
if (array_ptr == array_ref) {
|
||||
ZVAL_NEW_REF(array_ref, array_ref);
|
||||
array_ptr = Z_REFVAL_P(array_ref);
|
||||
}
|
||||
if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
|
||||
} else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
|
||||
ce = Z_OBJCE_P(array_ptr);
|
||||
if (ce->get_iterator == NULL) {
|
||||
Z_ADDREF_P(array_ptr);
|
||||
}
|
||||
array_ref = array_ptr;
|
||||
Z_ADDREF_P(array_ref);
|
||||
ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
|
||||
} else {
|
||||
if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref);
|
||||
array_ptr = EX_VAR(opline->result.var);
|
||||
ZVAL_COPY_VALUE(array_ptr, array_ref);
|
||||
}
|
||||
} else {
|
||||
array_ptr = array_ref = GET_OP1_ZVAL_PTR(BP_VAR_R);
|
||||
if (OP1_TYPE & (IS_VAR|IS_CV)) {
|
||||
ZVAL_DEREF(array_ptr);
|
||||
}
|
||||
if (OP1_TYPE == IS_TMP_VAR) {
|
||||
ZVAL_COPY_VALUE(&tmp, array_ptr);
|
||||
if (Z_OPT_IMMUTABLE_P(&tmp)) {
|
||||
zval_copy_ctor_func(&tmp);
|
||||
}
|
||||
array_ref = array_ptr = &tmp;
|
||||
if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
|
||||
ce = Z_OBJCE_P(array_ptr);
|
||||
if (ce && ce->get_iterator) {
|
||||
Z_DELREF_P(array_ref);
|
||||
}
|
||||
}
|
||||
} else if (Z_TYPE_P(array_ptr) == IS_OBJECT) {
|
||||
ce = Z_OBJCE_P(array_ptr);
|
||||
if (!ce->get_iterator) {
|
||||
if (OP1_TYPE == IS_CV) {
|
||||
Z_ADDREF_P(array_ref);
|
||||
}
|
||||
}
|
||||
} else if (Z_IMMUTABLE_P(array_ref)) {
|
||||
if (OP1_TYPE == IS_CV) {
|
||||
zval_copy_ctor_func(array_ref);
|
||||
Z_ADDREF_P(array_ref);
|
||||
} else {
|
||||
ZVAL_COPY_VALUE(&tmp, array_ref);
|
||||
zval_copy_ctor_func(&tmp);
|
||||
array_ptr = array_ref = &tmp;
|
||||
}
|
||||
} else if (Z_REFCOUNTED_P(array_ref)) {
|
||||
if (OP1_TYPE == IS_CONST ||
|
||||
(OP1_TYPE == IS_CV &&
|
||||
!Z_ISREF_P(array_ref) &&
|
||||
Z_REFCOUNT_P(array_ref) > 1) ||
|
||||
(OP1_TYPE == IS_VAR &&
|
||||
!Z_ISREF_P(array_ref) &&
|
||||
Z_REFCOUNT_P(array_ref) > 2)) {
|
||||
if (OP1_TYPE == IS_VAR) {
|
||||
Z_DELREF_P(array_ref);
|
||||
}
|
||||
ZVAL_DUP(&tmp, array_ref);
|
||||
array_ptr = array_ref = &tmp;
|
||||
} else if (OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) {
|
||||
if (Z_ISREF_P(array_ref) && Z_REFCOUNT_P(array_ref) == 1) {
|
||||
ZVAL_UNREF(array_ref);
|
||||
array_ptr = array_ref;
|
||||
}
|
||||
if (Z_IMMUTABLE_P(array_ptr)) {
|
||||
zval_copy_ctor_func(array_ptr);
|
||||
} else if (Z_ISREF_P(array_ref) &&
|
||||
Z_COPYABLE_P(array_ptr) &&
|
||||
Z_REFCOUNT_P(array_ptr) > 1) {
|
||||
Z_DELREF_P(array_ptr);
|
||||
zval_copy_ctor_func(array_ptr);
|
||||
}
|
||||
if (OP1_TYPE == IS_CV) {
|
||||
Z_ADDREF_P(array_ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ce && ce->get_iterator) {
|
||||
iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_FETCH_BYREF);
|
||||
|
||||
if (OP1_TYPE == IS_VAR && !(opline->extended_value & ZEND_FE_FETCH_BYREF)) {
|
||||
FREE_OP1_IF_VAR();
|
||||
}
|
||||
if (iter && EXPECTED(EG(exception) == NULL)) {
|
||||
ZVAL_OBJ(&iterator, &iter->std);
|
||||
array_ptr = array_ref = &iterator;
|
||||
if (OP1_TYPE == IS_CONST) {
|
||||
zval_copy_ctor_func(array_ptr);
|
||||
} else {
|
||||
if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
}
|
||||
if (!EG(exception)) {
|
||||
zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
|
||||
}
|
||||
zend_throw_exception_internal(NULL);
|
||||
HANDLE_EXCEPTION();
|
||||
SEPARATE_ARRAY(array_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
|
||||
|
||||
if (iter) {
|
||||
iter->index = 0;
|
||||
if (iter->funcs->rewind) {
|
||||
iter->funcs->rewind(iter);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array_ref);
|
||||
if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
}
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
}
|
||||
is_empty = iter->funcs->valid(iter) != SUCCESS;
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array_ref);
|
||||
if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
}
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
iter->index = -1; /* will be set to 0 before using next handler */
|
||||
} else if ((fe_ht = HASH_OF(array_ptr)) != NULL) {
|
||||
HashPointer *ptr = (HashPointer*)EX_VAR((opline+2)->op1.var);
|
||||
HashPosition pos = 0;
|
||||
Bucket *p;
|
||||
|
||||
fe_ht = Z_ARRVAL_P(array_ptr);
|
||||
while (1) {
|
||||
if (pos >= fe_ht->nNumUsed) {
|
||||
is_empty = 1;
|
||||
if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
}
|
||||
FREE_OP1_VAR_PTR();
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
if (Z_TYPE(p->val) == IS_UNDEF ||
|
||||
(Z_TYPE(p->val) == IS_INDIRECT &&
|
||||
Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF)) {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
if (!ce ||
|
||||
!p->key ||
|
||||
zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS) {
|
||||
if (Z_TYPE(p->val) != IS_UNDEF &&
|
||||
(Z_TYPE(p->val) != IS_INDIRECT ||
|
||||
Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
fe_ht->nInternalPointer = pos;
|
||||
ptr->pos = pos;
|
||||
ptr->ht = fe_ht;
|
||||
ptr->h = fe_ht->arData[pos].h;
|
||||
ptr->key = fe_ht->arData[pos].key;
|
||||
is_empty = 0;
|
||||
} else {
|
||||
zend_error(E_WARNING, "Invalid argument supplied for foreach()");
|
||||
is_empty = 1;
|
||||
}
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht, pos);
|
||||
|
||||
if (OP1_TYPE == IS_VAR && opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
}
|
||||
if (is_empty) {
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
} else {
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else if (OP1_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) {
|
||||
if (!Z_OBJCE_P(array_ptr)->get_iterator) {
|
||||
if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) {
|
||||
if (array_ptr == array_ref) {
|
||||
ZVAL_NEW_REF(array_ref, array_ref);
|
||||
array_ptr = Z_REFVAL_P(array_ref);
|
||||
}
|
||||
Z_ADDREF_P(array_ref);
|
||||
ZVAL_COPY_VALUE(EX_VAR(opline->result.var), array_ref);
|
||||
} else {
|
||||
array_ptr = EX_VAR(opline->result.var);
|
||||
ZVAL_COPY_VALUE(array_ptr, array_ref);
|
||||
}
|
||||
fe_ht = Z_OBJPROP_P(array_ptr);
|
||||
while (1) {
|
||||
if (pos >= fe_ht->nNumUsed) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
if ((Z_TYPE(p->val) != IS_UNDEF &&
|
||||
(Z_TYPE(p->val) != IS_INDIRECT ||
|
||||
Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
|
||||
(!p->key ||
|
||||
zend_check_property_access(Z_OBJ_P(array_ptr), p->key) == SUCCESS)) {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
fe_ht->nInternalPointer = pos;
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(fe_ht, pos);
|
||||
|
||||
FREE_OP1_VAR_PTR();
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else {
|
||||
zend_class_entry *ce = Z_OBJCE_P(array_ptr);
|
||||
zend_object_iterator *iter = ce->get_iterator(ce, array_ptr, 1);
|
||||
zend_bool is_empty;
|
||||
|
||||
if (UNEXPECTED(!iter) || UNEXPECTED(EG(exception))) {
|
||||
if (OP1_TYPE == IS_VAR) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
} else {
|
||||
FREE_OP1();
|
||||
}
|
||||
if (!EG(exception)) {
|
||||
zend_throw_exception_ex(NULL, 0, "Object of type %s did not create an Iterator", ce->name->val);
|
||||
}
|
||||
zend_throw_exception_internal(NULL);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
iter->index = 0;
|
||||
if (iter->funcs->rewind) {
|
||||
iter->funcs->rewind(iter);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
OBJ_RELEASE(&iter->std);
|
||||
if (OP1_TYPE == IS_VAR) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
} else {
|
||||
FREE_OP1();
|
||||
}
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
}
|
||||
|
||||
is_empty = iter->funcs->valid(iter) != SUCCESS;
|
||||
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
OBJ_RELEASE(&iter->std);
|
||||
if (OP1_TYPE == IS_VAR) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
} else {
|
||||
FREE_OP1();
|
||||
}
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
iter->index = -1; /* will be set to 0 before using next handler */
|
||||
|
||||
ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std);
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
|
||||
if (OP1_TYPE == IS_VAR) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
} else {
|
||||
FREE_OP1();
|
||||
}
|
||||
if (is_empty) {
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
} else {
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zend_error(E_WARNING, "Invalid argument supplied for foreach()");
|
||||
ZVAL_UNDEF(EX_VAR(opline->result.var));
|
||||
Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;
|
||||
if (OP1_TYPE == IS_VAR) {
|
||||
FREE_OP1_VAR_PTR();
|
||||
} else {
|
||||
FREE_OP1();
|
||||
}
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
|
||||
ZEND_VM_HANDLER(78, ZEND_FE_FETCH_R, VAR, ANY)
|
||||
{
|
||||
USE_OPLINE
|
||||
zend_free_op free_op1;
|
||||
zval *array, *array_ref;
|
||||
zval *array;
|
||||
zval *value;
|
||||
HashTable *fe_ht;
|
||||
HashPointer *ptr;
|
||||
HashPosition pos;
|
||||
Bucket *p;
|
||||
|
||||
array = array_ref = EX_VAR(opline->op1.var);
|
||||
if (Z_ISREF_P(array)) {
|
||||
array = Z_REFVAL_P(array);
|
||||
// TODO: referenced value might be changed to different array ???
|
||||
if (Z_IMMUTABLE_P(array)) {
|
||||
zval_copy_ctor_func(array);
|
||||
}
|
||||
}
|
||||
|
||||
array = EX_VAR(opline->op1.var);
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) {
|
||||
fe_ht = Z_ARRVAL_P(array);
|
||||
ptr = (HashPointer*)EX_VAR((opline+1)->op1.var);
|
||||
pos = ptr->pos;
|
||||
if (UNEXPECTED(pos == INVALID_IDX)) {
|
||||
/* reached end of iteration */
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
} else if (UNEXPECTED(ptr->ht != fe_ht)) {
|
||||
ptr->ht = fe_ht;
|
||||
pos = 0;
|
||||
} else if (UNEXPECTED(fe_ht->nInternalPointer != ptr->pos)) {
|
||||
if (fe_ht->u.flags & HASH_FLAG_PACKED) {
|
||||
pos = ptr->h;
|
||||
} else {
|
||||
pos = fe_ht->arHash[ptr->h & fe_ht->nTableMask];
|
||||
while (1) {
|
||||
if (pos == INVALID_IDX) {
|
||||
pos = fe_ht->nInternalPointer;
|
||||
break;
|
||||
} else if (fe_ht->arData[pos].h == ptr->h && fe_ht->arData[pos].key == ptr->key) {
|
||||
break;
|
||||
}
|
||||
pos = Z_NEXT(fe_ht->arData[pos].val);
|
||||
}
|
||||
}
|
||||
}
|
||||
pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
|
||||
while (1) {
|
||||
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
|
||||
/* reached end of iteration */
|
||||
@@ -4866,46 +4940,27 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
value = &p->val;
|
||||
if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
} else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
|
||||
} else if (Z_TYPE_P(value) == IS_INDIRECT) {
|
||||
value = Z_INDIRECT_P(value);
|
||||
if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
ZVAL_MAKE_REF(value);
|
||||
Z_ADDREF_P(value);
|
||||
ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
|
||||
} else {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), value);
|
||||
}
|
||||
if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
|
||||
if (!p->key) {
|
||||
ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
|
||||
} else {
|
||||
ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
do {
|
||||
pos++;
|
||||
if (pos >= fe_ht->nNumUsed) {
|
||||
fe_ht->nInternalPointer = ptr->pos = INVALID_IDX;
|
||||
ZEND_VM_INC_OPCODE();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
if (opline->extended_value) {
|
||||
if (!p->key) {
|
||||
ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
|
||||
} else {
|
||||
ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
} while (Z_TYPE(p->val) == IS_UNDEF ||
|
||||
(Z_TYPE(p->val) == IS_INDIRECT &&
|
||||
Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF));
|
||||
fe_ht->nInternalPointer = ptr->pos = pos;
|
||||
ptr->h = fe_ht->arData[pos].h;
|
||||
ptr->key = fe_ht->arData[pos].key;
|
||||
}
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), value);
|
||||
Z_FE_POS_P(EX_VAR(opline->op1.var)) = pos + 1;
|
||||
ZEND_VM_INC_OPCODE();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
|
||||
@@ -4916,30 +4971,7 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
|
||||
zend_object *zobj = Z_OBJ_P(array);
|
||||
|
||||
fe_ht = Z_OBJPROP_P(array);
|
||||
ptr = (HashPointer*)EX_VAR((opline+1)->op1.var);
|
||||
pos = ptr->pos;
|
||||
if (pos == INVALID_IDX) {
|
||||
/* reached end of iteration */
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
} else if (UNEXPECTED(ptr->ht != fe_ht)) {
|
||||
ptr->ht = fe_ht;
|
||||
pos = 0;
|
||||
} else if (UNEXPECTED(fe_ht->nInternalPointer != ptr->pos)) {
|
||||
if (fe_ht->u.flags & HASH_FLAG_PACKED) {
|
||||
pos = ptr->h;
|
||||
} else {
|
||||
pos = fe_ht->arHash[ptr->h & fe_ht->nTableMask];
|
||||
while (1) {
|
||||
if (pos == INVALID_IDX) {
|
||||
pos = fe_ht->nInternalPointer;
|
||||
break;
|
||||
} else if (fe_ht->arData[pos].h == ptr->h && fe_ht->arData[pos].key == ptr->key) {
|
||||
break;
|
||||
}
|
||||
pos = Z_NEXT(fe_ht->arData[pos].val);
|
||||
}
|
||||
}
|
||||
}
|
||||
pos = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
|
||||
while (1) {
|
||||
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
|
||||
/* reached end of iteration */
|
||||
@@ -4948,61 +4980,54 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
|
||||
|
||||
p = fe_ht->arData + pos;
|
||||
value = &p->val;
|
||||
if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
} else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
|
||||
} else if (Z_TYPE_P(value) == IS_INDIRECT) {
|
||||
value = Z_INDIRECT_P(value);
|
||||
if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (UNEXPECTED(!p->key)) {
|
||||
if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
|
||||
ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
|
||||
}
|
||||
break;
|
||||
} else if (zend_check_property_access(zobj, p->key) == SUCCESS) {
|
||||
if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
|
||||
if (p->key->val[0]) {
|
||||
ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
|
||||
} else {
|
||||
const char *class_name, *prop_name;
|
||||
size_t prop_name_len;
|
||||
zend_unmangle_property_name_ex(
|
||||
p->key, &class_name, &prop_name, &prop_name_len);
|
||||
ZVAL_STRINGL(EX_VAR((opline+1)->result.var), prop_name, prop_name_len);
|
||||
}
|
||||
}
|
||||
if (!p->key ||
|
||||
zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS) {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
if (opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
ZVAL_MAKE_REF(value);
|
||||
Z_ADDREF_P(value);
|
||||
ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
|
||||
} else {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), value);
|
||||
if (opline->extended_value) {
|
||||
if (UNEXPECTED(!p->key)) {
|
||||
ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
|
||||
} else if (p->key->val[0]) {
|
||||
ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
|
||||
} else {
|
||||
const char *class_name, *prop_name;
|
||||
size_t prop_name_len;
|
||||
zend_unmangle_property_name_ex(
|
||||
p->key, &class_name, &prop_name, &prop_name_len);
|
||||
ZVAL_STRINGL(EX_VAR((opline+1)->result.var), prop_name, prop_name_len);
|
||||
}
|
||||
}
|
||||
do {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), value);
|
||||
while (1) {
|
||||
pos++;
|
||||
if (pos >= fe_ht->nNumUsed) {
|
||||
fe_ht->nInternalPointer = ptr->pos = INVALID_IDX;
|
||||
ZEND_VM_INC_OPCODE();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
pos = INVALID_IDX;
|
||||
break;
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
} while (Z_TYPE(p->val) == IS_UNDEF ||
|
||||
(Z_TYPE(p->val) == IS_INDIRECT &&
|
||||
Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF) ||
|
||||
(EXPECTED(p->key != NULL) &&
|
||||
zend_check_property_access(zobj, p->key) == FAILURE));
|
||||
fe_ht->nInternalPointer = ptr->pos = pos;
|
||||
ptr->h = fe_ht->arData[pos].h;
|
||||
ptr->key = fe_ht->arData[pos].key;
|
||||
if ((Z_TYPE(p->val) != IS_UNDEF &&
|
||||
(Z_TYPE(p->val) != IS_INDIRECT ||
|
||||
Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
|
||||
(Z_TYPE_P(array) != IS_OBJECT ||
|
||||
!p->key ||
|
||||
zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos =
|
||||
fe_ht->nInternalPointer = pos;
|
||||
ZEND_VM_INC_OPCODE();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else {
|
||||
@@ -5012,7 +5037,7 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
|
||||
* In case that ever happens we need an additional flag. */
|
||||
iter->funcs->move_forward(iter);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array_ref);
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
}
|
||||
@@ -5020,32 +5045,26 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
|
||||
if (!iter || (iter->index > 0 && iter->funcs->valid(iter) == FAILURE)) {
|
||||
/* reached end of iteration */
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array_ref);
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
value = iter->funcs->get_current_data(iter);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array_ref);
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
if (!value) {
|
||||
/* failure in get_current_data */
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
if (opline->extended_value & ZEND_FE_FETCH_BYREF) {
|
||||
ZVAL_MAKE_REF(value);
|
||||
Z_ADDREF_P(value);
|
||||
ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
|
||||
} else {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), value);
|
||||
}
|
||||
if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), value);
|
||||
if (opline->extended_value) {
|
||||
if (iter->funcs->get_current_key) {
|
||||
iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array_ref);
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} else {
|
||||
@@ -5061,6 +5080,192 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
|
||||
{
|
||||
USE_OPLINE
|
||||
zend_free_op free_op1;
|
||||
zval *array;
|
||||
zval *value;
|
||||
HashTable *fe_ht;
|
||||
HashPosition pos;
|
||||
Bucket *p;
|
||||
|
||||
array = EX_VAR(opline->op1.var);
|
||||
SAVE_OPLINE();
|
||||
|
||||
ZVAL_DEREF(array);
|
||||
if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) {
|
||||
fe_ht = Z_ARRVAL_P(array);
|
||||
pos = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
|
||||
while (1) {
|
||||
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
|
||||
/* reached end of iteration */
|
||||
fe_ht->nInternalPointer = INVALID_IDX;
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
value = &p->val;
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
} else if (Z_TYPE_P(value) == IS_INDIRECT) {
|
||||
value = Z_INDIRECT_P(value);
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (opline->extended_value) {
|
||||
if (!p->key) {
|
||||
ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
|
||||
} else {
|
||||
ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
|
||||
}
|
||||
}
|
||||
ZVAL_MAKE_REF(value);
|
||||
Z_ADDREF_P(value);
|
||||
ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
|
||||
while (1) {
|
||||
pos++;
|
||||
if (pos >= fe_ht->nNumUsed) {
|
||||
pos = INVALID_IDX;
|
||||
break;
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
if (Z_TYPE(p->val) != IS_UNDEF &&
|
||||
(Z_TYPE(p->val) != IS_INDIRECT ||
|
||||
Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos =
|
||||
fe_ht->nInternalPointer = pos;
|
||||
ZEND_VM_INC_OPCODE();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
|
||||
zend_object_iterator *iter;
|
||||
|
||||
if ((iter = zend_iterator_unwrap(array)) == NULL) {
|
||||
/* plain object */
|
||||
zend_object *zobj = Z_OBJ_P(array);
|
||||
|
||||
fe_ht = Z_OBJPROP_P(array);
|
||||
pos = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
|
||||
while (1) {
|
||||
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
|
||||
/* reached end of iteration */
|
||||
fe_ht->nInternalPointer = INVALID_IDX;
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
|
||||
p = fe_ht->arData + pos;
|
||||
value = &p->val;
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
} else if (Z_TYPE_P(value) == IS_INDIRECT) {
|
||||
value = Z_INDIRECT_P(value);
|
||||
if (Z_TYPE_P(value) == IS_UNDEF) {
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!p->key ||
|
||||
zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS) {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
if (opline->extended_value) {
|
||||
if (UNEXPECTED(!p->key)) {
|
||||
ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
|
||||
} else if (p->key->val[0]) {
|
||||
ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
|
||||
} else {
|
||||
const char *class_name, *prop_name;
|
||||
size_t prop_name_len;
|
||||
zend_unmangle_property_name_ex(
|
||||
p->key, &class_name, &prop_name, &prop_name_len);
|
||||
ZVAL_STRINGL(EX_VAR((opline+1)->result.var), prop_name, prop_name_len);
|
||||
}
|
||||
}
|
||||
ZVAL_MAKE_REF(value);
|
||||
Z_ADDREF_P(value);
|
||||
ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
|
||||
while (1) {
|
||||
pos++;
|
||||
if (pos >= fe_ht->nNumUsed) {
|
||||
pos = INVALID_IDX;
|
||||
break;
|
||||
}
|
||||
p = fe_ht->arData + pos;
|
||||
if ((Z_TYPE(p->val) != IS_UNDEF &&
|
||||
(Z_TYPE(p->val) != IS_INDIRECT ||
|
||||
Z_TYPE_P(Z_INDIRECT(p->val)) != IS_UNDEF)) &&
|
||||
(Z_TYPE_P(array) != IS_OBJECT ||
|
||||
!p->key ||
|
||||
zend_check_property_access(Z_OBJ_P(array), p->key) == SUCCESS)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos =
|
||||
fe_ht->nInternalPointer = pos;
|
||||
ZEND_VM_INC_OPCODE();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
} else {
|
||||
/* !iter happens from exception */
|
||||
if (iter && ++iter->index > 0) {
|
||||
/* This could cause an endless loop if index becomes zero again.
|
||||
* In case that ever happens we need an additional flag. */
|
||||
iter->funcs->move_forward(iter);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
}
|
||||
/* If index is zero we come from FE_RESET and checked valid() already. */
|
||||
if (!iter || (iter->index > 0 && iter->funcs->valid(iter) == FAILURE)) {
|
||||
/* reached end of iteration */
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
value = iter->funcs->get_current_data(iter);
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
if (!value) {
|
||||
/* failure in get_current_data */
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
if (opline->extended_value) {
|
||||
if (iter->funcs->get_current_key) {
|
||||
iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zval_ptr_dtor(array);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} else {
|
||||
ZVAL_LONG(EX_VAR((opline+1)->result.var), iter->index);
|
||||
}
|
||||
}
|
||||
ZVAL_MAKE_REF(value);
|
||||
Z_ADDREF_P(value);
|
||||
ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
|
||||
ZEND_VM_INC_OPCODE();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
} else {
|
||||
zend_error(E_WARNING, "Invalid argument supplied for foreach()");
|
||||
ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
|
||||
{
|
||||
USE_OPLINE
|
||||
@@ -5840,6 +6045,14 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
|
||||
if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
|
||||
zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
|
||||
}
|
||||
} else if (brk_opline->opcode == ZEND_FE_FREE) {
|
||||
if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
|
||||
zval *var = EX_VAR(brk_opline->op1.var);
|
||||
if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
|
||||
zend_hash_iterator_del(Z_FE_ITER_P(var));
|
||||
}
|
||||
zval_ptr_dtor_nogc(var);
|
||||
}
|
||||
} else if (brk_opline->opcode == ZEND_END_SILENCE) {
|
||||
/* restore previous error_reporting value */
|
||||
if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(brk_opline->op1.var)) != 0) {
|
||||
|
||||
+1293
-842
File diff suppressed because it is too large.
Load diff
@@ -99,8 +99,8 @@ const char *zend_vm_opcodes_map[170] = {
|
||||
"ZEND_UNSET_VAR",
|
||||
"ZEND_UNSET_DIM",
|
||||
"ZEND_UNSET_OBJ",
|
||||
"ZEND_FE_RESET",
|
||||
"ZEND_FE_FETCH",
|
||||
"ZEND_FE_RESET_R",
|
||||
"ZEND_FE_FETCH_R",
|
||||
"ZEND_EXIT",
|
||||
"ZEND_FETCH_R",
|
||||
"ZEND_FETCH_DIM_R",
|
||||
@@ -147,9 +147,9 @@ const char *zend_vm_opcodes_map[170] = {
|
||||
"ZEND_DEFINED",
|
||||
"ZEND_TYPE_CHECK",
|
||||
"ZEND_VERIFY_RETURN_TYPE",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
"ZEND_FE_RESET_RW",
|
||||
"ZEND_FE_FETCH_RW",
|
||||
"ZEND_FE_FREE",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
@@ -101,8 +101,8 @@ END_EXTERN_C()
|
||||
#define ZEND_UNSET_VAR 74
|
||||
#define ZEND_UNSET_DIM 75
|
||||
#define ZEND_UNSET_OBJ 76
|
||||
#define ZEND_FE_RESET 77
|
||||
#define ZEND_FE_FETCH 78
|
||||
#define ZEND_FE_RESET_R 77
|
||||
#define ZEND_FE_FETCH_R 78
|
||||
#define ZEND_EXIT 79
|
||||
#define ZEND_FETCH_R 80
|
||||
#define ZEND_FETCH_DIM_R 81
|
||||
@@ -149,6 +149,9 @@ END_EXTERN_C()
|
||||
#define ZEND_DEFINED 122
|
||||
#define ZEND_TYPE_CHECK 123
|
||||
#define ZEND_VERIFY_RETURN_TYPE 124
|
||||
#define ZEND_FE_RESET_RW 125
|
||||
#define ZEND_FE_FETCH_RW 126
|
||||
#define ZEND_FE_FREE 127
|
||||
#define ZEND_PRE_INC_OBJ 132
|
||||
#define ZEND_PRE_DEC_OBJ 133
|
||||
#define ZEND_POST_INC_OBJ 134
|
||||
|
||||
@@ -166,14 +166,16 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
|
||||
case ZEND_JMPNZ:
|
||||
case ZEND_JMPZ_EX:
|
||||
case ZEND_JMPNZ_EX:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_NEW:
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
START_BLOCK_OP(ZEND_OP2(opline).opline_num);
|
||||
START_BLOCK_OP(opno + 1);
|
||||
break;
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
START_BLOCK_OP(ZEND_OP2(opline).opline_num);
|
||||
START_BLOCK_OP(opno + 2);
|
||||
break;
|
||||
@@ -205,12 +207,15 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
|
||||
for (i = 0; i< op_array->last_brk_cont; i++) {
|
||||
if (op_array->brk_cont_array[i].start >= 0 &&
|
||||
(op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
|
||||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE ||
|
||||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) {
|
||||
int parent = op_array->brk_cont_array[i].parent;
|
||||
|
||||
while (parent >= 0 &&
|
||||
op_array->brk_cont_array[parent].start < 0 &&
|
||||
op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FREE) {
|
||||
(op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FREE ||
|
||||
op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_FE_FREE ||
|
||||
op_array->opcodes[op_array->brk_cont_array[parent].brk].opcode != ZEND_END_SILENCE)) {
|
||||
parent = op_array->brk_cont_array[parent].parent;
|
||||
}
|
||||
op_array->brk_cont_array[i].parent = parent;
|
||||
@@ -225,6 +230,7 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
|
||||
for (i = 0; i< op_array->last_brk_cont; i++) {
|
||||
if (op_array->brk_cont_array[i].start >= 0 &&
|
||||
(op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
|
||||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FE_FREE ||
|
||||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) {
|
||||
if (i != j) {
|
||||
op_array->brk_cont_array[j] = op_array->brk_cont_array[i];
|
||||
@@ -293,11 +299,13 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
|
||||
case ZEND_JMPNZ:
|
||||
case ZEND_JMPZ_EX:
|
||||
case ZEND_JMPNZ_EX:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_NEW:
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
cur_block->op2_to = &blocks[ZEND_OP2(opline).opline_num];
|
||||
/* break missing intentionally */
|
||||
default:
|
||||
@@ -619,7 +627,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
|
||||
ZEND_OP1_TYPE(VAR_SOURCE(opline->op1)) == IS_CONST &&
|
||||
opline->opcode != ZEND_CASE && /* CASE _always_ expects variable */
|
||||
opline->opcode != ZEND_FETCH_LIST &&
|
||||
opline->opcode != ZEND_FE_RESET &&
|
||||
(opline->opcode != ZEND_FE_RESET_R || opline->opcode != ZEND_FE_RESET_RW) &&
|
||||
opline->opcode != ZEND_FREE
|
||||
) {
|
||||
zend_op *src = VAR_SOURCE(opline->op1);
|
||||
|
||||
@@ -93,8 +93,10 @@ void zend_optimizer_nop_removal(zend_op_array *op_array)
|
||||
case ZEND_JMPNZ:
|
||||
case ZEND_JMPZ_EX:
|
||||
case ZEND_JMPNZ_EX:
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_NEW:
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
|
||||
@@ -66,16 +66,6 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c
|
||||
if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
|
||||
start_of_T[VAR_NUM(ZEND_RESULT(opline).var) - offset] = opline;
|
||||
}
|
||||
/* special puprose variable to keep HashPointer on VM stack */
|
||||
if (opline->opcode == ZEND_OP_DATA &&
|
||||
(opline-1)->opcode == ZEND_FE_FETCH &&
|
||||
opline->op1_type == IS_TMP_VAR) {
|
||||
start_of_T[VAR_NUM(ZEND_OP1(opline).var) - offset] = opline;
|
||||
if (sizeof(HashPointer) > sizeof(zval)) {
|
||||
/* Make shure 1 zval is enough for HashPointer (2 must be enough) */
|
||||
start_of_T[VAR_NUM(ZEND_OP1(opline).var) + 1 - offset] = opline;
|
||||
}
|
||||
}
|
||||
opline--;
|
||||
}
|
||||
|
||||
@@ -88,25 +78,13 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c
|
||||
while (opline >= end) {
|
||||
if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) {
|
||||
|
||||
/* special puprose variable to keep HashPointer on VM stack */
|
||||
if (opline->opcode == ZEND_OP_DATA &&
|
||||
(opline-1)->opcode == ZEND_FE_FETCH &&
|
||||
opline->op1_type == IS_TMP_VAR) {
|
||||
max++;
|
||||
ZEND_OP1(opline).var = NUM_VAR(max + offset);
|
||||
if (sizeof(HashPointer) > sizeof(zval)) {
|
||||
/* Make shure 1 zval is enough for HashPointer (2 must be enough) */
|
||||
max++;
|
||||
}
|
||||
} else {
|
||||
currT = VAR_NUM(ZEND_OP1(opline).var) - offset;
|
||||
if (!valid_T[currT]) {
|
||||
GET_AVAILABLE_T();
|
||||
map_T[currT] = i;
|
||||
valid_T[currT] = 1;
|
||||
}
|
||||
ZEND_OP1(opline).var = NUM_VAR(map_T[currT] + offset);
|
||||
currT = VAR_NUM(ZEND_OP1(opline).var) - offset;
|
||||
if (!valid_T[currT]) {
|
||||
GET_AVAILABLE_T();
|
||||
map_T[currT] = i;
|
||||
valid_T[currT] = 1;
|
||||
}
|
||||
ZEND_OP1(opline).var = NUM_VAR(map_T[currT] + offset);
|
||||
}
|
||||
|
||||
/* Skip OP_DATA */
|
||||
|
||||
@@ -602,8 +602,10 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
|
||||
case ZEND_JMPNZ:
|
||||
case ZEND_JMPZ_EX:
|
||||
case ZEND_JMPNZ_EX:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
case ZEND_NEW:
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
|
||||
@@ -203,7 +203,9 @@ void zend_optimizer_pass2(zend_op_array *op_array)
|
||||
jmp_to = &op_array->brk_cont_array[array_offset];
|
||||
array_offset = jmp_to->parent;
|
||||
if (--nest_levels > 0) {
|
||||
if (op_array->opcodes[jmp_to->brk].opcode == ZEND_FREE) {
|
||||
if (op_array->opcodes[jmp_to->brk].opcode == ZEND_FREE ||
|
||||
op_array->opcodes[jmp_to->brk].opcode == ZEND_FE_FREE ||
|
||||
op_array->opcodes[jmp_to->brk].opcode == ZEND_END_SILENCE) {
|
||||
dont_optimize = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -328,7 +328,8 @@ continue_jmp_ex_optimization:
|
||||
op->opcode == ZEND_RETURN ||
|
||||
op->opcode == ZEND_RETURN_BY_REF ||
|
||||
op->opcode == ZEND_FAST_RET ||
|
||||
op->opcode == ZEND_FE_FETCH ||
|
||||
op->opcode == ZEND_FE_FETCH_R ||
|
||||
op->opcode == ZEND_FE_FETCH_RW ||
|
||||
op->opcode == ZEND_EXIT) {
|
||||
break;
|
||||
}
|
||||
@@ -363,7 +364,8 @@ continue_jmp_ex_optimization:
|
||||
op->opcode == ZEND_RETURN ||
|
||||
op->opcode == ZEND_RETURN_BY_REF ||
|
||||
op->opcode == ZEND_FAST_RET ||
|
||||
op->opcode == ZEND_FE_FETCH ||
|
||||
op->opcode == ZEND_FE_FETCH_R ||
|
||||
op->opcode == ZEND_FE_FETCH_RW ||
|
||||
op->opcode == ZEND_EXIT) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -450,8 +450,10 @@ static void zend_accel_optimize(zend_op_array *op_array,
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
case ZEND_NEW:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
ZEND_PASS_TWO_UNDO_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
|
||||
break;
|
||||
}
|
||||
@@ -488,8 +490,10 @@ static void zend_accel_optimize(zend_op_array *op_array,
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
case ZEND_NEW:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -378,8 +378,10 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
|
||||
case ZEND_JMP_SET:
|
||||
case ZEND_COALESCE:
|
||||
case ZEND_NEW:
|
||||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_FE_RESET_R:
|
||||
case ZEND_FE_RESET_RW:
|
||||
case ZEND_FE_FETCH_R:
|
||||
case ZEND_FE_FETCH_RW:
|
||||
ZEND_OP2(opline).jmp_addr = &new_opcodes[ZEND_OP2(opline).jmp_addr - op_array->opcodes];
|
||||
break;
|
||||
}
|
||||
|
||||
+151
-40
@@ -1877,26 +1877,54 @@ static void php_array_data_shuffle(zval *array) /* {{{ */
|
||||
hash = Z_ARRVAL_P(array);
|
||||
n_left = n_elems;
|
||||
|
||||
if (hash->nNumUsed != hash->nNumOfElements) {
|
||||
for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
|
||||
p = hash->arData + idx;
|
||||
if (Z_TYPE(p->val) == IS_UNDEF) continue;
|
||||
if (j != idx) {
|
||||
hash->arData[j] = *p;
|
||||
if (EXPECTED(hash->u.v.nIteratorsCount == 0)) {
|
||||
if (hash->nNumUsed != hash->nNumOfElements) {
|
||||
for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
|
||||
p = hash->arData + idx;
|
||||
if (Z_TYPE(p->val) == IS_UNDEF) continue;
|
||||
if (j != idx) {
|
||||
hash->arData[j] = *p;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
while (--n_left) {
|
||||
rnd_idx = php_rand();
|
||||
RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
|
||||
if (rnd_idx != n_left) {
|
||||
temp = hash->arData[n_left];
|
||||
hash->arData[n_left] = hash->arData[rnd_idx];
|
||||
hash->arData[rnd_idx] = temp;
|
||||
while (--n_left) {
|
||||
rnd_idx = php_rand();
|
||||
RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
|
||||
if (rnd_idx != n_left) {
|
||||
temp = hash->arData[n_left];
|
||||
hash->arData[n_left] = hash->arData[rnd_idx];
|
||||
hash->arData[rnd_idx] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint32_t iter_pos = zend_hash_iterators_lower_pos(hash, 0);
|
||||
|
||||
if (hash->nNumUsed != hash->nNumOfElements) {
|
||||
for (j = 0, idx = 0; idx < hash->nNumUsed; idx++) {
|
||||
p = hash->arData + idx;
|
||||
if (Z_TYPE(p->val) == IS_UNDEF) continue;
|
||||
if (j != idx) {
|
||||
hash->arData[j] = *p;
|
||||
if (idx == iter_pos) {
|
||||
zend_hash_iterators_update(hash, idx, j);
|
||||
iter_pos = zend_hash_iterators_lower_pos(hash, iter_pos + 1);
|
||||
}
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
while (--n_left) {
|
||||
rnd_idx = php_rand();
|
||||
RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
|
||||
if (rnd_idx != n_left) {
|
||||
temp = hash->arData[n_left];
|
||||
hash->arData[n_left] = hash->arData[rnd_idx];
|
||||
hash->arData[rnd_idx] = temp;
|
||||
zend_hash_iterators_update(hash, rnd_idx, n_left);
|
||||
}
|
||||
}
|
||||
}
|
||||
HANDLE_BLOCK_INTERRUPTIONS();
|
||||
hash->nNumUsed = n_elems;
|
||||
hash->nInternalPointer = 0;
|
||||
@@ -1941,6 +1969,7 @@ static void php_splice(HashTable *in_hash, int offset, int length, HashTable *re
|
||||
uint idx;
|
||||
Bucket *p; /* Pointer to hash bucket */
|
||||
zval *entry; /* Hash entry */
|
||||
uint32_t iter_pos = zend_hash_iterators_lower_pos(in_hash, 0);
|
||||
|
||||
/* Get number of entries in the input hash */
|
||||
num_in = zend_hash_num_elements(in_hash);
|
||||
@@ -1966,7 +1995,6 @@ static void php_splice(HashTable *in_hash, int offset, int length, HashTable *re
|
||||
for (pos = 0, idx = 0; pos < offset && idx < in_hash->nNumUsed; idx++) {
|
||||
p = in_hash->arData + idx;
|
||||
if (Z_TYPE(p->val) == IS_UNDEF) continue;
|
||||
pos++;
|
||||
/* Get entry and increase reference count */
|
||||
entry = &p->val;
|
||||
|
||||
@@ -1976,6 +2004,13 @@ static void php_splice(HashTable *in_hash, int offset, int length, HashTable *re
|
||||
} else {
|
||||
zend_hash_add_new(&out_hash, p->key, entry);
|
||||
}
|
||||
if (idx == iter_pos) {
|
||||
if (idx != pos) {
|
||||
zend_hash_iterators_update(in_hash, idx, pos);
|
||||
}
|
||||
iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos + 1);
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
/* If hash for removed entries exists, go until offset+length and copy the entries to it */
|
||||
@@ -2001,10 +2036,12 @@ static void php_splice(HashTable *in_hash, int offset, int length, HashTable *re
|
||||
}
|
||||
}
|
||||
} else { /* otherwise just skip those entries */
|
||||
for ( ; pos < offset + length && idx < in_hash->nNumUsed; idx++) {
|
||||
int pos2 = pos;
|
||||
|
||||
for ( ; pos2 < offset + length && idx < in_hash->nNumUsed; idx++) {
|
||||
p = in_hash->arData + idx;
|
||||
if (Z_TYPE(p->val) == IS_UNDEF) continue;
|
||||
pos++;
|
||||
pos2++;
|
||||
if (p->key == NULL) {
|
||||
zend_hash_index_del(in_hash, p->h);
|
||||
} else {
|
||||
@@ -2016,12 +2053,14 @@ static void php_splice(HashTable *in_hash, int offset, int length, HashTable *re
|
||||
}
|
||||
}
|
||||
}
|
||||
iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos);
|
||||
|
||||
/* If there are entries to insert.. */
|
||||
if (replace) {
|
||||
ZEND_HASH_FOREACH_VAL_IND(replace, entry) {
|
||||
if (Z_REFCOUNTED_P(entry)) Z_ADDREF_P(entry);
|
||||
zend_hash_next_index_insert_new(&out_hash, entry);
|
||||
pos++;
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
@@ -2035,13 +2074,31 @@ static void php_splice(HashTable *in_hash, int offset, int length, HashTable *re
|
||||
} else {
|
||||
zend_hash_add_new(&out_hash, p->key, entry);
|
||||
}
|
||||
if (idx == iter_pos) {
|
||||
if (idx != pos) {
|
||||
zend_hash_iterators_update(in_hash, idx, pos);
|
||||
}
|
||||
iter_pos = zend_hash_iterators_lower_pos(in_hash, iter_pos + 1);
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
zend_hash_internal_pointer_reset(&out_hash);
|
||||
|
||||
/* replace HashTable data */
|
||||
in_hash->u.v.nIteratorsCount = 0;
|
||||
in_hash->pDestructor = NULL;
|
||||
zend_hash_destroy(in_hash);
|
||||
*in_hash = out_hash;
|
||||
|
||||
in_hash->u.v.flags = out_hash.u.v.flags;
|
||||
in_hash->nTableSize = out_hash.nTableSize;
|
||||
in_hash->nTableMask = out_hash.nTableMask;
|
||||
in_hash->nNumUsed = out_hash.nNumUsed;
|
||||
in_hash->nNumOfElements = out_hash.nNumOfElements;
|
||||
in_hash->nNextFreeElement = out_hash.nNextFreeElement;
|
||||
in_hash->arData = out_hash.arData;
|
||||
in_hash->arHash = out_hash.arHash;
|
||||
in_hash->pDestructor = out_hash.pDestructor;
|
||||
|
||||
zend_hash_internal_pointer_reset(in_hash);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -2194,17 +2251,38 @@ PHP_FUNCTION(array_shift)
|
||||
if (Z_ARRVAL_P(stack)->u.flags & HASH_FLAG_PACKED) {
|
||||
uint32_t k = 0;
|
||||
|
||||
for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
|
||||
p = Z_ARRVAL_P(stack)->arData + idx;
|
||||
if (Z_TYPE(p->val) == IS_UNDEF) continue;
|
||||
if (idx != k) {
|
||||
Bucket *q = Z_ARRVAL_P(stack)->arData + k;
|
||||
q->h = k;
|
||||
q->key = NULL;
|
||||
ZVAL_COPY_VALUE(&q->val, &p->val);
|
||||
ZVAL_UNDEF(&p->val);
|
||||
if (EXPECTED(Z_ARRVAL_P(stack)->u.v.nIteratorsCount == 0)) {
|
||||
for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
|
||||
p = Z_ARRVAL_P(stack)->arData + idx;
|
||||
if (Z_TYPE(p->val) == IS_UNDEF) continue;
|
||||
if (idx != k) {
|
||||
Bucket *q = Z_ARRVAL_P(stack)->arData + k;
|
||||
q->h = k;
|
||||
q->key = NULL;
|
||||
ZVAL_COPY_VALUE(&q->val, &p->val);
|
||||
ZVAL_UNDEF(&p->val);
|
||||
}
|
||||
k++;
|
||||
}
|
||||
} else {
|
||||
uint32_t iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), 0);
|
||||
|
||||
for (idx = 0; idx < Z_ARRVAL_P(stack)->nNumUsed; idx++) {
|
||||
p = Z_ARRVAL_P(stack)->arData + idx;
|
||||
if (Z_TYPE(p->val) == IS_UNDEF) continue;
|
||||
if (idx != k) {
|
||||
Bucket *q = Z_ARRVAL_P(stack)->arData + k;
|
||||
q->h = k;
|
||||
q->key = NULL;
|
||||
ZVAL_COPY_VALUE(&q->val, &p->val);
|
||||
ZVAL_UNDEF(&p->val);
|
||||
if (idx == iter_pos) {
|
||||
zend_hash_iterators_update(Z_ARRVAL_P(stack), idx, k);
|
||||
iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), iter_pos + 1);
|
||||
}
|
||||
}
|
||||
k++;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
Z_ARRVAL_P(stack)->nNumUsed = k;
|
||||
Z_ARRVAL_P(stack)->nNextFreeElement = k;
|
||||
@@ -2257,17 +2335,50 @@ PHP_FUNCTION(array_unshift)
|
||||
}
|
||||
zend_hash_next_index_insert_new(&new_hash, &args[i]);
|
||||
}
|
||||
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
|
||||
if (key) {
|
||||
zend_hash_add_new(&new_hash, key, value);
|
||||
} else {
|
||||
zend_hash_next_index_insert_new(&new_hash, value);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
if (EXPECTED(Z_ARRVAL_P(stack)->u.v.nIteratorsCount == 0)) {
|
||||
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
|
||||
if (key) {
|
||||
zend_hash_add_new(&new_hash, key, value);
|
||||
} else {
|
||||
zend_hash_next_index_insert_new(&new_hash, value);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
} else {
|
||||
uint32_t old_idx;
|
||||
uint32_t new_idx = i;
|
||||
uint32_t iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), 0);
|
||||
|
||||
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(stack), key, value) {
|
||||
if (key) {
|
||||
zend_hash_add_new(&new_hash, key, value);
|
||||
} else {
|
||||
zend_hash_next_index_insert_new(&new_hash, value);
|
||||
}
|
||||
old_idx = (Bucket*)value - Z_ARRVAL_P(stack)->arData;
|
||||
if (old_idx == iter_pos) {
|
||||
zend_hash_iterators_update(Z_ARRVAL_P(stack), old_idx, new_idx);
|
||||
iter_pos = zend_hash_iterators_lower_pos(Z_ARRVAL_P(stack), iter_pos + 1);
|
||||
}
|
||||
new_idx++;
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
/* replace HashTable data */
|
||||
Z_ARRVAL_P(stack)->u.v.nIteratorsCount = 0;
|
||||
Z_ARRVAL_P(stack)->pDestructor = NULL;
|
||||
zend_hash_destroy(Z_ARRVAL_P(stack));
|
||||
*Z_ARRVAL_P(stack) = new_hash;
|
||||
|
||||
Z_ARRVAL_P(stack)->u.v.flags = new_hash.u.v.flags;
|
||||
Z_ARRVAL_P(stack)->nTableSize = new_hash.nTableSize;
|
||||
Z_ARRVAL_P(stack)->nTableMask = new_hash.nTableMask;
|
||||
Z_ARRVAL_P(stack)->nNumUsed = new_hash.nNumUsed;
|
||||
Z_ARRVAL_P(stack)->nNumOfElements = new_hash.nNumOfElements;
|
||||
Z_ARRVAL_P(stack)->nNextFreeElement = new_hash.nNextFreeElement;
|
||||
Z_ARRVAL_P(stack)->arData = new_hash.arData;
|
||||
Z_ARRVAL_P(stack)->arHash = new_hash.arHash;
|
||||
Z_ARRVAL_P(stack)->pDestructor = new_hash.pDestructor;
|
||||
|
||||
zend_hash_internal_pointer_reset(Z_ARRVAL_P(stack));
|
||||
|
||||
/* Clean up and return the number of elements in the stack */
|
||||
RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
|
||||
|
||||
@@ -9,4 +9,4 @@ Bug #23624 (foreach leaves current array key as null)
|
||||
?>
|
||||
--EXPECT--
|
||||
string(3) "one"
|
||||
bool(false)
|
||||
string(3) "one"
|
||||
@@ -60,5 +60,5 @@ string(1) "f"
|
||||
int(2)
|
||||
string(1) "f"
|
||||
|
||||
bool(false)
|
||||
string(1) "a"
|
||||
bool(false)
|
||||
@@ -55,6 +55,7 @@ foreach ($refedArray as $k=>&$v4) {
|
||||
Remove elements from a referenced array during loop
|
||||
key: 0; value: original.0
|
||||
key: 1; value: original.1
|
||||
key: 2; value: original.2
|
||||
|
||||
Remove elements from a referenced array during loop, using &$value
|
||||
key: 0; value: original.0
|
||||
@@ -64,11 +65,6 @@ Add elements to a referenced array during loop
|
||||
key: 0; value: original.0
|
||||
key: 1; value: original.1
|
||||
key: 2; value: original.2
|
||||
key: 3; value: new.0
|
||||
key: 4; value: new.1
|
||||
key: 5; value: new.2
|
||||
key: 6; value: new.3
|
||||
Loop detected, as expected.
|
||||
|
||||
Add elements to a referenced array during loop, using &$value
|
||||
key: 0; value: original.0
|
||||
|
||||
@@ -25,10 +25,9 @@ foreach ($a as $v) {
|
||||
|
||||
Change from array to non iterable:
|
||||
int(1)
|
||||
|
||||
Warning: Invalid argument supplied for foreach() in %s on line 5
|
||||
int(2)
|
||||
int(3)
|
||||
|
||||
Change from object to non iterable:
|
||||
int(1)
|
||||
|
||||
Warning: Invalid argument supplied for foreach() in %s on line 15
|
||||
int(2)
|
||||
@@ -1,7 +1,5 @@
|
||||
--TEST--
|
||||
Directly modifying an unreferenced array when foreach'ing over it while using &$value syntax.
|
||||
--XFAIL--
|
||||
Needs major foreach changes to get sane behavior
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
@@ -70,7 +68,7 @@ withRefValue(3, $transform);
|
||||
withRefValue(4, $transform);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
--EXPECT--
|
||||
|
||||
Popping elements off end of an unreferenced array, using &$value.
|
||||
---( Array with 1 element(s): )---
|
||||
@@ -95,9 +93,10 @@ array(2) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=v.0
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
array(1) {
|
||||
[0]=>
|
||||
&string(3) "v.0"
|
||||
}
|
||||
|
||||
---( Array with 3 element(s): )---
|
||||
@@ -134,10 +133,12 @@ array(4) {
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=0; $v=v.0
|
||||
iteration 3: $k=0; $v=v.0
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(3) "v.0"
|
||||
[1]=>
|
||||
&string(3) "v.1"
|
||||
}
|
||||
|
||||
|
||||
@@ -289,12 +290,28 @@ array(1) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=new.0
|
||||
iteration 2: $k=2; $v=new.1
|
||||
iteration 3: $k=3; $v=new.2
|
||||
iteration 4: $k=4; $v=new.3
|
||||
iteration 5: $k=5; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
--> State of array after loop:
|
||||
array(2) {
|
||||
array(7) {
|
||||
[0]=>
|
||||
&string(3) "v.0"
|
||||
string(3) "v.0"
|
||||
[1]=>
|
||||
string(5) "new.0"
|
||||
[2]=>
|
||||
string(5) "new.1"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
string(5) "new.3"
|
||||
[5]=>
|
||||
&string(5) "new.4"
|
||||
[6]=>
|
||||
string(5) "new.5"
|
||||
}
|
||||
|
||||
---( Array with 2 element(s): )---
|
||||
@@ -446,30 +463,17 @@ array(2) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=new.0
|
||||
iteration 2: $k=0; $v=new.1
|
||||
iteration 3: $k=0; $v=new.2
|
||||
iteration 4: $k=0; $v=new.3
|
||||
iteration 5: $k=0; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
iteration 1: $k=2; $v=v.1
|
||||
--> State of array after loop:
|
||||
array(8) {
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(5) "new.5"
|
||||
[1]=>
|
||||
&string(5) "new.4"
|
||||
[2]=>
|
||||
string(5) "new.3"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
[1]=>
|
||||
string(5) "new.0"
|
||||
[6]=>
|
||||
[2]=>
|
||||
string(3) "v.0"
|
||||
[7]=>
|
||||
string(3) "v.1"
|
||||
[3]=>
|
||||
&string(3) "v.1"
|
||||
}
|
||||
|
||||
---( Array with 3 element(s): )---
|
||||
@@ -484,32 +488,19 @@ array(3) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=new.0
|
||||
iteration 2: $k=0; $v=new.1
|
||||
iteration 3: $k=0; $v=new.2
|
||||
iteration 4: $k=0; $v=new.3
|
||||
iteration 5: $k=0; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
iteration 1: $k=3; $v=v.2
|
||||
--> State of array after loop:
|
||||
array(9) {
|
||||
array(5) {
|
||||
[0]=>
|
||||
string(5) "new.5"
|
||||
[1]=>
|
||||
&string(5) "new.4"
|
||||
[2]=>
|
||||
string(5) "new.3"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
[1]=>
|
||||
string(5) "new.0"
|
||||
[6]=>
|
||||
[2]=>
|
||||
string(3) "v.0"
|
||||
[7]=>
|
||||
[3]=>
|
||||
string(3) "v.1"
|
||||
[8]=>
|
||||
string(3) "v.2"
|
||||
[4]=>
|
||||
&string(3) "v.2"
|
||||
}
|
||||
|
||||
---( Array with 4 element(s): )---
|
||||
@@ -526,32 +517,19 @@ array(4) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=new.0
|
||||
iteration 2: $k=0; $v=new.1
|
||||
iteration 3: $k=0; $v=new.2
|
||||
iteration 4: $k=0; $v=new.3
|
||||
iteration 5: $k=0; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
iteration 1: $k=4; $v=v.3
|
||||
--> State of array after loop:
|
||||
array(10) {
|
||||
array(6) {
|
||||
[0]=>
|
||||
string(5) "new.5"
|
||||
[1]=>
|
||||
&string(5) "new.4"
|
||||
[2]=>
|
||||
string(5) "new.3"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
[1]=>
|
||||
string(5) "new.0"
|
||||
[6]=>
|
||||
[2]=>
|
||||
string(3) "v.0"
|
||||
[7]=>
|
||||
[3]=>
|
||||
string(3) "v.1"
|
||||
[8]=>
|
||||
[4]=>
|
||||
string(3) "v.2"
|
||||
[9]=>
|
||||
string(3) "v.3"
|
||||
[5]=>
|
||||
&string(3) "v.3"
|
||||
}
|
||||
+38
-101
@@ -1,7 +1,5 @@
|
||||
--TEST--
|
||||
Directly modifying a REFERENCED array when foreach'ing over it.
|
||||
--XFAIL--
|
||||
Needs major foreach changes to get sane behavior
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
@@ -96,7 +94,7 @@ array(2) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=v.1
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
}
|
||||
@@ -114,10 +112,9 @@ array(3) {
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=v.2
|
||||
--> State of array after loop:
|
||||
array(1) {
|
||||
[0]=>
|
||||
string(3) "v.0"
|
||||
array(0) {
|
||||
}
|
||||
|
||||
---( Array with 4 element(s): )---
|
||||
@@ -135,8 +132,8 @@ array(4) {
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=0; $v=v.0
|
||||
iteration 3: $k=0; $v=v.0
|
||||
iteration 2: $k=2; $v=v.2
|
||||
iteration 3: $k=3; $v=v.3
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
}
|
||||
@@ -166,7 +163,7 @@ array(2) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=v.1
|
||||
iteration 1: $k=1; $v=v.1
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
}
|
||||
@@ -183,8 +180,8 @@ array(3) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=v.1
|
||||
iteration 2: $k=0; $v=v.2
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=v.2
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
}
|
||||
@@ -203,9 +200,9 @@ array(4) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=v.1
|
||||
iteration 2: $k=0; $v=v.2
|
||||
iteration 3: $k=0; $v=v.3
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=v.2
|
||||
iteration 3: $k=3; $v=v.3
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
}
|
||||
@@ -309,13 +306,8 @@ array(2) {
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=new.0
|
||||
iteration 3: $k=3; $v=new.1
|
||||
iteration 4: $k=4; $v=new.2
|
||||
iteration 5: $k=5; $v=new.3
|
||||
** Stuck in a loop! **
|
||||
--> State of array after loop:
|
||||
array(8) {
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(3) "v.0"
|
||||
[1]=>
|
||||
@@ -324,14 +316,6 @@ array(8) {
|
||||
string(5) "new.0"
|
||||
[3]=>
|
||||
string(5) "new.1"
|
||||
[4]=>
|
||||
string(5) "new.2"
|
||||
[5]=>
|
||||
string(5) "new.3"
|
||||
[6]=>
|
||||
string(5) "new.4"
|
||||
[7]=>
|
||||
string(5) "new.5"
|
||||
}
|
||||
|
||||
---( Array with 3 element(s): )---
|
||||
@@ -348,12 +332,8 @@ array(3) {
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=v.2
|
||||
iteration 3: $k=3; $v=new.0
|
||||
iteration 4: $k=4; $v=new.1
|
||||
iteration 5: $k=5; $v=new.2
|
||||
** Stuck in a loop! **
|
||||
--> State of array after loop:
|
||||
array(9) {
|
||||
array(6) {
|
||||
[0]=>
|
||||
string(3) "v.0"
|
||||
[1]=>
|
||||
@@ -366,12 +346,6 @@ array(9) {
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
string(5) "new.2"
|
||||
[6]=>
|
||||
string(5) "new.3"
|
||||
[7]=>
|
||||
string(5) "new.4"
|
||||
[8]=>
|
||||
string(5) "new.5"
|
||||
}
|
||||
|
||||
---( Array with 4 element(s): )---
|
||||
@@ -391,11 +365,8 @@ array(4) {
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=v.2
|
||||
iteration 3: $k=3; $v=v.3
|
||||
iteration 4: $k=4; $v=new.0
|
||||
iteration 5: $k=5; $v=new.1
|
||||
** Stuck in a loop! **
|
||||
--> State of array after loop:
|
||||
array(10) {
|
||||
array(8) {
|
||||
[0]=>
|
||||
string(3) "v.0"
|
||||
[1]=>
|
||||
@@ -412,10 +383,6 @@ array(10) {
|
||||
string(5) "new.2"
|
||||
[7]=>
|
||||
string(5) "new.3"
|
||||
[8]=>
|
||||
string(5) "new.4"
|
||||
[9]=>
|
||||
string(5) "new.5"
|
||||
}
|
||||
|
||||
|
||||
@@ -447,29 +414,16 @@ array(2) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=new.0
|
||||
iteration 2: $k=0; $v=new.1
|
||||
iteration 3: $k=0; $v=new.2
|
||||
iteration 4: $k=0; $v=new.3
|
||||
iteration 5: $k=0; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
iteration 1: $k=1; $v=v.1
|
||||
--> State of array after loop:
|
||||
array(8) {
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(5) "new.5"
|
||||
[1]=>
|
||||
string(5) "new.4"
|
||||
[2]=>
|
||||
string(5) "new.3"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
[1]=>
|
||||
string(5) "new.0"
|
||||
[6]=>
|
||||
[2]=>
|
||||
string(3) "v.0"
|
||||
[7]=>
|
||||
[3]=>
|
||||
string(3) "v.1"
|
||||
}
|
||||
|
||||
@@ -485,31 +439,21 @@ array(3) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=new.0
|
||||
iteration 2: $k=0; $v=new.1
|
||||
iteration 3: $k=0; $v=new.2
|
||||
iteration 4: $k=0; $v=new.3
|
||||
iteration 5: $k=0; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=v.2
|
||||
--> State of array after loop:
|
||||
array(9) {
|
||||
array(6) {
|
||||
[0]=>
|
||||
string(5) "new.5"
|
||||
[1]=>
|
||||
string(5) "new.4"
|
||||
[2]=>
|
||||
string(5) "new.3"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
[1]=>
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
[2]=>
|
||||
string(5) "new.0"
|
||||
[6]=>
|
||||
[3]=>
|
||||
string(3) "v.0"
|
||||
[7]=>
|
||||
[4]=>
|
||||
string(3) "v.1"
|
||||
[8]=>
|
||||
[5]=>
|
||||
string(3) "v.2"
|
||||
}
|
||||
|
||||
@@ -527,32 +471,25 @@ array(4) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=new.0
|
||||
iteration 2: $k=0; $v=new.1
|
||||
iteration 3: $k=0; $v=new.2
|
||||
iteration 4: $k=0; $v=new.3
|
||||
iteration 5: $k=0; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=2; $v=v.2
|
||||
iteration 3: $k=3; $v=v.3
|
||||
--> State of array after loop:
|
||||
array(10) {
|
||||
array(8) {
|
||||
[0]=>
|
||||
string(5) "new.5"
|
||||
[1]=>
|
||||
string(5) "new.4"
|
||||
[2]=>
|
||||
string(5) "new.3"
|
||||
[3]=>
|
||||
[1]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
[2]=>
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
[3]=>
|
||||
string(5) "new.0"
|
||||
[6]=>
|
||||
[4]=>
|
||||
string(3) "v.0"
|
||||
[7]=>
|
||||
[5]=>
|
||||
string(3) "v.1"
|
||||
[8]=>
|
||||
[6]=>
|
||||
string(3) "v.2"
|
||||
[9]=>
|
||||
[7]=>
|
||||
string(3) "v.3"
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
--TEST--
|
||||
Directly modifying a REFERENCED array when foreach'ing over it while using &$value syntax.
|
||||
--XFAIL--
|
||||
Needs major foreach changes to get sane behavior
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
@@ -72,7 +70,7 @@ withRefValue(3, $transform);
|
||||
withRefValue(4, $transform);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
--EXPECT--
|
||||
|
||||
Popping elements off end of a referenced array, using &$value
|
||||
---( Array with 1 element(s): )---
|
||||
@@ -97,9 +95,10 @@ array(2) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=v.0
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
array(1) {
|
||||
[0]=>
|
||||
&string(3) "v.0"
|
||||
}
|
||||
|
||||
---( Array with 3 element(s): )---
|
||||
@@ -136,10 +135,12 @@ array(4) {
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=v.1
|
||||
iteration 2: $k=0; $v=v.0
|
||||
iteration 3: $k=0; $v=v.0
|
||||
--> State of array after loop:
|
||||
array(0) {
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(3) "v.0"
|
||||
[1]=>
|
||||
&string(3) "v.1"
|
||||
}
|
||||
|
||||
|
||||
@@ -291,12 +292,28 @@ array(1) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=1; $v=new.0
|
||||
iteration 2: $k=2; $v=new.1
|
||||
iteration 3: $k=3; $v=new.2
|
||||
iteration 4: $k=4; $v=new.3
|
||||
iteration 5: $k=5; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
--> State of array after loop:
|
||||
array(2) {
|
||||
array(7) {
|
||||
[0]=>
|
||||
&string(3) "v.0"
|
||||
string(3) "v.0"
|
||||
[1]=>
|
||||
string(5) "new.0"
|
||||
[2]=>
|
||||
string(5) "new.1"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
string(5) "new.3"
|
||||
[5]=>
|
||||
&string(5) "new.4"
|
||||
[6]=>
|
||||
string(5) "new.5"
|
||||
}
|
||||
|
||||
---( Array with 2 element(s): )---
|
||||
@@ -448,30 +465,17 @@ array(2) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=new.0
|
||||
iteration 2: $k=0; $v=new.1
|
||||
iteration 3: $k=0; $v=new.2
|
||||
iteration 4: $k=0; $v=new.3
|
||||
iteration 5: $k=0; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
iteration 1: $k=2; $v=v.1
|
||||
--> State of array after loop:
|
||||
array(8) {
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(5) "new.5"
|
||||
[1]=>
|
||||
&string(5) "new.4"
|
||||
[2]=>
|
||||
string(5) "new.3"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
[1]=>
|
||||
string(5) "new.0"
|
||||
[6]=>
|
||||
[2]=>
|
||||
string(3) "v.0"
|
||||
[7]=>
|
||||
string(3) "v.1"
|
||||
[3]=>
|
||||
&string(3) "v.1"
|
||||
}
|
||||
|
||||
---( Array with 3 element(s): )---
|
||||
@@ -486,32 +490,19 @@ array(3) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=new.0
|
||||
iteration 2: $k=0; $v=new.1
|
||||
iteration 3: $k=0; $v=new.2
|
||||
iteration 4: $k=0; $v=new.3
|
||||
iteration 5: $k=0; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
iteration 1: $k=3; $v=v.2
|
||||
--> State of array after loop:
|
||||
array(9) {
|
||||
array(5) {
|
||||
[0]=>
|
||||
string(5) "new.5"
|
||||
[1]=>
|
||||
&string(5) "new.4"
|
||||
[2]=>
|
||||
string(5) "new.3"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
[1]=>
|
||||
string(5) "new.0"
|
||||
[6]=>
|
||||
[2]=>
|
||||
string(3) "v.0"
|
||||
[7]=>
|
||||
[3]=>
|
||||
string(3) "v.1"
|
||||
[8]=>
|
||||
string(3) "v.2"
|
||||
[4]=>
|
||||
&string(3) "v.2"
|
||||
}
|
||||
|
||||
---( Array with 4 element(s): )---
|
||||
@@ -528,32 +519,19 @@ array(4) {
|
||||
}
|
||||
--> Do loop:
|
||||
iteration 0: $k=0; $v=v.0
|
||||
iteration 1: $k=0; $v=new.0
|
||||
iteration 2: $k=0; $v=new.1
|
||||
iteration 3: $k=0; $v=new.2
|
||||
iteration 4: $k=0; $v=new.3
|
||||
iteration 5: $k=0; $v=new.4
|
||||
** Stuck in a loop! **
|
||||
iteration 1: $k=4; $v=v.3
|
||||
--> State of array after loop:
|
||||
array(10) {
|
||||
array(6) {
|
||||
[0]=>
|
||||
string(5) "new.5"
|
||||
[1]=>
|
||||
&string(5) "new.4"
|
||||
[2]=>
|
||||
string(5) "new.3"
|
||||
[3]=>
|
||||
string(5) "new.2"
|
||||
[4]=>
|
||||
string(5) "new.1"
|
||||
[5]=>
|
||||
[1]=>
|
||||
string(5) "new.0"
|
||||
[6]=>
|
||||
[2]=>
|
||||
string(3) "v.0"
|
||||
[7]=>
|
||||
[3]=>
|
||||
string(3) "v.1"
|
||||
[8]=>
|
||||
[4]=>
|
||||
string(3) "v.2"
|
||||
[9]=>
|
||||
string(3) "v.3"
|
||||
[5]=>
|
||||
&string(3) "v.3"
|
||||
}
|
||||
@@ -70,16 +70,12 @@ var_dump($obj);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
|
||||
Substituting the iterated object for a different object.
|
||||
string(10) "Original a"
|
||||
string(10) "Original b"
|
||||
string(5) "new a"
|
||||
string(5) "new b"
|
||||
string(5) "new c"
|
||||
string(5) "new d"
|
||||
string(5) "new e"
|
||||
string(5) "new f"
|
||||
string(10) "Original c"
|
||||
string(10) "Original d"
|
||||
string(10) "Original e"
|
||||
object(stdClass)#%d (6) {
|
||||
["a"]=>
|
||||
string(5) "new a"
|
||||
@@ -98,14 +94,9 @@ object(stdClass)#%d (6) {
|
||||
Substituting the iterated object for an array.
|
||||
string(10) "Original a"
|
||||
string(10) "Original b"
|
||||
int(1)
|
||||
int(2)
|
||||
int(3)
|
||||
int(4)
|
||||
int(5)
|
||||
int(6)
|
||||
int(7)
|
||||
int(8)
|
||||
string(10) "Original c"
|
||||
string(10) "Original d"
|
||||
string(10) "Original e"
|
||||
array(8) {
|
||||
[0]=>
|
||||
int(1)
|
||||
@@ -128,11 +119,12 @@ array(8) {
|
||||
Substituting the iterated array for an object.
|
||||
int(1)
|
||||
int(2)
|
||||
string(10) "Original a"
|
||||
string(10) "Original b"
|
||||
string(10) "Original c"
|
||||
string(10) "Original d"
|
||||
string(10) "Original e"
|
||||
int(3)
|
||||
int(4)
|
||||
int(5)
|
||||
int(6)
|
||||
int(7)
|
||||
int(8)
|
||||
object(C)#%d (5) {
|
||||
["a"]=>
|
||||
string(10) "Original a"
|
||||
|
||||
Reference in new issue
Block a user