mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Added garbage collector
This commit is contained in:
parent
f51bf6118c
commit
6847c18150
40 changed files with 1503 additions and 6 deletions
12
Zend/tests/gc_001.phpt
Normal file
12
Zend/tests/gc_001.phpt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
--TEST--
|
||||||
|
GC 001: gc_enable()/gc_diable()/gc_enabled()
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
gc_disable();
|
||||||
|
var_dump(gc_enabled());
|
||||||
|
gc_enable();
|
||||||
|
var_dump(gc_enabled());
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(false)
|
||||||
|
bool(true)
|
16
Zend/tests/gc_002.phpt
Normal file
16
Zend/tests/gc_002.phpt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
--TEST--
|
||||||
|
GC 002: gc_enable()/gc_diable() and ini_get()
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
gc_disable();
|
||||||
|
var_dump(gc_enabled());
|
||||||
|
echo ini_get('zend.enable_gc') . "\n";
|
||||||
|
gc_enable();
|
||||||
|
var_dump(gc_enabled());
|
||||||
|
echo ini_get('zend.enable_gc') . "\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(false)
|
||||||
|
0
|
||||||
|
bool(true)
|
||||||
|
1
|
16
Zend/tests/gc_003.phpt
Normal file
16
Zend/tests/gc_003.phpt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
--TEST--
|
||||||
|
GC 003: gc_enabled() and ini_set()
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
ini_set('zend.enable_gc','0');
|
||||||
|
var_dump(gc_enabled());
|
||||||
|
echo ini_get('zend.enable_gc') . "\n";
|
||||||
|
ini_set('zend.enable_gc','1');
|
||||||
|
var_dump(gc_enabled());
|
||||||
|
echo ini_get('zend.enable_gc') . "\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(false)
|
||||||
|
0
|
||||||
|
bool(true)
|
||||||
|
1
|
24
Zend/tests/gc_004.phpt
Normal file
24
Zend/tests/gc_004.phpt
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
--TEST--
|
||||||
|
GC 004: Simple array cycle
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = array();
|
||||||
|
$a[] =& $a;
|
||||||
|
var_dump($a);
|
||||||
|
unset($a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
&array(1) {
|
||||||
|
[0]=>
|
||||||
|
&array(1) {
|
||||||
|
[0]=>
|
||||||
|
*RECURSION*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int(1)
|
||||||
|
ok
|
31
Zend/tests/gc_005.phpt
Normal file
31
Zend/tests/gc_005.phpt
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
--TEST--
|
||||||
|
GC 005: Simple object cycle
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = new stdClass();
|
||||||
|
$a->a = $a;
|
||||||
|
var_dump($a);
|
||||||
|
unset($a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
object(stdClass)#1 (1) {
|
||||||
|
["a"]=>
|
||||||
|
object(stdClass)#1 (1) {
|
||||||
|
["a"]=>
|
||||||
|
*RECURSION*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int(1)
|
||||||
|
ok
|
||||||
|
--UEXPECT--
|
||||||
|
object(stdClass)#1 (1) {
|
||||||
|
[u"a"]=>
|
||||||
|
object(stdClass)#1 (1) {
|
||||||
|
[u"a"]=>
|
||||||
|
*RECURSION*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int(1)
|
||||||
|
ok
|
44
Zend/tests/gc_006.phpt
Normal file
44
Zend/tests/gc_006.phpt
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
--TEST--
|
||||||
|
GC 006: Simple array-object cycle
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = new stdClass();
|
||||||
|
$a->a = array();
|
||||||
|
$a->a[0] =& $a;
|
||||||
|
var_dump($a);
|
||||||
|
unset($a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
object(stdClass)#1 (1) {
|
||||||
|
["a"]=>
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
&object(stdClass)#1 (1) {
|
||||||
|
["a"]=>
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
*RECURSION*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int(2)
|
||||||
|
ok
|
||||||
|
--UEXPECT--
|
||||||
|
object(stdClass)#1 (1) {
|
||||||
|
[u"a"]=>
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
&object(stdClass)#1 (1) {
|
||||||
|
[u"a"]=>
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
*RECURSION*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int(2)
|
||||||
|
ok
|
26
Zend/tests/gc_007.phpt
Normal file
26
Zend/tests/gc_007.phpt
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
--TEST--
|
||||||
|
GC 007: Unreferensed array cycle
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = array(array());
|
||||||
|
$a[0][0] =& $a[0];
|
||||||
|
var_dump($a[0]);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
unset($a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
&array(1) {
|
||||||
|
[0]=>
|
||||||
|
&array(1) {
|
||||||
|
[0]=>
|
||||||
|
*RECURSION*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int(0)
|
||||||
|
int(1)
|
||||||
|
ok
|
35
Zend/tests/gc_008.phpt
Normal file
35
Zend/tests/gc_008.phpt
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
--TEST--
|
||||||
|
GC 008: Unreferensed object cycle
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = new stdClass();
|
||||||
|
$a->a = new stdClass();
|
||||||
|
$a->a->a = $a->a;
|
||||||
|
var_dump($a->a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
unset($a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
object(stdClass)#2 (1) {
|
||||||
|
["a"]=>
|
||||||
|
object(stdClass)#2 (1) {
|
||||||
|
["a"]=>
|
||||||
|
*RECURSION*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int(0)
|
||||||
|
int(1)
|
||||||
|
ok
|
||||||
|
--UEXPECT--
|
||||||
|
object(stdClass)#2 (1) {
|
||||||
|
[u"a"]=>
|
||||||
|
object(stdClass)#2 (1) {
|
||||||
|
[u"a"]=>
|
||||||
|
*RECURSION*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int(0)
|
||||||
|
int(1)
|
||||||
|
ok
|
48
Zend/tests/gc_009.phpt
Normal file
48
Zend/tests/gc_009.phpt
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
--TEST--
|
||||||
|
GC 009: Unreferensed array-object cycle
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = array();
|
||||||
|
$a[0] = new stdClass();
|
||||||
|
$a[0]->a = array();
|
||||||
|
$a[0]->a[0] =& $a[0];
|
||||||
|
var_dump($a[0]);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
unset($a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
object(stdClass)#1 (1) {
|
||||||
|
["a"]=>
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
&object(stdClass)#1 (1) {
|
||||||
|
["a"]=>
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
*RECURSION*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int(0)
|
||||||
|
int(2)
|
||||||
|
ok
|
||||||
|
--UEXPECT--
|
||||||
|
object(stdClass)#1 (1) {
|
||||||
|
[u"a"]=>
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
&object(stdClass)#1 (1) {
|
||||||
|
[u"a"]=>
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
*RECURSION*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int(0)
|
||||||
|
int(2)
|
||||||
|
ok
|
25
Zend/tests/gc_010.phpt
Normal file
25
Zend/tests/gc_010.phpt
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
--TEST--
|
||||||
|
GC 010: Cycle with reference to $GLOBALS
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = array();
|
||||||
|
$a[] =& $a;
|
||||||
|
var_dump($a);
|
||||||
|
$a[] =& $GLOBALS;
|
||||||
|
unset($a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
&array(1) {
|
||||||
|
[0]=>
|
||||||
|
&array(1) {
|
||||||
|
[0]=>
|
||||||
|
*RECURSION*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int(1)
|
||||||
|
ok
|
39
Zend/tests/gc_011.phpt
Normal file
39
Zend/tests/gc_011.phpt
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
--TEST--
|
||||||
|
GC 011: GC and destructors
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Foo {
|
||||||
|
public $a;
|
||||||
|
function __destruct() {
|
||||||
|
echo __FUNCTION__,"\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$a = new Foo();
|
||||||
|
$a->a = $a;
|
||||||
|
var_dump($a);
|
||||||
|
unset($a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
object(Foo)#1 (1) {
|
||||||
|
["a"]=>
|
||||||
|
object(Foo)#1 (1) {
|
||||||
|
["a"]=>
|
||||||
|
*RECURSION*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__destruct
|
||||||
|
int(1)
|
||||||
|
ok
|
||||||
|
--UEXPECT--
|
||||||
|
object(Foo)#1 (1) {
|
||||||
|
[u"a"]=>
|
||||||
|
object(Foo)#1 (1) {
|
||||||
|
[u"a"]=>
|
||||||
|
*RECURSION*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__destruct
|
||||||
|
int(1)
|
||||||
|
ok
|
17
Zend/tests/gc_012.phpt
Normal file
17
Zend/tests/gc_012.phpt
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
--TEST--
|
||||||
|
GC 012: collection of many loops at once
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a=array();
|
||||||
|
for ($i=0; $i < 1000; $i++) {
|
||||||
|
$a[$i] = array(array());
|
||||||
|
$a[$i][0] = & $a[$i];
|
||||||
|
}
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
unset($a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n";
|
||||||
|
--EXPECT--
|
||||||
|
int(0)
|
||||||
|
int(1000)
|
||||||
|
ok
|
16
Zend/tests/gc_013.phpt
Normal file
16
Zend/tests/gc_013.phpt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
--TEST--
|
||||||
|
GC 013: Too many cycles in one array
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = array();
|
||||||
|
for ($i = 0; $i < 10001; $i++) {
|
||||||
|
$a[$i] =& $a;
|
||||||
|
}
|
||||||
|
$a[] = "xxx";
|
||||||
|
unset($a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
int(2)
|
||||||
|
ok
|
18
Zend/tests/gc_014.phpt
Normal file
18
Zend/tests/gc_014.phpt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
--TEST--
|
||||||
|
GC 014: Too many cycles in one object
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = new stdClass();
|
||||||
|
for ($i = 0; $i < 10001; $i++) {
|
||||||
|
$b =& $a;
|
||||||
|
$a->{"a".$i} = $a;
|
||||||
|
}
|
||||||
|
unset($b);
|
||||||
|
$a->b = "xxx";
|
||||||
|
unset($a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
int(10002)
|
||||||
|
ok
|
18
Zend/tests/gc_015.phpt
Normal file
18
Zend/tests/gc_015.phpt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
--TEST--
|
||||||
|
GC 015: Object as root of cycle
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = new stdClass();
|
||||||
|
$c =& $a;
|
||||||
|
$b = $a;
|
||||||
|
$a->a = $a;
|
||||||
|
$a->b = "xxx";
|
||||||
|
unset($c);
|
||||||
|
unset($a);
|
||||||
|
unset($b);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
int(2)
|
||||||
|
ok
|
24
Zend/tests/gc_016.phpt
Normal file
24
Zend/tests/gc_016.phpt
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
--TEST--
|
||||||
|
GC 016: nested GC calls
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Foo {
|
||||||
|
public $a;
|
||||||
|
function __destruct() {
|
||||||
|
echo "-> ";
|
||||||
|
$a = array();
|
||||||
|
$a[] =& $a;
|
||||||
|
unset($a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$a = new Foo();
|
||||||
|
$a->a = $a;
|
||||||
|
unset($a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
-> int(1)
|
||||||
|
int(1)
|
||||||
|
ok
|
47
Zend/tests/gc_017.phpt
Normal file
47
Zend/tests/gc_017.phpt
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
--TEST--
|
||||||
|
GC 017: GC and destructors with unset
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Node {
|
||||||
|
public $name;
|
||||||
|
public $children;
|
||||||
|
public $parent;
|
||||||
|
function __construct($name) {
|
||||||
|
$this->name = $name;
|
||||||
|
$this->children = array();
|
||||||
|
$this->parent = null;
|
||||||
|
}
|
||||||
|
function insert($node) {
|
||||||
|
$node->parent = $this;
|
||||||
|
$this->children[] = $node;
|
||||||
|
}
|
||||||
|
function __destruct() {
|
||||||
|
var_dump($this->name);
|
||||||
|
unset($this->name);
|
||||||
|
unset($this->children);
|
||||||
|
unset($this->parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$a = new Node('A');
|
||||||
|
$b = new Node('B');
|
||||||
|
$c = new Node('C');
|
||||||
|
$a->insert($b);
|
||||||
|
$a->insert($c);
|
||||||
|
unset($a);
|
||||||
|
unset($b);
|
||||||
|
unset($c);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
string(1) "%s"
|
||||||
|
string(1) "%s"
|
||||||
|
string(1) "%s"
|
||||||
|
int(10)
|
||||||
|
ok
|
||||||
|
--UEXPECTF--
|
||||||
|
unicode(1) "%s"
|
||||||
|
unicode(1) "%s"
|
||||||
|
unicode(1) "%s"
|
||||||
|
int(10)
|
||||||
|
ok
|
13
Zend/tests/gc_018.phpt
Normal file
13
Zend/tests/gc_018.phpt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
--TEST--
|
||||||
|
GC 018: GC detach with assign
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = array(array());
|
||||||
|
$a[0][0] =& $a[0];
|
||||||
|
$a = 1;
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
int(1)
|
||||||
|
ok
|
14
Zend/tests/gc_019.phpt
Normal file
14
Zend/tests/gc_019.phpt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
--TEST--
|
||||||
|
GC 019: GC detach with assign by reference
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = array(array());
|
||||||
|
$a[0][0] =& $a[0];
|
||||||
|
$b = 1;
|
||||||
|
$a =& $b;
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
int(1)
|
||||||
|
ok
|
15
Zend/tests/gc_020.phpt
Normal file
15
Zend/tests/gc_020.phpt
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
--TEST--
|
||||||
|
GC 020: GC detach reference with assign
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = array();
|
||||||
|
$a[0] =& $a;
|
||||||
|
$a[1] = array();
|
||||||
|
$a[1][0] =& $a[1];
|
||||||
|
$a = 1;
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
int(1)
|
||||||
|
ok
|
16
Zend/tests/gc_021.phpt
Normal file
16
Zend/tests/gc_021.phpt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
--TEST--
|
||||||
|
GC 021: GC detach reference with assign by reference
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = array();
|
||||||
|
$a[0] =& $a;
|
||||||
|
$a[1] = array();
|
||||||
|
$a[1][0] =& $a[1];
|
||||||
|
$b = 1;
|
||||||
|
$a =& $b;
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
int(2)
|
||||||
|
ok
|
15
Zend/tests/gc_022.phpt
Normal file
15
Zend/tests/gc_022.phpt
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
--TEST--
|
||||||
|
GC 022: GC detach reference in executor's PZVAL_UNLOCK()
|
||||||
|
--INI--
|
||||||
|
error_reporting=0
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = array(array());
|
||||||
|
$a[0][0] =& $a[0];
|
||||||
|
$s = array(1) + unserialize(serialize(&$a[0]));
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
int(1)
|
||||||
|
ok
|
27
Zend/tests/gc_023.phpt
Normal file
27
Zend/tests/gc_023.phpt
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
--TEST--
|
||||||
|
GC 023: Root buffer overflow (automatic collection)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a=array();
|
||||||
|
for ($i=0; $i < 9999; $i++) {
|
||||||
|
$a[$i] = array(array());
|
||||||
|
$a[$i][0] = & $a[$i];
|
||||||
|
}
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
unset($a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
$a=array();
|
||||||
|
for ($i=0; $i < 10001; $i++) {
|
||||||
|
$a[$i] = array(array());
|
||||||
|
$a[$i][0] = & $a[$i];
|
||||||
|
}
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
unset($a); // 10000 zvals collected automatic
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n";
|
||||||
|
--EXPECT--
|
||||||
|
int(0)
|
||||||
|
int(9999)
|
||||||
|
int(0)
|
||||||
|
int(1)
|
||||||
|
ok
|
16
Zend/tests/gc_024.phpt
Normal file
16
Zend/tests/gc_024.phpt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
--TEST--
|
||||||
|
GC 024: GC and objects with non-standard handlers
|
||||||
|
--SKIPIF--
|
||||||
|
<?php if (!extension_loaded("spl")) print "skip"; ?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = new ArrayObject();
|
||||||
|
$a[0] = $a;
|
||||||
|
//var_dump($a);
|
||||||
|
unset($a);
|
||||||
|
var_dump(gc_collect_cycles());
|
||||||
|
echo "ok\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
int(1)
|
||||||
|
ok
|
11
Zend/tests/gc_025.phpt
Normal file
11
Zend/tests/gc_025.phpt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
--TEST--
|
||||||
|
GC 025: Automatic GC on request shutdown
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = array(array());
|
||||||
|
$a[0][0] =& $a[0];
|
||||||
|
unset($a);
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
ok
|
14
Zend/tests/gc_026.phpt
Normal file
14
Zend/tests/gc_026.phpt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
--TEST--
|
||||||
|
GC 026: Automatic GC on request shutdown (GC enabled at run-time)
|
||||||
|
--INI--
|
||||||
|
zend.enable_gc=0
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
gc_enable();
|
||||||
|
$a = array(array());
|
||||||
|
$a[0][0] =& $a[0];
|
||||||
|
unset($a);
|
||||||
|
echo "ok\n"
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
ok
|
21
Zend/zend.c
21
Zend/zend.c
|
@ -172,9 +172,23 @@ void zend_update_converters_error_behavior(TSRMLS_D) /* {{{ */
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
static ZEND_INI_MH(OnUpdateGCEnabled) /* {{{ */
|
||||||
|
{
|
||||||
|
OnUpdateBool(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
|
||||||
|
|
||||||
|
if (GC_G(gc_enabled)) {
|
||||||
|
gc_init(TSRMLS_C);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
ZEND_INI_BEGIN()
|
ZEND_INI_BEGIN()
|
||||||
ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting)
|
ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting)
|
||||||
|
|
||||||
|
STD_ZEND_INI_BOOLEAN("zend.enable_gc", "1", ZEND_INI_ALL, OnUpdateGCEnabled, gc_enabled, zend_gc_globals, gc_globals)
|
||||||
|
|
||||||
/* Unicode .ini entries */
|
/* Unicode .ini entries */
|
||||||
STD_ZEND_INI_BOOLEAN("unicode.semantics", "0", ZEND_INI_SYSTEM, OnUpdateBool, unicode, zend_unicode_globals, unicode_globals)
|
STD_ZEND_INI_BOOLEAN("unicode.semantics", "0", ZEND_INI_SYSTEM, OnUpdateBool, unicode, zend_unicode_globals, unicode_globals)
|
||||||
STD_ZEND_INI_ENTRY("unicode.fallback_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, fallback_encoding_conv, zend_unicode_globals, unicode_globals)
|
STD_ZEND_INI_ENTRY("unicode.fallback_encoding", NULL, ZEND_INI_ALL, OnUpdateEncoding, fallback_encoding_conv, zend_unicode_globals, unicode_globals)
|
||||||
|
@ -1324,6 +1338,7 @@ static void shutdown_unicode_request_globals(TSRMLS_D) /* {{{ */
|
||||||
|
|
||||||
void zend_activate(TSRMLS_D) /* {{{ */
|
void zend_activate(TSRMLS_D) /* {{{ */
|
||||||
{
|
{
|
||||||
|
gc_reset(TSRMLS_C);
|
||||||
init_unicode_request_globals(TSRMLS_C);
|
init_unicode_request_globals(TSRMLS_C);
|
||||||
init_unicode_strings();
|
init_unicode_strings();
|
||||||
init_compiler(TSRMLS_C);
|
init_compiler(TSRMLS_C);
|
||||||
|
@ -1377,6 +1392,12 @@ void zend_deactivate(TSRMLS_D) /* {{{ */
|
||||||
|
|
||||||
zend_destroy_rsrc_list(&EG(regular_list) TSRMLS_CC);
|
zend_destroy_rsrc_list(&EG(regular_list) TSRMLS_CC);
|
||||||
|
|
||||||
|
#ifdef ZEND_DEBUG
|
||||||
|
if (GC_G(gc_enabled) && !CG(unclean_shutdown)) {
|
||||||
|
gc_collect_cycles(TSRMLS_C);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
zend_try {
|
zend_try {
|
||||||
zend_ini_deactivate(TSRMLS_C);
|
zend_ini_deactivate(TSRMLS_C);
|
||||||
} zend_end_try();
|
} zend_end_try();
|
||||||
|
|
|
@ -762,6 +762,7 @@ END_EXTERN_C()
|
||||||
|
|
||||||
#define ZEND_INTERNAL_ENCODING "UTF-16"
|
#define ZEND_INTERNAL_ENCODING "UTF-16"
|
||||||
|
|
||||||
|
#include "zend_gc.h"
|
||||||
#include "zend_operators.h"
|
#include "zend_operators.h"
|
||||||
#include "zend_variables.h"
|
#include "zend_variables.h"
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,10 @@ static ZEND_FUNCTION(zend_test_func);
|
||||||
static ZEND_FUNCTION(zend_thread_id);
|
static ZEND_FUNCTION(zend_thread_id);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
static ZEND_FUNCTION(gc_collect_cycles);
|
||||||
|
static ZEND_FUNCTION(gc_enabled);
|
||||||
|
static ZEND_FUNCTION(gc_enable);
|
||||||
|
static ZEND_FUNCTION(gc_disable);
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
#include "zend_arg_defs.c"
|
#include "zend_arg_defs.c"
|
||||||
|
@ -148,6 +152,10 @@ static const zend_function_entry builtin_functions[] = { /* {{{ */
|
||||||
ZEND_FE(zend_thread_id, NULL)
|
ZEND_FE(zend_thread_id, NULL)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
ZEND_FE(gc_collect_cycles, NULL)
|
||||||
|
ZEND_FE(gc_enabled, NULL)
|
||||||
|
ZEND_FE(gc_enable, NULL)
|
||||||
|
ZEND_FE(gc_disable, NULL)
|
||||||
{ NULL, NULL, NULL }
|
{ NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
@ -2326,6 +2334,39 @@ ZEND_FUNCTION(get_extension_funcs)
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto int gc_collect_cycles(void)
|
||||||
|
Forces collection of any existing garbage cycles.
|
||||||
|
Returns number of freed zvals */
|
||||||
|
ZEND_FUNCTION(gc_collect_cycles)
|
||||||
|
{
|
||||||
|
RETURN_LONG(gc_collect_cycles(TSRMLS_C));
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto void gc_enabled(void)
|
||||||
|
Returns status of the circular reference collector */
|
||||||
|
ZEND_FUNCTION(gc_enabled)
|
||||||
|
{
|
||||||
|
RETURN_BOOL(GC_G(gc_enabled));
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto void gc_enable(void)
|
||||||
|
Activates the circular reference collector */
|
||||||
|
ZEND_FUNCTION(gc_enable)
|
||||||
|
{
|
||||||
|
zend_alter_ini_entry("zend.enable_gc", sizeof("zend.enable_gc"), "1", sizeof("1")-1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto void gc_disable(void)
|
||||||
|
Deactivates the circular reference collector */
|
||||||
|
ZEND_FUNCTION(gc_disable)
|
||||||
|
{
|
||||||
|
zend_alter_ini_entry("zend.enable_gc", sizeof("zend.enable_gc"), "0", sizeof("0")-1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local variables:
|
* Local variables:
|
||||||
* tab-width: 4
|
* tab-width: 4
|
||||||
|
|
|
@ -65,7 +65,7 @@ static void zend_extension_fcall_end_handler(zend_extension *extension, zend_op_
|
||||||
|
|
||||||
#define TEMP_VAR_STACK_LIMIT 2000
|
#define TEMP_VAR_STACK_LIMIT 2000
|
||||||
|
|
||||||
static inline void zend_pzval_unlock_func(zval *z, zend_free_op *should_free, int unref) /* {{{ */
|
static inline void zend_pzval_unlock_func(zval *z, zend_free_op *should_free, int unref TSRMLS_DC) /* {{{ */
|
||||||
{
|
{
|
||||||
if (!Z_DELREF_P(z)) {
|
if (!Z_DELREF_P(z)) {
|
||||||
Z_SET_REFCOUNT_P(z, 1);
|
Z_SET_REFCOUNT_P(z, 1);
|
||||||
|
@ -77,6 +77,7 @@ static inline void zend_pzval_unlock_func(zval *z, zend_free_op *should_free, in
|
||||||
if (unref && Z_ISREF_P(z) && Z_REFCOUNT_P(z) == 1) {
|
if (unref && Z_ISREF_P(z) && Z_REFCOUNT_P(z) == 1) {
|
||||||
Z_UNSET_ISREF_P(z);
|
Z_UNSET_ISREF_P(z);
|
||||||
}
|
}
|
||||||
|
GC_ZVAL_CHECK_POSSIBLE_ROOT(z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
@ -84,14 +85,15 @@ static inline void zend_pzval_unlock_func(zval *z, zend_free_op *should_free, in
|
||||||
static inline void zend_pzval_unlock_free_func(zval *z) /* {{{ */
|
static inline void zend_pzval_unlock_free_func(zval *z) /* {{{ */
|
||||||
{
|
{
|
||||||
if (!Z_DELREF_P(z)) {
|
if (!Z_DELREF_P(z)) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
safe_free_zval_ptr(z);
|
safe_free_zval_ptr(z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
#define PZVAL_UNLOCK(z, f) zend_pzval_unlock_func(z, f, 1)
|
#define PZVAL_UNLOCK(z, f) zend_pzval_unlock_func(z, f, 1 TSRMLS_CC)
|
||||||
#define PZVAL_UNLOCK_EX(z, f, u) zend_pzval_unlock_func(z, f, u)
|
#define PZVAL_UNLOCK_EX(z, f, u) zend_pzval_unlock_func(z, f, u TSRMLS_CC)
|
||||||
#define PZVAL_UNLOCK_FREE(z) zend_pzval_unlock_free_func(z)
|
#define PZVAL_UNLOCK_FREE(z) zend_pzval_unlock_free_func(z)
|
||||||
#define PZVAL_LOCK(z) Z_ADDREF_P((z))
|
#define PZVAL_LOCK(z) Z_ADDREF_P((z))
|
||||||
#define RETURN_VALUE_UNUSED(pzn) (((pzn)->u.EA.type & EXT_TYPE_UNUSED))
|
#define RETURN_VALUE_UNUSED(pzn) (((pzn)->u.EA.type & EXT_TYPE_UNUSED))
|
||||||
|
@ -792,6 +794,7 @@ static inline zval* zend_assign_to_variable(zval **variable_ptr_ptr, zval *value
|
||||||
} else {
|
} else {
|
||||||
Z_ADDREF_P(value);
|
Z_ADDREF_P(value);
|
||||||
*variable_ptr_ptr = value;
|
*variable_ptr_ptr = value;
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(variable_ptr);
|
||||||
zendi_zval_dtor(*variable_ptr);
|
zendi_zval_dtor(*variable_ptr);
|
||||||
safe_free_zval_ptr(variable_ptr);
|
safe_free_zval_ptr(variable_ptr);
|
||||||
return value;
|
return value;
|
||||||
|
|
|
@ -445,10 +445,16 @@ ZEND_API void _zval_ptr_dtor(zval **zval_ptr ZEND_FILE_LINE_DC) /* {{{ */
|
||||||
#endif
|
#endif
|
||||||
Z_DELREF_PP(zval_ptr);
|
Z_DELREF_PP(zval_ptr);
|
||||||
if (Z_REFCOUNT_PP(zval_ptr) == 0) {
|
if (Z_REFCOUNT_PP(zval_ptr) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(*zval_ptr);
|
||||||
zval_dtor(*zval_ptr);
|
zval_dtor(*zval_ptr);
|
||||||
safe_free_zval_ptr_rel(*zval_ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC);
|
safe_free_zval_ptr_rel(*zval_ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_CC);
|
||||||
} else if (Z_REFCOUNT_PP(zval_ptr) == 1) {
|
} else {
|
||||||
Z_UNSET_ISREF_PP(zval_ptr);
|
TSRMLS_FETCH();
|
||||||
|
|
||||||
|
if (Z_REFCOUNT_PP(zval_ptr) == 1) {
|
||||||
|
Z_UNSET_ISREF_PP(zval_ptr);
|
||||||
|
}
|
||||||
|
GC_ZVAL_CHECK_POSSIBLE_ROOT(*zval_ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
516
Zend/zend_gc.c
Normal file
516
Zend/zend_gc.c
Normal file
|
@ -0,0 +1,516 @@
|
||||||
|
/*
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Zend Engine |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Copyright (c) 1998-2007 Zend Technologies Ltd. (http://www.zend.com) |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| This source file is subject to version 2.00 of the Zend license, |
|
||||||
|
| that is bundled with this package in the file LICENSE, and is |
|
||||||
|
| available through the world-wide-web at the following url: |
|
||||||
|
| http://www.zend.com/license/2_00.txt. |
|
||||||
|
| If you did not receive a copy of the Zend license and are unable to |
|
||||||
|
| obtain it through the world-wide-web, please send a note to |
|
||||||
|
| license@zend.com so we can mail you a copy immediately. |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Authors: David Wang <planetbeing@gmail.com> |
|
||||||
|
| Dmitry Stogov <dmitry@zend.com> |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
#include "zend.h"
|
||||||
|
#include "zend_API.h"
|
||||||
|
|
||||||
|
#define GC_ROOT_BUFFER_MAX_ENTRIES 10000
|
||||||
|
|
||||||
|
#ifdef ZTS
|
||||||
|
ZEND_API int gc_globals_id;
|
||||||
|
#else
|
||||||
|
ZEND_API zend_gc_globals gc_globals;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Forward declarations */
|
||||||
|
static int children_scan_black(zval **pz TSRMLS_DC);
|
||||||
|
static int children_mark_grey(zval **pz TSRMLS_DC);
|
||||||
|
static int children_collect_white(zval **pz TSRMLS_DC);
|
||||||
|
static int children_scan(zval **pz TSRMLS_DC);
|
||||||
|
|
||||||
|
static void root_buffer_dtor(zend_gc_globals *gc_globals TSRMLS_DC)
|
||||||
|
{
|
||||||
|
if (gc_globals->buf) {
|
||||||
|
free(gc_globals->buf);
|
||||||
|
gc_globals->buf = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gc_globals_ctor_ex(zend_gc_globals *gc_globals TSRMLS_DC)
|
||||||
|
{
|
||||||
|
gc_globals->gc_enabled = 0;
|
||||||
|
|
||||||
|
gc_globals->buf = NULL;
|
||||||
|
|
||||||
|
gc_globals->roots.next = NULL;
|
||||||
|
gc_globals->roots.prev = NULL;
|
||||||
|
gc_globals->unused = NULL;
|
||||||
|
gc_globals->zval_to_free = NULL;
|
||||||
|
|
||||||
|
gc_globals->gc_runs = 0;
|
||||||
|
gc_globals->collected = 0;
|
||||||
|
|
||||||
|
#if GC_BENCH
|
||||||
|
gc_globals->root_buf_length = 0;
|
||||||
|
gc_globals->root_buf_peak = 0;
|
||||||
|
gc_globals->zval_possible_root = 0;
|
||||||
|
gc_globals->zobj_possible_root = 0;
|
||||||
|
gc_globals->zval_buffered = 0;
|
||||||
|
gc_globals->zobj_buffered = 0;
|
||||||
|
gc_globals->zval_remove_from_buffer = 0;
|
||||||
|
gc_globals->zobj_remove_from_buffer = 0;
|
||||||
|
gc_globals->zval_marked_grey = 0;
|
||||||
|
gc_globals->zobj_marked_grey = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ZEND_API void gc_globals_ctor(TSRMLS_D)
|
||||||
|
{
|
||||||
|
#ifdef ZTS
|
||||||
|
ts_allocate_id(&gc_globals_id, sizeof(zend_gc_globals), (ts_allocate_ctor) gc_globals_ctor_ex, (ts_allocate_dtor) root_buffer_dtor);
|
||||||
|
#else
|
||||||
|
gc_globals_ctor_ex(&gc_globals);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ZEND_API void gc_globals_dtor(TSRMLS_D)
|
||||||
|
{
|
||||||
|
#ifndef ZTS
|
||||||
|
root_buffer_dtor(&gc_globals TSRMLS_DC);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ZEND_API void gc_reset(TSRMLS_D)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
GC_G(gc_runs) = 0;
|
||||||
|
GC_G(collected) = 0;
|
||||||
|
|
||||||
|
#if GC_BENCH
|
||||||
|
GC_G(root_buf_length) = 0;
|
||||||
|
GC_G(root_buf_peak) = 0;
|
||||||
|
GC_G(zval_possible_root) = 0;
|
||||||
|
GC_G(zobj_possible_root) = 0;
|
||||||
|
GC_G(zval_buffered) = 0;
|
||||||
|
GC_G(zobj_buffered) = 0;
|
||||||
|
GC_G(zval_remove_from_buffer) = 0;
|
||||||
|
GC_G(zobj_remove_from_buffer) = 0;
|
||||||
|
GC_G(zval_marked_grey) = 0;
|
||||||
|
GC_G(zobj_marked_grey) = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (GC_G(buf) &&
|
||||||
|
(GC_G(roots).next != &GC_G(roots) ||
|
||||||
|
GC_G(roots).prev != &GC_G(roots))) {
|
||||||
|
|
||||||
|
GC_G(roots).next = &GC_G(roots);
|
||||||
|
GC_G(roots).prev = &GC_G(roots);
|
||||||
|
|
||||||
|
GC_G(unused) = &GC_G(buf)[0];
|
||||||
|
for (i = 0; i < GC_ROOT_BUFFER_MAX_ENTRIES-1; i++) {
|
||||||
|
GC_G(buf)[i].prev = &GC_G(buf)[i+1];
|
||||||
|
}
|
||||||
|
GC_G(buf)[GC_ROOT_BUFFER_MAX_ENTRIES-1].prev = NULL;
|
||||||
|
|
||||||
|
GC_G(zval_to_free) = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ZEND_API void gc_init(TSRMLS_D)
|
||||||
|
{
|
||||||
|
if (GC_G(buf) == NULL && GC_G(gc_enabled)) {
|
||||||
|
GC_G(buf) = (gc_root_buffer*) malloc(sizeof(gc_root_buffer) * GC_ROOT_BUFFER_MAX_ENTRIES);
|
||||||
|
gc_reset(TSRMLS_C);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ZEND_API void gc_zval_possible_root(zval *zv TSRMLS_DC)
|
||||||
|
{
|
||||||
|
if (zv->type == IS_OBJECT) {
|
||||||
|
GC_ZOBJ_CHECK_POSSIBLE_ROOT(zv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GC_BENCH_INC(zval_possible_root);
|
||||||
|
|
||||||
|
if (GC_ZVAL_GET_COLOR(zv) != GC_PURPLE) {
|
||||||
|
GC_ZVAL_SET_PURPLE(zv);
|
||||||
|
|
||||||
|
if (!GC_ZVAL_ADDRESS(zv)) {
|
||||||
|
gc_root_buffer *newRoot = GC_G(unused);
|
||||||
|
|
||||||
|
if (!newRoot) {
|
||||||
|
if (!GC_G(gc_enabled)) {
|
||||||
|
GC_ZVAL_SET_BLACK(zv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
zv->refcount__gc++;
|
||||||
|
gc_collect_cycles(TSRMLS_C);
|
||||||
|
zv->refcount__gc--;
|
||||||
|
GC_ZVAL_SET_PURPLE(zv);
|
||||||
|
newRoot = GC_G(unused);
|
||||||
|
}
|
||||||
|
|
||||||
|
GC_G(unused) = newRoot->prev;
|
||||||
|
|
||||||
|
newRoot->next = GC_G(roots).next;
|
||||||
|
newRoot->prev = &GC_G(roots);
|
||||||
|
GC_G(roots).next->prev = newRoot;
|
||||||
|
GC_G(roots).next = newRoot;
|
||||||
|
|
||||||
|
GC_ZVAL_SET_ADDRESS(zv, newRoot);
|
||||||
|
|
||||||
|
newRoot->handle = 0;
|
||||||
|
newRoot->u.pz = zv;
|
||||||
|
|
||||||
|
GC_BENCH_INC(zval_buffered);
|
||||||
|
GC_BENCH_INC(root_buf_length);
|
||||||
|
GC_BENCH_PEAK(root_buf_peak, root_buf_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ZEND_API void gc_zobj_possible_root(zval *zv TSRMLS_DC)
|
||||||
|
{
|
||||||
|
struct _store_object *obj;
|
||||||
|
|
||||||
|
if (UNEXPECTED(Z_OBJ_HT_P(zv)->get_properties == NULL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GC_BENCH_INC(zobj_possible_root);
|
||||||
|
|
||||||
|
obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zv)].bucket.obj;
|
||||||
|
if (GC_GET_COLOR(obj->buffered) != GC_PURPLE) {
|
||||||
|
GC_SET_PURPLE(obj->buffered);
|
||||||
|
if (!GC_ADDRESS(obj->buffered)) {
|
||||||
|
gc_root_buffer *newRoot = GC_G(unused);
|
||||||
|
|
||||||
|
if (!newRoot) {
|
||||||
|
if (!GC_G(gc_enabled)) {
|
||||||
|
GC_ZVAL_SET_BLACK(zv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
zv->refcount__gc++;
|
||||||
|
gc_collect_cycles(TSRMLS_C);
|
||||||
|
zv->refcount__gc--;
|
||||||
|
GC_SET_PURPLE(obj->buffered);
|
||||||
|
newRoot = GC_G(unused);
|
||||||
|
}
|
||||||
|
|
||||||
|
GC_G(unused) = newRoot->prev;
|
||||||
|
|
||||||
|
newRoot->next = GC_G(roots).next;
|
||||||
|
newRoot->prev = &GC_G(roots);
|
||||||
|
GC_G(roots).next->prev = newRoot;
|
||||||
|
GC_G(roots).next = newRoot;
|
||||||
|
|
||||||
|
GC_SET_ADDRESS(obj->buffered, newRoot);
|
||||||
|
|
||||||
|
newRoot->handle = Z_OBJ_HANDLE_P(zv);
|
||||||
|
newRoot->u.handlers = Z_OBJ_HT_P(zv);
|
||||||
|
|
||||||
|
GC_BENCH_INC(zobj_buffered);
|
||||||
|
GC_BENCH_INC(root_buf_length);
|
||||||
|
GC_BENCH_PEAK(root_buf_peak, root_buf_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zobj_scan_black(struct _store_object *obj, zval *pz TSRMLS_DC)
|
||||||
|
{
|
||||||
|
GC_SET_BLACK(obj->buffered);
|
||||||
|
|
||||||
|
if (EXPECTED(Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
|
||||||
|
zend_hash_apply(Z_OBJPROP_P(pz), (apply_func_t) children_scan_black TSRMLS_CC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zval_scan_black(zval *pz TSRMLS_DC)
|
||||||
|
{
|
||||||
|
GC_ZVAL_SET_BLACK(pz);
|
||||||
|
|
||||||
|
if (Z_TYPE_P(pz) == IS_OBJECT) {
|
||||||
|
struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
|
||||||
|
|
||||||
|
obj->refcount++;
|
||||||
|
if (GC_GET_COLOR(obj->buffered) != GC_BLACK) {
|
||||||
|
zobj_scan_black(obj, pz TSRMLS_CC);
|
||||||
|
}
|
||||||
|
} else if (Z_TYPE_P(pz) == IS_ARRAY) {
|
||||||
|
if (Z_ARRVAL_P(pz) != &EG(symbol_table)) {
|
||||||
|
zend_hash_apply(Z_ARRVAL_P(pz), (apply_func_t) children_scan_black TSRMLS_CC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int children_scan_black(zval **pz TSRMLS_DC)
|
||||||
|
{
|
||||||
|
(*pz)->refcount__gc++;
|
||||||
|
|
||||||
|
if (GC_ZVAL_GET_COLOR(*pz) != GC_BLACK) {
|
||||||
|
zval_scan_black(*pz TSRMLS_CC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zobj_mark_grey(struct _store_object *obj, zval *pz TSRMLS_DC)
|
||||||
|
{
|
||||||
|
if (GC_GET_COLOR(obj->buffered) != GC_GREY) {
|
||||||
|
GC_BENCH_INC(zobj_marked_grey);
|
||||||
|
GC_SET_COLOR(obj->buffered, GC_GREY);
|
||||||
|
if (EXPECTED(Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
|
||||||
|
zend_hash_apply(Z_OBJPROP_P(pz), (apply_func_t) children_mark_grey TSRMLS_CC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zval_mark_grey(zval *pz TSRMLS_DC)
|
||||||
|
{
|
||||||
|
if (GC_ZVAL_GET_COLOR(pz) != GC_GREY) {
|
||||||
|
GC_BENCH_INC(zval_marked_grey);
|
||||||
|
GC_ZVAL_SET_COLOR(pz, GC_GREY);
|
||||||
|
|
||||||
|
if (Z_TYPE_P(pz) == IS_OBJECT) {
|
||||||
|
struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
|
||||||
|
|
||||||
|
obj->refcount--;
|
||||||
|
zobj_mark_grey(obj, pz TSRMLS_CC);
|
||||||
|
} else if (Z_TYPE_P(pz) == IS_ARRAY) {
|
||||||
|
if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
|
||||||
|
GC_ZVAL_SET_BLACK(pz);
|
||||||
|
} else {
|
||||||
|
zend_hash_apply(Z_ARRVAL_P(pz), (apply_func_t) children_mark_grey TSRMLS_CC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int children_mark_grey(zval **pz TSRMLS_DC)
|
||||||
|
{
|
||||||
|
(*pz)->refcount__gc--;
|
||||||
|
zval_mark_grey(*pz TSRMLS_CC);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gc_mark_roots(TSRMLS_D)
|
||||||
|
{
|
||||||
|
gc_root_buffer *current = GC_G(roots).next;
|
||||||
|
|
||||||
|
while (current != &GC_G(roots)) {
|
||||||
|
if (current->handle) {
|
||||||
|
struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj;
|
||||||
|
|
||||||
|
if (GC_GET_COLOR(obj->buffered) == GC_PURPLE) {
|
||||||
|
zval z;
|
||||||
|
|
||||||
|
INIT_PZVAL(&z);
|
||||||
|
Z_OBJ_HANDLE(z) = current->handle;
|
||||||
|
Z_OBJ_HT(z) = current->u.handlers;
|
||||||
|
zobj_mark_grey(obj, &z TSRMLS_CC);
|
||||||
|
} else {
|
||||||
|
GC_SET_ADDRESS(obj->buffered, NULL);
|
||||||
|
GC_REMOVE_FROM_BUFFER(current);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (GC_ZVAL_GET_COLOR(current->u.pz) == GC_PURPLE) {
|
||||||
|
zval_mark_grey(current->u.pz TSRMLS_CC);
|
||||||
|
} else {
|
||||||
|
GC_ZVAL_SET_ADDRESS(current->u.pz, NULL);
|
||||||
|
GC_REMOVE_FROM_BUFFER(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zobj_scan(zval *pz TSRMLS_DC)
|
||||||
|
{
|
||||||
|
struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
|
||||||
|
|
||||||
|
if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
|
||||||
|
if (obj->refcount > 0) {
|
||||||
|
zobj_scan_black(obj, pz TSRMLS_CC);
|
||||||
|
} else {
|
||||||
|
GC_SET_COLOR(obj->buffered, GC_WHITE);
|
||||||
|
if (EXPECTED(Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
|
||||||
|
zend_hash_apply(Z_OBJPROP_P(pz), (apply_func_t) children_scan TSRMLS_CC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zval_scan(zval *pz TSRMLS_DC)
|
||||||
|
{
|
||||||
|
if (GC_ZVAL_GET_COLOR(pz) == GC_GREY) {
|
||||||
|
if (pz->refcount__gc > 0) {
|
||||||
|
zval_scan_black(pz TSRMLS_CC);
|
||||||
|
} else {
|
||||||
|
GC_ZVAL_SET_COLOR(pz, GC_WHITE);
|
||||||
|
|
||||||
|
if (Z_TYPE_P(pz) == IS_OBJECT) {
|
||||||
|
zobj_scan(pz TSRMLS_CC);
|
||||||
|
} else if (Z_TYPE_P(pz) == IS_ARRAY) {
|
||||||
|
if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
|
||||||
|
GC_ZVAL_SET_BLACK(pz);
|
||||||
|
} else {
|
||||||
|
zend_hash_apply(Z_ARRVAL_P(pz), (apply_func_t) children_scan TSRMLS_CC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int children_scan(zval **pz TSRMLS_DC)
|
||||||
|
{
|
||||||
|
zval_scan(*pz TSRMLS_CC);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gc_scan_roots(TSRMLS_D)
|
||||||
|
{
|
||||||
|
gc_root_buffer *current = GC_G(roots).next;
|
||||||
|
|
||||||
|
while (current != &GC_G(roots)) {
|
||||||
|
if (current->handle) {
|
||||||
|
zval z;
|
||||||
|
|
||||||
|
INIT_PZVAL(&z);
|
||||||
|
Z_OBJ_HANDLE(z) = current->handle;
|
||||||
|
Z_OBJ_HT(z) = current->u.handlers;
|
||||||
|
zobj_scan(&z TSRMLS_CC);
|
||||||
|
} else {
|
||||||
|
zval_scan(current->u.pz TSRMLS_CC);
|
||||||
|
}
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zobj_collect_white(zval *pz TSRMLS_DC)
|
||||||
|
{
|
||||||
|
zend_object_handle handle = Z_OBJ_HANDLE_P(pz);
|
||||||
|
struct _store_object *obj = &EG(objects_store).object_buckets[handle].bucket.obj;
|
||||||
|
|
||||||
|
if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
|
||||||
|
GC_SET_BLACK(obj->buffered);
|
||||||
|
|
||||||
|
if (EXPECTED(Z_OBJ_HANDLER_P(pz, get_properties) != NULL)) {
|
||||||
|
zend_hash_apply(Z_OBJPROP_P(pz), (apply_func_t) children_collect_white TSRMLS_CC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zval_collect_white(zval *pz TSRMLS_DC)
|
||||||
|
{
|
||||||
|
if (((zval_gc_info*)(pz))->u.buffered == (gc_root_buffer*)GC_WHITE) {
|
||||||
|
GC_ZVAL_SET_BLACK(pz);
|
||||||
|
|
||||||
|
if (Z_TYPE_P(pz) == IS_OBJECT) {
|
||||||
|
zobj_collect_white(pz TSRMLS_CC);
|
||||||
|
} else {
|
||||||
|
if (Z_TYPE_P(pz) == IS_ARRAY) {
|
||||||
|
if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
zend_hash_apply(Z_ARRVAL_P(pz), (apply_func_t) children_collect_white TSRMLS_CC);
|
||||||
|
}
|
||||||
|
/* restore refcount */
|
||||||
|
pz->refcount__gc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
((zval_gc_info*)pz)->u.next = GC_G(zval_to_free);
|
||||||
|
GC_G(zval_to_free) = (zval_gc_info*)pz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int children_collect_white(zval **pz TSRMLS_DC)
|
||||||
|
{
|
||||||
|
zval_collect_white(*pz TSRMLS_CC);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gc_collect_roots(TSRMLS_D)
|
||||||
|
{
|
||||||
|
gc_root_buffer *current = GC_G(roots).next;
|
||||||
|
|
||||||
|
while (current != &GC_G(roots)) {
|
||||||
|
if (current->handle) {
|
||||||
|
struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj;
|
||||||
|
zval z;
|
||||||
|
|
||||||
|
GC_SET_ADDRESS(obj->buffered, NULL);
|
||||||
|
INIT_PZVAL(&z);
|
||||||
|
Z_OBJ_HANDLE(z) = current->handle;
|
||||||
|
Z_OBJ_HT(z) = current->u.handlers;
|
||||||
|
zobj_collect_white(&z TSRMLS_CC);
|
||||||
|
} else {
|
||||||
|
GC_ZVAL_SET_ADDRESS(current->u.pz, NULL);
|
||||||
|
zval_collect_white(current->u.pz TSRMLS_CC);
|
||||||
|
}
|
||||||
|
|
||||||
|
GC_REMOVE_FROM_BUFFER(current);
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ZEND_API int gc_collect_cycles(TSRMLS_D)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
if (GC_G(roots).next != &GC_G(roots)) {
|
||||||
|
zval_gc_info *p, *q;
|
||||||
|
|
||||||
|
GC_G(gc_runs)++;
|
||||||
|
GC_G(zval_to_free) = NULL;
|
||||||
|
gc_mark_roots(TSRMLS_C);
|
||||||
|
gc_scan_roots(TSRMLS_C);
|
||||||
|
gc_collect_roots(TSRMLS_C);
|
||||||
|
|
||||||
|
p = GC_G(zval_to_free);
|
||||||
|
GC_G(zval_to_free) = NULL;
|
||||||
|
while (p) {
|
||||||
|
q = p->u.next;
|
||||||
|
if (Z_TYPE(p->z) == IS_OBJECT) {
|
||||||
|
if (EG(objects_store).object_buckets &&
|
||||||
|
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
|
||||||
|
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 1) {
|
||||||
|
if (EXPECTED(Z_OBJ_HANDLER(p->z, get_properties) != NULL)) {
|
||||||
|
Z_OBJPROP(p->z)->pDestructor = NULL;
|
||||||
|
}
|
||||||
|
EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount = 1;
|
||||||
|
zend_objects_store_del_ref_by_handle(Z_OBJ_HANDLE(p->z) TSRMLS_CC);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Z_TYPE(p->z) == IS_ARRAY) {
|
||||||
|
Z_ARRVAL(p->z)->pDestructor = NULL;
|
||||||
|
}
|
||||||
|
zval_dtor(&p->z);
|
||||||
|
}
|
||||||
|
FREE_ZVAL_EX(&p->z);
|
||||||
|
p = q;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
GC_G(collected) += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* tab-width: 4
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
245
Zend/zend_gc.h
Normal file
245
Zend/zend_gc.h
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
/*
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Zend Engine |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Copyright (c) 1998-2007 Zend Technologies Ltd. (http://www.zend.com) |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| This source file is subject to version 2.00 of the Zend license, |
|
||||||
|
| that is bundled with this package in the file LICENSE, and is |
|
||||||
|
| available through the world-wide-web at the following url: |
|
||||||
|
| http://www.zend.com/license/2_00.txt. |
|
||||||
|
| If you did not receive a copy of the Zend license and are unable to |
|
||||||
|
| obtain it through the world-wide-web, please send a note to |
|
||||||
|
| license@zend.com so we can mail you a copy immediately. |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Authors: David Wang <planetbeing@gmail.com> |
|
||||||
|
| Dmitry Stogov <dmitry@zend.com> |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
#ifndef ZEND_GC_H
|
||||||
|
#define ZEND_GC_H
|
||||||
|
|
||||||
|
#ifndef GC_BENCH
|
||||||
|
# define GC_BENCH 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if GC_BENCH
|
||||||
|
# define GC_BENCH_INC(counter) GC_G(counter)++
|
||||||
|
# define GC_BENCH_DEC(counter) GC_G(counter)--
|
||||||
|
# define GC_BENCH_PEAK(peak, counter) do { \
|
||||||
|
if (GC_G(counter) > GC_G(peak)) { \
|
||||||
|
GC_G(peak) = GC_G(counter); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
# define GC_BENCH_INC(counter)
|
||||||
|
# define GC_BENCH_DEC(counter)
|
||||||
|
# define GC_BENCH_PEAK(peak, counter)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define GC_COLOR 0x03
|
||||||
|
|
||||||
|
#define GC_BLACK 0x00
|
||||||
|
#define GC_WHITE 0x01
|
||||||
|
#define GC_GREY 0x02
|
||||||
|
#define GC_PURPLE 0x03
|
||||||
|
|
||||||
|
#define GC_ADDRESS(v) \
|
||||||
|
((gc_root_buffer*)(((zend_uintptr_t)(v)) & ~GC_COLOR))
|
||||||
|
#define GC_SET_ADDRESS(v, a) \
|
||||||
|
(v) = ((gc_root_buffer*)((((zend_uintptr_t)(v)) & GC_COLOR) | ((zend_uintptr_t)(a))))
|
||||||
|
#define GC_GET_COLOR(v) \
|
||||||
|
(((zend_uintptr_t)(v)) & GC_COLOR)
|
||||||
|
#define GC_SET_COLOR(v, c) \
|
||||||
|
(v) = ((gc_root_buffer*)((((zend_uintptr_t)(v)) & ~GC_COLOR) | (c)))
|
||||||
|
#define GC_SET_BLACK(v) \
|
||||||
|
(v) = ((gc_root_buffer*)(((zend_uintptr_t)(v)) & ~GC_COLOR))
|
||||||
|
#define GC_SET_PURPLE(v) \
|
||||||
|
(v) = ((gc_root_buffer*)(((zend_uintptr_t)(v)) | GC_PURPLE))
|
||||||
|
|
||||||
|
#define GC_ZVAL_INIT(z) \
|
||||||
|
((zval_gc_info*)(z))->u.buffered = NULL
|
||||||
|
#define GC_ZVAL_ADDRESS(v) \
|
||||||
|
GC_ADDRESS(((zval_gc_info*)(v))->u.buffered)
|
||||||
|
#define GC_ZVAL_SET_ADDRESS(v, a) \
|
||||||
|
GC_SET_ADDRESS(((zval_gc_info*)(v))->u.buffered, (a))
|
||||||
|
#define GC_ZVAL_GET_COLOR(v) \
|
||||||
|
GC_GET_COLOR(((zval_gc_info*)(v))->u.buffered)
|
||||||
|
#define GC_ZVAL_SET_COLOR(v, c) \
|
||||||
|
GC_SET_COLOR(((zval_gc_info*)(v))->u.buffered, (c))
|
||||||
|
#define GC_ZVAL_SET_BLACK(v) \
|
||||||
|
GC_SET_BLACK(((zval_gc_info*)(v))->u.buffered)
|
||||||
|
#define GC_ZVAL_SET_PURPLE(v) \
|
||||||
|
GC_SET_PURPLE(((zval_gc_info*)(v))->u.buffered)
|
||||||
|
|
||||||
|
#define GC_OBJ_INIT(z) \
|
||||||
|
(z)->buffered = NULL
|
||||||
|
|
||||||
|
typedef struct _gc_root_buffer {
|
||||||
|
struct _gc_root_buffer *prev; /* double-linked list */
|
||||||
|
struct _gc_root_buffer *next;
|
||||||
|
zend_object_handle handle; /* must be 0 for zval */
|
||||||
|
union {
|
||||||
|
zval *pz;
|
||||||
|
zend_object_handlers *handlers;
|
||||||
|
} u;
|
||||||
|
} gc_root_buffer;
|
||||||
|
|
||||||
|
typedef struct _zval_gc_info {
|
||||||
|
zval z;
|
||||||
|
union {
|
||||||
|
gc_root_buffer *buffered;
|
||||||
|
struct _zval_gc_info *next;
|
||||||
|
} u;
|
||||||
|
} zval_gc_info;
|
||||||
|
|
||||||
|
typedef struct _zend_gc_globals {
|
||||||
|
zend_bool gc_enabled;
|
||||||
|
|
||||||
|
gc_root_buffer *buf; /* preallocated arrays of buffers */
|
||||||
|
gc_root_buffer roots; /* list of possible roots of cycles */
|
||||||
|
gc_root_buffer *unused; /* list of unused buffers */
|
||||||
|
|
||||||
|
zval_gc_info *zval_to_free; /* temporaryt list of zvals to free */
|
||||||
|
|
||||||
|
zend_uint gc_runs;
|
||||||
|
zend_uint collected;
|
||||||
|
|
||||||
|
#if GC_BENCH
|
||||||
|
zend_uint root_buf_length;
|
||||||
|
zend_uint root_buf_peak;
|
||||||
|
zend_uint zval_possible_root;
|
||||||
|
zend_uint zobj_possible_root;
|
||||||
|
zend_uint zval_buffered;
|
||||||
|
zend_uint zobj_buffered;
|
||||||
|
zend_uint zval_remove_from_buffer;
|
||||||
|
zend_uint zobj_remove_from_buffer;
|
||||||
|
zend_uint zval_marked_grey;
|
||||||
|
zend_uint zobj_marked_grey;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} zend_gc_globals;
|
||||||
|
|
||||||
|
#ifdef ZTS
|
||||||
|
BEGIN_EXTERN_C()
|
||||||
|
ZEND_API extern int gc_globals_id;
|
||||||
|
END_EXTERN_C()
|
||||||
|
#define GC_G(v) TSRMG(gc_globals_id, zend_gc_globals *, v)
|
||||||
|
#else
|
||||||
|
#define GC_G(v) (gc_globals.v)
|
||||||
|
extern ZEND_API zend_gc_globals gc_globals;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BEGIN_EXTERN_C()
|
||||||
|
ZEND_API int gc_collect_cycles(TSRMLS_D);
|
||||||
|
ZEND_API void gc_zval_possible_root(zval *zv TSRMLS_DC);
|
||||||
|
ZEND_API void gc_zobj_possible_root(zval *zv TSRMLS_DC);
|
||||||
|
ZEND_API void gc_globals_ctor(TSRMLS_D);
|
||||||
|
ZEND_API void gc_globals_dtor(TSRMLS_D);
|
||||||
|
ZEND_API void gc_init(TSRMLS_D);
|
||||||
|
ZEND_API void gc_reset(TSRMLS_D);
|
||||||
|
END_EXTERN_C()
|
||||||
|
|
||||||
|
#define GC_ZVAL_CHECK_POSSIBLE_ROOT(z) \
|
||||||
|
gc_zval_check_possible_root((z) TSRMLS_CC)
|
||||||
|
|
||||||
|
#define GC_REMOVE_FROM_BUFFER(current) \
|
||||||
|
gc_remove_from_buffer((current) TSRMLS_CC)
|
||||||
|
|
||||||
|
#define GC_REMOVE_ZVAL_FROM_BUFFER(z) \
|
||||||
|
gc_remove_zval_from_buffer(z)
|
||||||
|
|
||||||
|
#define GC_ZOBJ_CHECK_POSSIBLE_ROOT(zobject) \
|
||||||
|
do { \
|
||||||
|
if (EXPECTED(EG(objects_store).object_buckets != NULL) && \
|
||||||
|
EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zobject)].valid) { \
|
||||||
|
gc_zobj_possible_root(zobject TSRMLS_CC); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define GC_REMOVE_ZOBJ_FROM_BUFFER(obj) \
|
||||||
|
do { \
|
||||||
|
if (GC_ADDRESS((obj)->buffered)) { \
|
||||||
|
GC_BENCH_INC(zobj_remove_from_buffer); \
|
||||||
|
GC_REMOVE_FROM_BUFFER(GC_ADDRESS((obj)->buffered)); \
|
||||||
|
(obj)->buffered = NULL; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static zend_always_inline void gc_zval_check_possible_root(zval *z TSRMLS_DC)
|
||||||
|
{
|
||||||
|
if (z->type == IS_ARRAY || z->type == IS_OBJECT) {
|
||||||
|
gc_zval_possible_root(z TSRMLS_CC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static zend_always_inline void gc_remove_from_buffer(gc_root_buffer *root TSRMLS_DC)
|
||||||
|
{
|
||||||
|
root->next->prev = root->prev;
|
||||||
|
root->prev->next = root->next;
|
||||||
|
root->prev = GC_G(unused);
|
||||||
|
GC_G(unused) = root;
|
||||||
|
GC_BENCH_DEC(root_buf_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static zend_always_inline void gc_remove_zval_from_buffer(zval* z)
|
||||||
|
{
|
||||||
|
gc_root_buffer* root_buffer;
|
||||||
|
|
||||||
|
root_buffer = GC_ADDRESS(((zval_gc_info*)z)->u.buffered);
|
||||||
|
if (root_buffer) {
|
||||||
|
TSRMLS_FETCH();
|
||||||
|
|
||||||
|
GC_BENCH_INC(zval_remove_from_buffer);
|
||||||
|
GC_REMOVE_FROM_BUFFER(root_buffer);
|
||||||
|
((zval_gc_info*)z)->u.buffered = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The following macroses override macroses from zend_alloc.h */
|
||||||
|
#undef ALLOC_ZVAL
|
||||||
|
#define ALLOC_ZVAL(z) \
|
||||||
|
do { \
|
||||||
|
(z) = (zval*)emalloc(sizeof(zval_gc_info)); \
|
||||||
|
GC_ZVAL_INIT(z); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#undef FREE_ZVAL
|
||||||
|
#define FREE_ZVAL(z) \
|
||||||
|
do { \
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z); \
|
||||||
|
efree(z); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#undef ALLOC_ZVAL_REL
|
||||||
|
#define ALLOC_ZVAL_REL(z) \
|
||||||
|
do { \
|
||||||
|
(z) = (zval*)emalloc_rel(sizeof(zval_gc_info)); \
|
||||||
|
GC_ZVAL_INIT(z); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#undef FREE_ZVAL_REL
|
||||||
|
#define FREE_ZVAL_REL(z) \
|
||||||
|
do { \
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z); \
|
||||||
|
efree_rel(z); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define FREE_ZVAL_EX(z) \
|
||||||
|
efree(z)
|
||||||
|
|
||||||
|
#define FREE_ZVAL_REL_EX(z) \
|
||||||
|
efree_rel(z)
|
||||||
|
|
||||||
|
#endif /* ZEND_GC_H */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* tab-width: 4
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* End:
|
||||||
|
*/
|
|
@ -88,6 +88,8 @@ ZEND_API void zend_objects_store_free_object_storage(zend_objects_store *objects
|
||||||
if (objects->object_buckets[i].valid) {
|
if (objects->object_buckets[i].valid) {
|
||||||
struct _store_object *obj = &objects->object_buckets[i].bucket.obj;
|
struct _store_object *obj = &objects->object_buckets[i].bucket.obj;
|
||||||
|
|
||||||
|
GC_REMOVE_ZOBJ_FROM_BUFFER(obj);
|
||||||
|
|
||||||
objects->object_buckets[i].valid = 0;
|
objects->object_buckets[i].valid = 0;
|
||||||
if (obj->free_storage) {
|
if (obj->free_storage) {
|
||||||
obj->free_storage(obj->object TSRMLS_CC);
|
obj->free_storage(obj->object TSRMLS_CC);
|
||||||
|
@ -119,6 +121,7 @@ ZEND_API zend_object_handle zend_objects_store_put(void *object, zend_objects_st
|
||||||
EG(objects_store).object_buckets[handle].valid = 1;
|
EG(objects_store).object_buckets[handle].valid = 1;
|
||||||
|
|
||||||
obj->refcount = 1;
|
obj->refcount = 1;
|
||||||
|
GC_OBJ_INIT(obj);
|
||||||
obj->object = object;
|
obj->object = object;
|
||||||
obj->dtor = dtor?dtor:(zend_objects_store_dtor_t)zend_objects_destroy_object;
|
obj->dtor = dtor?dtor:(zend_objects_store_dtor_t)zend_objects_destroy_object;
|
||||||
obj->free_storage = free_storage;
|
obj->free_storage = free_storage;
|
||||||
|
@ -183,6 +186,8 @@ ZEND_API void zend_objects_store_del_ref(zval *zobject TSRMLS_DC) /* {{{ */
|
||||||
Z_ADDREF_P(zobject);
|
Z_ADDREF_P(zobject);
|
||||||
zend_objects_store_del_ref_by_handle(handle TSRMLS_CC);
|
zend_objects_store_del_ref_by_handle(handle TSRMLS_CC);
|
||||||
Z_DELREF_P(zobject);
|
Z_DELREF_P(zobject);
|
||||||
|
|
||||||
|
GC_ZOBJ_CHECK_POSSIBLE_ROOT(zobject);
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
@ -218,6 +223,7 @@ ZEND_API void zend_objects_store_del_ref_by_handle(zend_object_handle handle TSR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (obj->refcount == 1) {
|
if (obj->refcount == 1) {
|
||||||
|
GC_REMOVE_ZOBJ_FROM_BUFFER(obj);
|
||||||
if (obj->free_storage) {
|
if (obj->free_storage) {
|
||||||
zend_try {
|
zend_try {
|
||||||
obj->free_storage(obj->object TSRMLS_CC);
|
obj->free_storage(obj->object TSRMLS_CC);
|
||||||
|
|
|
@ -38,6 +38,7 @@ typedef struct _zend_object_store_bucket {
|
||||||
zend_objects_free_object_storage_t free_storage;
|
zend_objects_free_object_storage_t free_storage;
|
||||||
zend_objects_store_clone_t clone;
|
zend_objects_store_clone_t clone;
|
||||||
zend_uint refcount;
|
zend_uint refcount;
|
||||||
|
gc_root_buffer *buffered;
|
||||||
} obj;
|
} obj;
|
||||||
struct {
|
struct {
|
||||||
int next;
|
int next;
|
||||||
|
|
|
@ -1920,6 +1920,7 @@ ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_
|
||||||
static inline void zend_free_obj_get_result(zval *op) /* {{{ */
|
static inline void zend_free_obj_get_result(zval *op) /* {{{ */
|
||||||
{
|
{
|
||||||
if (Z_REFCOUNT_P(op) == 0) {
|
if (Z_REFCOUNT_P(op) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(op);
|
||||||
zval_dtor(op);
|
zval_dtor(op);
|
||||||
FREE_ZVAL(op);
|
FREE_ZVAL(op);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -349,6 +349,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -587,6 +588,7 @@ ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR|
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -677,6 +679,7 @@ ZEND_VM_HELPER_EX(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -1262,6 +1265,7 @@ ZEND_VM_HELPER_EX(zend_fetch_property_address_read_helper, VAR|UNUSED|CV, CONST|
|
||||||
|
|
||||||
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
||||||
if (Z_REFCOUNT_P(retval) == 0) {
|
if (Z_REFCOUNT_P(retval) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(retval);
|
||||||
zval_dtor(retval);
|
zval_dtor(retval);
|
||||||
FREE_ZVAL(retval);
|
FREE_ZVAL(retval);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9158,6 +9158,7 @@ static int zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(int (*binary_op)(zval
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -9395,6 +9396,7 @@ static int zend_pre_incdec_property_helper_SPEC_VAR_CONST(incdec_t incdec_op, ZE
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -9485,6 +9487,7 @@ static int zend_post_incdec_property_helper_SPEC_VAR_CONST(incdec_t incdec_op, Z
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -9718,6 +9721,7 @@ static int zend_fetch_property_address_read_helper_SPEC_VAR_CONST(int type, ZEND
|
||||||
|
|
||||||
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
||||||
if (Z_REFCOUNT_P(retval) == 0) {
|
if (Z_REFCOUNT_P(retval) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(retval);
|
||||||
zval_dtor(retval);
|
zval_dtor(retval);
|
||||||
FREE_ZVAL(retval);
|
FREE_ZVAL(retval);
|
||||||
}
|
}
|
||||||
|
@ -10980,6 +10984,7 @@ static int zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(int (*binary_op)(zval *
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -11218,6 +11223,7 @@ static int zend_pre_incdec_property_helper_SPEC_VAR_TMP(incdec_t incdec_op, ZEND
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -11308,6 +11314,7 @@ static int zend_post_incdec_property_helper_SPEC_VAR_TMP(incdec_t incdec_op, ZEN
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -11541,6 +11548,7 @@ static int zend_fetch_property_address_read_helper_SPEC_VAR_TMP(int type, ZEND_O
|
||||||
|
|
||||||
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
||||||
if (Z_REFCOUNT_P(retval) == 0) {
|
if (Z_REFCOUNT_P(retval) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(retval);
|
||||||
zval_dtor(retval);
|
zval_dtor(retval);
|
||||||
FREE_ZVAL(retval);
|
FREE_ZVAL(retval);
|
||||||
}
|
}
|
||||||
|
@ -12708,6 +12716,7 @@ static int zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(int (*binary_op)(zval *
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -12946,6 +12955,7 @@ static int zend_pre_incdec_property_helper_SPEC_VAR_VAR(incdec_t incdec_op, ZEND
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -13036,6 +13046,7 @@ static int zend_post_incdec_property_helper_SPEC_VAR_VAR(incdec_t incdec_op, ZEN
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -13269,6 +13280,7 @@ static int zend_fetch_property_address_read_helper_SPEC_VAR_VAR(int type, ZEND_O
|
||||||
|
|
||||||
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
||||||
if (Z_REFCOUNT_P(retval) == 0) {
|
if (Z_REFCOUNT_P(retval) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(retval);
|
||||||
zval_dtor(retval);
|
zval_dtor(retval);
|
||||||
FREE_ZVAL(retval);
|
FREE_ZVAL(retval);
|
||||||
}
|
}
|
||||||
|
@ -14239,6 +14251,7 @@ static int zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(int (*binary_op)(zva
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -15043,6 +15056,7 @@ static int zend_binary_assign_op_obj_helper_SPEC_VAR_CV(int (*binary_op)(zval *r
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -15280,6 +15294,7 @@ static int zend_pre_incdec_property_helper_SPEC_VAR_CV(incdec_t incdec_op, ZEND_
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -15370,6 +15385,7 @@ static int zend_post_incdec_property_helper_SPEC_VAR_CV(incdec_t incdec_op, ZEND
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -15603,6 +15619,7 @@ static int zend_fetch_property_address_read_helper_SPEC_VAR_CV(int type, ZEND_OP
|
||||||
|
|
||||||
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
||||||
if (Z_REFCOUNT_P(retval) == 0) {
|
if (Z_REFCOUNT_P(retval) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(retval);
|
||||||
zval_dtor(retval);
|
zval_dtor(retval);
|
||||||
FREE_ZVAL(retval);
|
FREE_ZVAL(retval);
|
||||||
}
|
}
|
||||||
|
@ -16650,6 +16667,7 @@ static int zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(int (*binary_op)(z
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -16886,6 +16904,7 @@ static int zend_pre_incdec_property_helper_SPEC_UNUSED_CONST(incdec_t incdec_op,
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -16976,6 +16995,7 @@ static int zend_post_incdec_property_helper_SPEC_UNUSED_CONST(incdec_t incdec_op
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -17055,6 +17075,7 @@ static int zend_fetch_property_address_read_helper_SPEC_UNUSED_CONST(int type, Z
|
||||||
|
|
||||||
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
||||||
if (Z_REFCOUNT_P(retval) == 0) {
|
if (Z_REFCOUNT_P(retval) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(retval);
|
||||||
zval_dtor(retval);
|
zval_dtor(retval);
|
||||||
FREE_ZVAL(retval);
|
FREE_ZVAL(retval);
|
||||||
}
|
}
|
||||||
|
@ -17768,6 +17789,7 @@ static int zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(int (*binary_op)(zva
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -18005,6 +18027,7 @@ static int zend_pre_incdec_property_helper_SPEC_UNUSED_TMP(incdec_t incdec_op, Z
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -18095,6 +18118,7 @@ static int zend_post_incdec_property_helper_SPEC_UNUSED_TMP(incdec_t incdec_op,
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -18174,6 +18198,7 @@ static int zend_fetch_property_address_read_helper_SPEC_UNUSED_TMP(int type, ZEN
|
||||||
|
|
||||||
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
||||||
if (Z_REFCOUNT_P(retval) == 0) {
|
if (Z_REFCOUNT_P(retval) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(retval);
|
||||||
zval_dtor(retval);
|
zval_dtor(retval);
|
||||||
FREE_ZVAL(retval);
|
FREE_ZVAL(retval);
|
||||||
}
|
}
|
||||||
|
@ -18816,6 +18841,7 @@ static int zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(int (*binary_op)(zva
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -19053,6 +19079,7 @@ static int zend_pre_incdec_property_helper_SPEC_UNUSED_VAR(incdec_t incdec_op, Z
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -19143,6 +19170,7 @@ static int zend_post_incdec_property_helper_SPEC_UNUSED_VAR(incdec_t incdec_op,
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -19222,6 +19250,7 @@ static int zend_fetch_property_address_read_helper_SPEC_UNUSED_VAR(int type, ZEN
|
||||||
|
|
||||||
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
||||||
if (Z_REFCOUNT_P(retval) == 0) {
|
if (Z_REFCOUNT_P(retval) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(retval);
|
||||||
zval_dtor(retval);
|
zval_dtor(retval);
|
||||||
FREE_ZVAL(retval);
|
FREE_ZVAL(retval);
|
||||||
}
|
}
|
||||||
|
@ -19864,6 +19893,7 @@ static int zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(int (*binary_op)(
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -20130,6 +20160,7 @@ static int zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(int (*binary_op)(zval
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -20366,6 +20397,7 @@ static int zend_pre_incdec_property_helper_SPEC_UNUSED_CV(incdec_t incdec_op, ZE
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -20456,6 +20488,7 @@ static int zend_post_incdec_property_helper_SPEC_UNUSED_CV(incdec_t incdec_op, Z
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -20535,6 +20568,7 @@ static int zend_fetch_property_address_read_helper_SPEC_UNUSED_CV(int type, ZEND
|
||||||
|
|
||||||
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
||||||
if (Z_REFCOUNT_P(retval) == 0) {
|
if (Z_REFCOUNT_P(retval) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(retval);
|
||||||
zval_dtor(retval);
|
zval_dtor(retval);
|
||||||
FREE_ZVAL(retval);
|
FREE_ZVAL(retval);
|
||||||
}
|
}
|
||||||
|
@ -22749,6 +22783,7 @@ static int zend_binary_assign_op_obj_helper_SPEC_CV_CONST(int (*binary_op)(zval
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -22985,6 +23020,7 @@ static int zend_pre_incdec_property_helper_SPEC_CV_CONST(incdec_t incdec_op, ZEN
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -23075,6 +23111,7 @@ static int zend_post_incdec_property_helper_SPEC_CV_CONST(incdec_t incdec_op, ZE
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -23307,6 +23344,7 @@ static int zend_fetch_property_address_read_helper_SPEC_CV_CONST(int type, ZEND_
|
||||||
|
|
||||||
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
||||||
if (Z_REFCOUNT_P(retval) == 0) {
|
if (Z_REFCOUNT_P(retval) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(retval);
|
||||||
zval_dtor(retval);
|
zval_dtor(retval);
|
||||||
FREE_ZVAL(retval);
|
FREE_ZVAL(retval);
|
||||||
}
|
}
|
||||||
|
@ -24397,6 +24435,7 @@ static int zend_binary_assign_op_obj_helper_SPEC_CV_TMP(int (*binary_op)(zval *r
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -24634,6 +24673,7 @@ static int zend_pre_incdec_property_helper_SPEC_CV_TMP(incdec_t incdec_op, ZEND_
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -24724,6 +24764,7 @@ static int zend_post_incdec_property_helper_SPEC_CV_TMP(incdec_t incdec_op, ZEND
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -24956,6 +24997,7 @@ static int zend_fetch_property_address_read_helper_SPEC_CV_TMP(int type, ZEND_OP
|
||||||
|
|
||||||
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
||||||
if (Z_REFCOUNT_P(retval) == 0) {
|
if (Z_REFCOUNT_P(retval) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(retval);
|
||||||
zval_dtor(retval);
|
zval_dtor(retval);
|
||||||
FREE_ZVAL(retval);
|
FREE_ZVAL(retval);
|
||||||
}
|
}
|
||||||
|
@ -26023,6 +26065,7 @@ static int zend_binary_assign_op_obj_helper_SPEC_CV_VAR(int (*binary_op)(zval *r
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -26260,6 +26303,7 @@ static int zend_pre_incdec_property_helper_SPEC_CV_VAR(incdec_t incdec_op, ZEND_
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -26350,6 +26394,7 @@ static int zend_post_incdec_property_helper_SPEC_CV_VAR(incdec_t incdec_op, ZEND
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -26582,6 +26627,7 @@ static int zend_fetch_property_address_read_helper_SPEC_CV_VAR(int type, ZEND_OP
|
||||||
|
|
||||||
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
||||||
if (Z_REFCOUNT_P(retval) == 0) {
|
if (Z_REFCOUNT_P(retval) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(retval);
|
||||||
zval_dtor(retval);
|
zval_dtor(retval);
|
||||||
FREE_ZVAL(retval);
|
FREE_ZVAL(retval);
|
||||||
}
|
}
|
||||||
|
@ -27451,6 +27497,7 @@ static int zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(int (*binary_op)(zval
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -28163,6 +28210,7 @@ static int zend_binary_assign_op_obj_helper_SPEC_CV_CV(int (*binary_op)(zval *re
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -28399,6 +28447,7 @@ static int zend_pre_incdec_property_helper_SPEC_CV_CV(incdec_t incdec_op, ZEND_O
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -28489,6 +28538,7 @@ static int zend_post_incdec_property_helper_SPEC_CV_CV(incdec_t incdec_op, ZEND_
|
||||||
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
|
||||||
|
|
||||||
if (Z_REFCOUNT_P(z) == 0) {
|
if (Z_REFCOUNT_P(z) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(z);
|
||||||
zval_dtor(z);
|
zval_dtor(z);
|
||||||
FREE_ZVAL(z);
|
FREE_ZVAL(z);
|
||||||
}
|
}
|
||||||
|
@ -28721,6 +28771,7 @@ static int zend_fetch_property_address_read_helper_SPEC_CV_CV(int type, ZEND_OPC
|
||||||
|
|
||||||
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
if (RETURN_VALUE_UNUSED(&opline->result)) {
|
||||||
if (Z_REFCOUNT_P(retval) == 0) {
|
if (Z_REFCOUNT_P(retval) == 0) {
|
||||||
|
GC_REMOVE_ZVAL_FROM_BUFFER(retval);
|
||||||
zval_dtor(retval);
|
zval_dtor(retval);
|
||||||
FREE_ZVAL(retval);
|
FREE_ZVAL(retval);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1235,7 +1235,8 @@ PHP_ADD_SOURCES(Zend, \
|
||||||
zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \
|
zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \
|
||||||
zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \
|
zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \
|
||||||
zend_ini.c zend_qsort.c zend_ts_hash.c zend_stream.c \
|
zend_ini.c zend_qsort.c zend_ts_hash.c zend_stream.c \
|
||||||
zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_strtol.c)
|
zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c \
|
||||||
|
zend_strtol.c zend_gc.c)
|
||||||
|
|
||||||
if test -r "$abs_srcdir/Zend/zend_objects.c"; then
|
if test -r "$abs_srcdir/Zend/zend_objects.c"; then
|
||||||
PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c \
|
PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c \
|
||||||
|
|
|
@ -1822,6 +1822,8 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
|
||||||
ts_allocate_id(&php_win32_core_globals_id, sizeof(php_win32_core_globals), (ts_allocate_ctor) php_win32_core_globals_ctor, (ts_allocate_dtor) php_win32_core_globals_dtor);
|
ts_allocate_id(&php_win32_core_globals_id, sizeof(php_win32_core_globals), (ts_allocate_ctor) php_win32_core_globals_ctor, (ts_allocate_dtor) php_win32_core_globals_dtor);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
gc_globals_ctor(TSRMLS_C);
|
||||||
|
|
||||||
EG(bailout) = NULL;
|
EG(bailout) = NULL;
|
||||||
EG(error_reporting) = E_ALL & ~E_NOTICE;
|
EG(error_reporting) = E_ALL & ~E_NOTICE;
|
||||||
|
|
||||||
|
@ -2070,6 +2072,7 @@ void php_module_shutdown(TSRMLS_D)
|
||||||
|
|
||||||
#ifndef ZTS
|
#ifndef ZTS
|
||||||
core_globals_dtor(&core_globals TSRMLS_CC);
|
core_globals_dtor(&core_globals TSRMLS_CC);
|
||||||
|
gc_globals_dtor(TSRMLS_C);
|
||||||
#else
|
#else
|
||||||
ts_free_id(core_globals_id);
|
ts_free_id(core_globals_id);
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue