diff options
Diffstat (limited to 'Zend/zend_generators.c')
| -rw-r--r-- | Zend/zend_generators.c | 537 |
1 files changed, 208 insertions, 329 deletions
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 3fbbd49c0a..68c1865c00 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -23,6 +23,8 @@ #include "zend_exceptions.h" #include "zend_generators.h" #include "zend_closures.h" +#include "zend_generators_arginfo.h" +#include "zend_observer.h" ZEND_API zend_class_entry *zend_ce_generator; ZEND_API zend_class_entry *zend_ce_ClosedGeneratorException; @@ -126,6 +128,9 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished } /* always free the CV's, in the symtable are only not-free'd IS_INDIRECT's */ zend_free_compiled_variables(execute_data); + if (EX_CALL_INFO() & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { + zend_free_extra_named_params(execute_data->extra_named_params); + } if (EX_CALL_INFO() & ZEND_CALL_RELEASE_THIS) { OBJ_RELEASE(Z_OBJ(execute_data->This)); @@ -151,18 +156,50 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } - /* 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(execute_data); } } /* }}} */ -static zend_generator *zend_generator_get_child(zend_generator_node *node, zend_generator *leaf); +static void zend_generator_remove_child(zend_generator_node *node, zend_generator *child) +{ + ZEND_ASSERT(node->children >= 1); + if (node->children == 1) { + node->child.single.child = NULL; + } else { + HashTable *ht = node->child.ht; + zend_hash_index_del(ht, (zend_ulong) child); + if (node->children == 2) { + zend_generator *other_child; + ZEND_HASH_FOREACH_PTR(ht, other_child) { + node->child.single.child = other_child; + break; + } ZEND_HASH_FOREACH_END(); + zend_hash_destroy(ht); + efree(ht); + } + } + node->children--; +} + +static zend_always_inline zend_generator *clear_link_to_leaf(zend_generator *generator) { + ZEND_ASSERT(!generator->node.parent); + zend_generator *leaf = generator->node.ptr.leaf; + if (leaf) { + leaf->node.ptr.root = NULL; + generator->node.ptr.leaf = NULL; + return leaf; + } + return NULL; +} + +static zend_always_inline void clear_link_to_root(zend_generator *generator) { + ZEND_ASSERT(generator->node.parent); + if (generator->node.ptr.root) { + generator->node.ptr.root->node.ptr.leaf = NULL; + generator->node.ptr.root = NULL; + } +} static void zend_generator_dtor_storage(zend_object *object) /* {{{ */ { @@ -177,15 +214,14 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */ ZVAL_UNDEF(&generator->values); } - if (EXPECTED(generator->node.children == 0)) { - zend_generator *root = generator->node.ptr.root, *next; - while (UNEXPECTED(root != generator)) { - next = zend_generator_get_child(&root->node, generator); - generator->node.ptr.root = next; - next->node.parent = NULL; - OBJ_RELEASE(&root->std); - root = next; - } + zend_generator *parent = generator->node.parent; + if (parent) { + zend_generator_remove_child(&parent->node, generator); + clear_link_to_root(generator); + generator->node.parent = NULL; + OBJ_RELEASE(&parent->std); + } else { + clear_link_to_leaf(generator); } if (EXPECTED(!ex) || EXPECTED(!(ex->func->op_array.fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) @@ -274,63 +310,11 @@ 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; - - /* Compiled variables */ - if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) { - size += op_array->last_var; - } - /* Extra args */ - if (EX_CALL_INFO() & ZEND_CALL_FREE_EXTRA_ARGS) { - size += EX_NUM_ARGS() - op_array->num_args; - } - size += (EX_CALL_INFO() & ZEND_CALL_RELEASE_THIS) != 0; /* $this */ - size += (EX_CALL_INFO() & ZEND_CALL_CLOSURE) != 0; /* Closure object */ - - /* Live vars */ - if (execute_data->opline != op_array->opcodes) { - /* -1 required because we want the last run opcode, not the next to-be-run one. */ - uint32_t i, op_num = execute_data->opline - op_array->opcodes - 1; - for (i = 0; i < op_array->last_live_range; i++) { - const zend_live_range *range = &op_array->live_range[i]; - if (range->start > op_num) { - /* Further ranges will not be relevant... */ - break; - } else if (op_num < range->end) { - /* LIVE_ROPE and LIVE_SILENCE not relevant for GC */ - uint32_t kind = range->var & ZEND_LIVE_MASK; - if (kind == ZEND_LIVE_TMPVAR || kind == ZEND_LIVE_LOOP) { - size++; - } - } - } - } - - /* Yield from root references */ - if (generator->node.children == 0) { - zend_generator *root = generator->node.ptr.root; - while (root != generator) { - root = zend_generator_get_child(&root->node, generator); - size++; - } - } - } - return size; -} -/* }}} */ - -static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* {{{ */ +static HashTable *zend_generator_get_gc(zend_object *object, zval **table, int *n) /* {{{ */ { - zend_generator *generator = (zend_generator*) Z_OBJ_P(object); + zend_generator *generator = (zend_generator*)object; zend_execute_data *execute_data = generator->execute_data; zend_op_array *op_array; - 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 @@ -351,24 +335,17 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* { } op_array = &EX(func)->op_array; - gc_buffer_size = calc_gc_buffer_size(generator); - if (generator->gc_buffer_size < gc_buffer_size) { - generator->gc_buffer = safe_erealloc(generator->gc_buffer, sizeof(zval), gc_buffer_size, 0); - generator->gc_buffer_size = gc_buffer_size; - } - *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); + zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create(); + zend_get_gc_buffer_add_zval(gc_buffer, &generator->value); + zend_get_gc_buffer_add_zval(gc_buffer, &generator->key); + zend_get_gc_buffer_add_zval(gc_buffer, &generator->retval); + zend_get_gc_buffer_add_zval(gc_buffer, &generator->values); if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) { 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)); + zend_get_gc_buffer_add_zval(gc_buffer, EX_VAR_NUM(i)); } } @@ -376,15 +353,20 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* { zval *zv = EX_VAR_NUM(op_array->last_var + op_array->T); zval *end = zv + (EX_NUM_ARGS() - op_array->num_args); while (zv != end) { - ZVAL_COPY_VALUE(gc_buffer++, zv++); + zend_get_gc_buffer_add_zval(gc_buffer, zv++); } } if (EX_CALL_INFO() & ZEND_CALL_RELEASE_THIS) { - ZVAL_OBJ(gc_buffer++, Z_OBJ(execute_data->This)); + zend_get_gc_buffer_add_obj(gc_buffer, Z_OBJ(execute_data->This)); } if (EX_CALL_INFO() & ZEND_CALL_CLOSURE) { - ZVAL_OBJ(gc_buffer++, ZEND_CLOSURE_OBJECT(EX(func))); + zend_get_gc_buffer_add_obj(gc_buffer, ZEND_CLOSURE_OBJECT(EX(func))); + } + if (EX_CALL_INFO() & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) { + zval extra_named_params; + ZVAL_ARR(&extra_named_params, EX(extra_named_params)); + zend_get_gc_buffer_add_zval(gc_buffer, &extra_named_params); } if (execute_data->opline != op_array->opcodes) { @@ -398,20 +380,17 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* { uint32_t var_num = range->var & ~ZEND_LIVE_MASK; zval *var = EX_VAR(var_num); if (kind == ZEND_LIVE_TMPVAR || kind == ZEND_LIVE_LOOP) { - ZVAL_COPY_VALUE(gc_buffer++, var); + zend_get_gc_buffer_add_zval(gc_buffer, var); } } } } - if (generator->node.children == 0) { - zend_generator *root = generator->node.ptr.root; - while (root != generator) { - ZVAL_OBJ(gc_buffer++, &root->std); - root = zend_generator_get_child(&root->node, generator); - } + if (generator->node.parent) { + zend_get_gc_buffer_add_obj(gc_buffer, &generator->node.parent->std); } + zend_get_gc_buffer_use(gc_buffer, table, n); if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) { return execute_data->symbol_table; } else { @@ -436,7 +415,7 @@ static zend_object *zend_generator_create(zend_class_entry *class_type) /* {{{ * /* By default we have a tree of only one node */ generator->node.parent = NULL; generator->node.children = 0; - generator->node.ptr.root = generator; + generator->node.ptr.root = NULL; zend_object_std_init(&generator->std, class_type); generator->std.handlers = &zend_generator_handlers; @@ -458,14 +437,12 @@ ZEND_API zend_execute_data *zend_generator_check_placeholder_frame(zend_execute_ if (!ptr->func && Z_TYPE(ptr->This) == IS_OBJECT) { if (Z_OBJCE(ptr->This) == zend_ce_generator) { zend_generator *generator = (zend_generator *) Z_OBJ(ptr->This); - zend_generator *root = (generator->node.children < 1 ? generator : generator->node.ptr.leaf)->node.ptr.root; zend_execute_data *prev = ptr->prev_execute_data; - if (generator->node.parent != root) { - do { - generator->execute_data->prev_execute_data = prev; - prev = generator->execute_data; - generator = generator->node.parent; - } while (generator->node.parent != root); + ZEND_ASSERT(generator->node.parent && "Placeholder only used with delegation"); + while (generator->node.parent->node.parent) { + generator->execute_data->prev_execute_data = prev; + prev = generator->execute_data; + generator = generator->node.parent; } generator->execute_data->prev_execute_data = prev; ptr = generator->execute_data; @@ -497,204 +474,131 @@ static void zend_generator_throw_exception(zend_generator *generator, zval *exce EG(current_execute_data) = original_execute_data; } -static zend_generator *zend_generator_get_child(zend_generator_node *node, zend_generator *leaf) +static void zend_generator_add_child(zend_generator *generator, zend_generator *child) { - if (node->children == 0) { - return NULL; - } else if (node->children == 1) { - return node->child.single.child; - } else { - return zend_hash_index_find_ptr(node->child.ht, (zend_ulong) leaf); - } -} + zend_generator_node *node = &generator->node; -static zend_generator_node *zend_generator_search_multi_children_node(zend_generator_node *node) -{ - while (node->children == 1) { - node = &node->child.single.child->node; - } - return node->children > 1 ? node : NULL; -} - -static void zend_generator_add_single_child(zend_generator_node *node, zend_generator *child, zend_generator *leaf) -{ if (node->children == 0) { - node->child.single.leaf = leaf; node->child.single.child = child; } else { if (node->children == 1) { HashTable *ht = emalloc(sizeof(HashTable)); zend_hash_init(ht, 0, NULL, NULL, 0); - zend_hash_index_add_ptr(ht, - (zend_ulong) node->child.single.leaf, node->child.single.child); + zend_hash_index_add_new_ptr(ht, + (zend_ulong) node->child.single.child, node->child.single.child); node->child.ht = ht; } - zend_hash_index_add_ptr(node->child.ht, (zend_ulong) leaf, child); + zend_hash_index_add_new_ptr(node->child.ht, (zend_ulong) child, child); } - node->children++; + ++node->children; } -static void zend_generator_merge_child_nodes(zend_generator_node *dest, zend_generator_node *src, zend_generator *child) +void zend_generator_yield_from(zend_generator *generator, zend_generator *from) { - zend_ulong leaf; - ZEND_ASSERT(src->children > 1); - ZEND_HASH_FOREACH_NUM_KEY(src->child.ht, leaf) { - zend_generator_add_single_child(dest, child, (zend_generator *) leaf); - } ZEND_HASH_FOREACH_END(); + ZEND_ASSERT(!generator->node.parent && "Already has parent?"); + zend_generator *leaf = clear_link_to_leaf(generator); + if (leaf && !from->node.parent && !from->node.ptr.leaf) { + from->node.ptr.leaf = leaf; + leaf->node.ptr.root = from; + } + generator->node.parent = from; + zend_generator_add_child(from, generator); + generator->flags |= ZEND_GENERATOR_DO_INIT; } -/* Pay attention so that the root of each subtree of the Generators tree is referenced - * once per leaf */ -static void zend_generator_add_child(zend_generator *generator, zend_generator *child) +ZEND_API zend_generator *zend_generator_update_root(zend_generator *generator) { - zend_generator *leaf = child->node.children ? child->node.ptr.leaf : child; - zend_generator_node *multi_children_node; - zend_bool was_leaf = generator->node.children == 0; - - if (was_leaf) { - zend_generator *next = generator->node.parent; - leaf->node.ptr.root = generator->node.ptr.root; - GC_ADDREF(&generator->std); /* we need to increment the generator refcount here as it became integrated into the tree (no leaf), but we must not increment the refcount of the *whole* path in tree */ - generator->node.ptr.leaf = leaf; - - while (next) { - if (next->node.children > 1) { - zend_generator *child = zend_hash_index_find_ptr(next->node.child.ht, (zend_ulong) generator); - zend_hash_index_del(next->node.child.ht, (zend_ulong) generator); - zend_hash_index_add_ptr(next->node.child.ht, (zend_ulong) leaf, child); - } - - next->node.ptr.leaf = leaf; - next = next->node.parent; - } - } else if (generator->node.children == 1) { - multi_children_node = zend_generator_search_multi_children_node(&generator->node); - if (multi_children_node) { - generator->node.children = 0; - zend_generator_merge_child_nodes(&generator->node, multi_children_node, generator->node.child.single.child); - } + zend_generator *root = generator->node.parent; + while (root->node.parent) { + root = root->node.parent; } - if (!was_leaf) { - multi_children_node = zend_generator_search_multi_children_node(&child->node); - } else { - multi_children_node = (zend_generator_node *) 0x1; + clear_link_to_leaf(root); + root->node.ptr.leaf = generator; + generator->node.ptr.root = root; + return root; +} + +static zend_generator *get_new_root(zend_generator *generator, zend_generator *root) +{ + while (!root->execute_data && root->node.children == 1) { + root = root->node.child.single.child; } - { - zend_generator *parent = generator->node.parent, *cur = generator; + if (root->execute_data) { + return root; + } - if (multi_children_node > (zend_generator_node *) 0x1) { - zend_generator_merge_child_nodes(&generator->node, multi_children_node, child); - } else { - zend_generator_add_single_child(&generator->node, child, leaf); - } - while (parent) { - if (parent->node.children > 1) { - if (multi_children_node == (zend_generator_node *) 0x1) { - multi_children_node = zend_generator_search_multi_children_node(&child->node); - } - if (multi_children_node) { - zend_generator_merge_child_nodes(&parent->node, multi_children_node, cur); - } else { - zend_generator_add_single_child(&parent->node, cur, leaf); - } - } - cur = parent; - parent = parent->node.parent; - } + /* We have reached a multi-child node haven't found the root yet. We don't know which + * child to follow, so perform the search from the other direction instead. */ + while (generator->node.parent->execute_data) { + generator = generator->node.parent; } + + return generator; } -void zend_generator_yield_from(zend_generator *generator, zend_generator *from) +ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator) { - zend_generator_add_child(from, generator); + zend_generator *old_root = generator->node.ptr.root; + ZEND_ASSERT(!old_root->execute_data && "Nothing to update?"); - generator->node.parent = from; - zend_generator_get_current(generator); - GC_DELREF(&from->std); - generator->flags |= ZEND_GENERATOR_DO_INIT; -} + zend_generator *new_root = get_new_root(generator, old_root); -ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator, zend_generator *leaf) -{ - zend_generator *old_root, *root = leaf->node.ptr.root; + ZEND_ASSERT(old_root->node.ptr.leaf == generator); + generator->node.ptr.root = new_root; + new_root->node.ptr.leaf = generator; + old_root->node.ptr.leaf = NULL; - /* generator at the root had stopped */ - if (root != generator) { - old_root = root; - root = zend_generator_get_child(&root->node, leaf); - } else { - old_root = NULL; - } + zend_generator *new_root_parent = new_root->node.parent; + ZEND_ASSERT(new_root_parent); + zend_generator_remove_child(&new_root_parent->node, new_root); - while (!root->execute_data && root != generator) { - OBJ_RELEASE(&old_root->std); - old_root = root; + if (EXPECTED(EG(exception) == NULL) && EXPECTED((OBJ_FLAGS(&generator->std) & IS_OBJ_DESTRUCTOR_CALLED) == 0)) { + zend_op *yield_from = (zend_op *) new_root->execute_data->opline - 1; - root = zend_generator_get_child(&root->node, leaf); - } + if (yield_from->opcode == ZEND_YIELD_FROM) { + if (Z_ISUNDEF(new_root_parent->retval)) { + /* Throw the exception in the context of the generator */ + zend_execute_data *original_execute_data = EG(current_execute_data); + EG(current_execute_data) = new_root->execute_data; - if (root->node.parent) { - if (root->node.parent->execute_data == NULL) { - if (EXPECTED(EG(exception) == NULL)) { - zend_op *yield_from = (zend_op *) root->execute_data->opline - 1; - - if (yield_from->opcode == ZEND_YIELD_FROM) { - if (Z_ISUNDEF(root->node.parent->retval)) { - /* Throw the exception in the context of the generator */ - zend_execute_data *original_execute_data = EG(current_execute_data); - EG(current_execute_data) = root->execute_data; - - if (root == generator) { - root->execute_data->prev_execute_data = original_execute_data; - } else { - root->execute_data->prev_execute_data = &generator->execute_fake; - generator->execute_fake.prev_execute_data = original_execute_data; - } - - root->execute_data->opline--; /* ZEND_YIELD(_FROM) already advance, so decrement opline to throw from correct place */ - zend_throw_exception(zend_ce_ClosedGeneratorException, "Generator yielded from aborted, no return value available", 0); - - EG(current_execute_data) = original_execute_data; - - if (!((old_root ? old_root : generator)->flags & ZEND_GENERATOR_CURRENTLY_RUNNING)) { - leaf->node.ptr.root = root; - root->node.parent = NULL; - if (old_root) { - OBJ_RELEASE(&old_root->std); - } - zend_generator_resume(leaf); - return leaf->node.ptr.root; /* this may be updated during zend_generator_resume! */ - } - } else { - zval_ptr_dtor(&root->value); - ZVAL_COPY(&root->value, &root->node.parent->value); - ZVAL_COPY(ZEND_CALL_VAR(root->execute_data, yield_from->result.var), &root->node.parent->retval); - } + if (new_root == generator) { + new_root->execute_data->prev_execute_data = original_execute_data; + } else { + new_root->execute_data->prev_execute_data = &generator->execute_fake; + generator->execute_fake.prev_execute_data = original_execute_data; } - } - root->node.parent = NULL; - } else { - do { - root = root->node.parent; - GC_ADDREF(&root->std); - } while (root->node.parent); + /* ZEND_YIELD(_FROM) already advance, so decrement opline to throw from correct place */ + new_root->execute_data->opline--; + zend_throw_exception(zend_ce_ClosedGeneratorException, "Generator yielded from aborted, no return value available", 0); + + EG(current_execute_data) = original_execute_data; + + if (!((old_root ? old_root : generator)->flags & ZEND_GENERATOR_CURRENTLY_RUNNING)) { + new_root->node.parent = NULL; + OBJ_RELEASE(&new_root_parent->std); + zend_generator_resume(generator); + return zend_generator_get_current(generator); + } + } else { + zval_ptr_dtor(&new_root->value); + ZVAL_COPY(&new_root->value, &new_root_parent->value); + ZVAL_COPY(ZEND_CALL_VAR(new_root->execute_data, yield_from->result.var), &new_root_parent->retval); + } } } - leaf->node.ptr.root = root; - if (old_root) { - OBJ_RELEASE(&old_root->std); - } + new_root->node.parent = NULL; + OBJ_RELEASE(&new_root_parent->std); - return root; + return new_root; } -static int zend_generator_get_next_delegated_value(zend_generator *generator) /* {{{ */ +static zend_result zend_generator_get_next_delegated_value(zend_generator *generator) /* {{{ */ { zval *value; if (Z_TYPE(generator->values) == IS_ARRAY) { @@ -799,6 +703,9 @@ try_again: return; } + /* Drop the AT_FIRST_YIELD flag */ + orig_generator->flags &= ~ZEND_GENERATOR_AT_FIRST_YIELD; + if (UNEXPECTED(!Z_ISUNDEF(generator->values))) { if (EXPECTED(zend_generator_get_next_delegated_value(generator) == SUCCESS)) { orig_generator->flags &= ~ZEND_GENERATOR_DO_INIT; @@ -808,15 +715,14 @@ try_again: * after the "yield from" expression. */ } - /* Drop the AT_FIRST_YIELD flag */ - orig_generator->flags &= ~ZEND_GENERATOR_AT_FIRST_YIELD; - { /* Backup executor globals */ zend_execute_data *original_execute_data = EG(current_execute_data); + uint32_t original_jit_trace_num = EG(jit_trace_num); /* Set executor globals */ EG(current_execute_data) = generator->execute_data; + EG(jit_trace_num) = 0; /* We want the backtrace to look as if the generator function was * called from whatever method we are current running (e.g. next()). @@ -837,7 +743,16 @@ try_again: /* Resume execution */ generator->flags |= ZEND_GENERATOR_CURRENTLY_RUNNING; - zend_execute_ex(generator->execute_data); + if (!ZEND_OBSERVER_ENABLED) { + zend_execute_ex(generator->execute_data); + } else { + zend_observer_generator_resume(generator->execute_data); + zend_execute_ex(generator->execute_data); + if (generator->execute_data) { + /* On the final return, this will be called from ZEND_GENERATOR_RETURN */ + zend_observer_fcall_end(generator->execute_data, &generator->value); + } + } generator->flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING; generator->frozen_call_stack = NULL; @@ -849,6 +764,7 @@ try_again: /* Restore executor globals */ EG(current_execute_data) = original_execute_data; + EG(jit_trace_num) = original_jit_trace_num; /* If an exception was thrown in the generator we have to internally * rethrow it in the parent scope. @@ -901,15 +817,12 @@ static inline void zend_generator_rewind(zend_generator *generator) /* {{{ */ } /* }}} */ -/* {{{ proto void Generator::rewind() - * Rewind the generator */ +/* {{{ Rewind the generator */ ZEND_METHOD(Generator, rewind) { zend_generator *generator; - if (zend_parse_parameters_none() == FAILURE) { - return; - } + ZEND_PARSE_PARAMETERS_NONE(); generator = (zend_generator *) Z_OBJ_P(ZEND_THIS); @@ -917,15 +830,12 @@ ZEND_METHOD(Generator, rewind) } /* }}} */ -/* {{{ proto bool Generator::valid() - * Check whether the generator is valid */ +/* {{{ Check whether the generator is valid */ ZEND_METHOD(Generator, valid) { zend_generator *generator; - if (zend_parse_parameters_none() == FAILURE) { - return; - } + ZEND_PARSE_PARAMETERS_NONE(); generator = (zend_generator *) Z_OBJ_P(ZEND_THIS); @@ -937,15 +847,12 @@ ZEND_METHOD(Generator, valid) } /* }}} */ -/* {{{ proto mixed Generator::current() - * Get the current value */ +/* {{{ Get the current value */ ZEND_METHOD(Generator, current) { zend_generator *generator, *root; - if (zend_parse_parameters_none() == FAILURE) { - return; - } + ZEND_PARSE_PARAMETERS_NONE(); generator = (zend_generator *) Z_OBJ_P(ZEND_THIS); @@ -960,15 +867,12 @@ ZEND_METHOD(Generator, current) } /* }}} */ -/* {{{ proto mixed Generator::key() - * Get the current key */ +/* {{{ Get the current key */ ZEND_METHOD(Generator, key) { zend_generator *generator, *root; - if (zend_parse_parameters_none() == FAILURE) { - return; - } + ZEND_PARSE_PARAMETERS_NONE(); generator = (zend_generator *) Z_OBJ_P(ZEND_THIS); @@ -983,15 +887,12 @@ ZEND_METHOD(Generator, key) } /* }}} */ -/* {{{ proto void Generator::next() - * Advances the generator */ +/* {{{ Advances the generator */ ZEND_METHOD(Generator, next) { zend_generator *generator; - if (zend_parse_parameters_none() == FAILURE) { - return; - } + ZEND_PARSE_PARAMETERS_NONE(); generator = (zend_generator *) Z_OBJ_P(ZEND_THIS); @@ -1001,8 +902,7 @@ ZEND_METHOD(Generator, next) } /* }}} */ -/* {{{ proto mixed Generator::send(mixed value) - * Sends a value to the generator */ +/* {{{ Sends a value to the generator */ ZEND_METHOD(Generator, send) { zval *value; @@ -1038,15 +938,14 @@ ZEND_METHOD(Generator, send) } /* }}} */ -/* {{{ proto mixed Generator::throw(Exception exception) - * Throws an exception into the generator */ +/* {{{ Throws an exception into the generator */ ZEND_METHOD(Generator, throw) { zval *exception; zend_generator *generator; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ZVAL(exception) + Z_PARAM_OBJECT_OF_CLASS(exception, zend_ce_throwable); ZEND_PARSE_PARAMETERS_END(); Z_TRY_ADDREF_P(exception); @@ -1076,15 +975,12 @@ ZEND_METHOD(Generator, throw) } /* }}} */ -/* {{{ proto mixed Generator::getReturn() - * Retrieves the return value of the generator */ +/* {{{ Retrieves the return value of the generator */ ZEND_METHOD(Generator, getReturn) { zend_generator *generator; - if (zend_parse_parameters_none() == FAILURE) { - return; - } + ZEND_PARSE_PARAMETERS_NONE(); generator = (zend_generator *) Z_OBJ_P(ZEND_THIS); @@ -1108,8 +1004,6 @@ ZEND_METHOD(Generator, getReturn) static void zend_generator_iterator_dtor(zend_object_iterator *iterator) /* {{{ */ { - zend_generator *generator = (zend_generator*)Z_OBJ(iterator->data); - generator->iterator = NULL; zval_ptr_dtor(&iterator->data); } /* }}} */ @@ -1174,6 +1068,14 @@ static void zend_generator_iterator_rewind(zend_object_iterator *iterator) /* {{ } /* }}} */ +static HashTable *zend_generator_iterator_get_gc( + zend_object_iterator *iterator, zval **table, int *n) +{ + *table = &iterator->data; + *n = 1; + return NULL; +} + static const zend_object_iterator_funcs zend_generator_iterator_functions = { zend_generator_iterator_dtor, zend_generator_iterator_valid, @@ -1181,9 +1083,11 @@ static const zend_object_iterator_funcs zend_generator_iterator_functions = { zend_generator_iterator_get_key, zend_generator_iterator_move_forward, zend_generator_iterator_rewind, - NULL + NULL, + zend_generator_iterator_get_gc, }; +/* by_ref is int due to Iterator API */ zend_object_iterator *zend_generator_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */ { zend_object_iterator *iterator; @@ -1199,53 +1103,28 @@ zend_object_iterator *zend_generator_get_iterator(zend_class_entry *ce, zval *ob return NULL; } - iterator = generator->iterator = emalloc(sizeof(zend_object_iterator)); - + iterator = emalloc(sizeof(zend_object_iterator)); zend_iterator_init(iterator); iterator->funcs = &zend_generator_iterator_functions; - Z_ADDREF_P(object); - ZVAL_OBJ(&iterator->data, Z_OBJ_P(object)); + ZVAL_OBJ_COPY(&iterator->data, Z_OBJ_P(object)); return iterator; } /* }}} */ -ZEND_BEGIN_ARG_INFO(arginfo_generator_void, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_generator_send, 0, 0, 1) - ZEND_ARG_INFO(0, value) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_generator_throw, 0, 0, 1) - ZEND_ARG_INFO(0, exception) -ZEND_END_ARG_INFO() - -static const zend_function_entry generator_functions[] = { - ZEND_ME(Generator, rewind, arginfo_generator_void, ZEND_ACC_PUBLIC) - ZEND_ME(Generator, valid, arginfo_generator_void, ZEND_ACC_PUBLIC) - ZEND_ME(Generator, current, arginfo_generator_void, ZEND_ACC_PUBLIC) - ZEND_ME(Generator, key, arginfo_generator_void, ZEND_ACC_PUBLIC) - ZEND_ME(Generator, next, arginfo_generator_void, ZEND_ACC_PUBLIC) - ZEND_ME(Generator, send, arginfo_generator_send, ZEND_ACC_PUBLIC) - ZEND_ME(Generator, throw, arginfo_generator_throw, ZEND_ACC_PUBLIC) - ZEND_ME(Generator, getReturn,arginfo_generator_void, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; - void zend_register_generator_ce(void) /* {{{ */ { zend_class_entry ce; - INIT_CLASS_ENTRY(ce, "Generator", generator_functions); + INIT_CLASS_ENTRY(ce, "Generator", class_Generator_methods); zend_ce_generator = zend_register_internal_class(&ce); - zend_ce_generator->ce_flags |= ZEND_ACC_FINAL; + zend_ce_generator->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NO_DYNAMIC_PROPERTIES; zend_ce_generator->create_object = zend_generator_create; zend_ce_generator->serialize = zend_class_serialize_deny; zend_ce_generator->unserialize = zend_class_unserialize_deny; - /* get_iterator has to be assigned *after* implementing the inferface */ + /* get_iterator has to be assigned *after* implementing the interface */ zend_class_implements(zend_ce_generator, 1, zend_ce_iterator); zend_ce_generator->get_iterator = zend_generator_get_iterator; |
