mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Support partial GC for unfinished generators
This doesn't cover everything yet, but should be a good start for cycled in unfinished generators.
This commit is contained in:
42
Zend/tests/bug69989_2.phpt
Normal file
42
Zend/tests/bug69989_2.phpt
Normal file
@@ -0,0 +1,42 @@
|
||||
--TEST--
|
||||
Collection of some cycles on unfinished generators
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
// CV
|
||||
function gen1() {
|
||||
$gen = yield;
|
||||
yield;
|
||||
}
|
||||
|
||||
$gen = gen1();
|
||||
$gen->send($gen);
|
||||
|
||||
// This
|
||||
class Test {
|
||||
public $gen;
|
||||
public function gen2() {
|
||||
yield;
|
||||
}
|
||||
}
|
||||
|
||||
$test = new Test;
|
||||
$test->gen = $test->gen2();
|
||||
|
||||
// Closure object
|
||||
$gen3 = (function() use (&$gen3) {
|
||||
yield;
|
||||
})();
|
||||
|
||||
// Yield from array
|
||||
function gen4() {
|
||||
yield from [yield];
|
||||
}
|
||||
|
||||
$gen = gen4();
|
||||
$gen->send($gen);
|
||||
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECT--
|
||||
===DONE===
|
||||
@@ -98,6 +98,12 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
|
||||
OBJ_RELEASE((zend_object *) EX(func)->common.prototype);
|
||||
}
|
||||
|
||||
/* Free GC buffer. GC for closed generators doesn't need an allocated buffer */
|
||||
if (generator->gc_buffer) {
|
||||
efree(generator->gc_buffer);
|
||||
generator->gc_buffer = NULL;
|
||||
}
|
||||
|
||||
efree(generator->stack);
|
||||
generator->execute_data = NULL;
|
||||
}
|
||||
@@ -188,11 +194,63 @@ static void zend_generator_free_storage(zend_object *object) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static uint32_t calc_gc_buffer_size(zend_generator *generator) /* {{{ */
|
||||
{
|
||||
uint32_t size = 4; /* value, key, retval, values */
|
||||
if (generator->execute_data) {
|
||||
zend_execute_data *execute_data = generator->execute_data;
|
||||
zend_op_array *op_array = &EX(func)->op_array;
|
||||
|
||||
size += op_array->last_var; /* CVs */
|
||||
size += Z_OBJ(execute_data->This) != NULL; /* $this */
|
||||
size += (EX_CALL_INFO() & ZEND_CALL_CLOSURE) != 0; /* Closure object */
|
||||
}
|
||||
return size;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* {{{ */
|
||||
{
|
||||
zend_generator *generator = (zend_generator*) Z_OBJ_P(object);
|
||||
*table = &generator->value;
|
||||
*n = 3;
|
||||
zend_execute_data *execute_data = generator->execute_data;
|
||||
zval *gc_buffer;
|
||||
uint32_t gc_buffer_size;
|
||||
|
||||
if (!execute_data) {
|
||||
/* If the generator has been closed, it can only hold on to three values: The value, key
|
||||
* and retval. These three zvals are stored sequentially starting at &generator->value. */
|
||||
*table = &generator->value;
|
||||
*n = 3;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gc_buffer_size = calc_gc_buffer_size(generator);
|
||||
if (!generator->gc_buffer) {
|
||||
generator->gc_buffer = safe_emalloc(sizeof(zval), gc_buffer_size, 0);
|
||||
}
|
||||
|
||||
*n = gc_buffer_size;
|
||||
*table = gc_buffer = generator->gc_buffer;
|
||||
|
||||
ZVAL_COPY_VALUE(gc_buffer++, &generator->value);
|
||||
ZVAL_COPY_VALUE(gc_buffer++, &generator->key);
|
||||
ZVAL_COPY_VALUE(gc_buffer++, &generator->retval);
|
||||
ZVAL_COPY_VALUE(gc_buffer++, &generator->values);
|
||||
|
||||
{
|
||||
uint32_t i, num_cvs = EX(func)->op_array.last_var;
|
||||
for (i = 0; i < num_cvs; i++) {
|
||||
ZVAL_COPY_VALUE(gc_buffer++, EX_VAR_NUM(i));
|
||||
}
|
||||
}
|
||||
|
||||
if (Z_OBJ(execute_data->This)) {
|
||||
ZVAL_OBJ(gc_buffer++, Z_OBJ(execute_data->This));
|
||||
}
|
||||
if (EX_CALL_INFO() & ZEND_CALL_CLOSURE) {
|
||||
ZVAL_OBJ(gc_buffer++, (zend_object *) EX(func)->common.prototype);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -82,7 +82,7 @@ struct _zend_generator {
|
||||
* by-value foreach. */
|
||||
zval values;
|
||||
|
||||
/* Node of waiting generators when multiple "yield *" expressions
|
||||
/* Node of waiting generators when multiple "yield from" expressions
|
||||
* are nested. */
|
||||
zend_generator_node node;
|
||||
|
||||
@@ -91,6 +91,8 @@ struct _zend_generator {
|
||||
|
||||
/* ZEND_GENERATOR_* flags */
|
||||
zend_uchar flags;
|
||||
|
||||
zval *gc_buffer;
|
||||
};
|
||||
|
||||
static const zend_uchar ZEND_GENERATOR_CURRENTLY_RUNNING = 0x1;
|
||||
|
||||
Reference in New Issue
Block a user