This source file includes following definitions.
- zend_generator_cleanup_unfinished_execution
- zend_generator_close
- zend_generator_dtor_storage
- zend_generator_free_storage
- zend_generator_get_gc
- zend_generator_create
- zend_generator_create_zval
- zend_generator_get_constructor
- zend_generator_check_placeholder_frame
- zend_generator_throw_exception
- zend_generator_get_child
- zend_generator_search_multi_children_node
- zend_generator_add_single_child
- zend_generator_merge_child_nodes
- zend_generator_add_child
- zend_generator_yield_from
- zend_generator_update_current
- zend_generator_get_next_delegated_value
- zend_generator_resume
- zend_generator_ensure_initialized
- zend_generator_rewind
- ZEND_METHOD
- ZEND_METHOD
- ZEND_METHOD
- ZEND_METHOD
- ZEND_METHOD
- ZEND_METHOD
- ZEND_METHOD
- ZEND_METHOD
- ZEND_METHOD
- zend_generator_iterator_dtor
- zend_generator_iterator_valid
- zend_generator_iterator_get_data
- zend_generator_iterator_get_key
- zend_generator_iterator_move_forward
- zend_generator_iterator_rewind
- zend_generator_get_iterator
- zend_register_generator_ce
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #include "zend.h"
23 #include "zend_API.h"
24 #include "zend_interfaces.h"
25 #include "zend_exceptions.h"
26 #include "zend_generators.h"
27
28 ZEND_API zend_class_entry *zend_ce_generator;
29 ZEND_API zend_class_entry *zend_ce_ClosedGeneratorException;
30 static zend_object_handlers zend_generator_handlers;
31
32 static zend_object *zend_generator_create(zend_class_entry *class_type);
33
34 static void zend_generator_cleanup_unfinished_execution(zend_generator *generator)
35 {
36 zend_execute_data *execute_data = generator->execute_data;
37
38 if (execute_data->opline != execute_data->func->op_array.opcodes) {
39
40 uint32_t op_num = execute_data->opline - execute_data->func->op_array.opcodes - 1;
41
42
43
44 zend_vm_stack original_stack = EG(vm_stack);
45 original_stack->top = EG(vm_stack_top);
46 EG(vm_stack_top) = generator->stack->top;
47 EG(vm_stack_end) = generator->stack->end;
48 EG(vm_stack) = generator->stack;
49
50 zend_cleanup_unfinished_execution(execute_data, op_num, 0);
51
52 generator->stack = EG(vm_stack);
53 generator->stack->top = EG(vm_stack_top);
54 EG(vm_stack_top) = original_stack->top;
55 EG(vm_stack_end) = original_stack->end;
56 EG(vm_stack) = original_stack;
57 }
58 }
59
60
61 ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished_execution)
62 {
63 if (EXPECTED(generator->execute_data)) {
64 zend_execute_data *execute_data = generator->execute_data;
65
66 if (execute_data->symbol_table) {
67 zend_clean_and_cache_symbol_table(execute_data->symbol_table);
68 }
69
70 zend_free_compiled_variables(execute_data);
71
72 if (Z_OBJ(execute_data->This)) {
73 OBJ_RELEASE(Z_OBJ(execute_data->This));
74 }
75
76
77
78 if (UNEXPECTED(CG(unclean_shutdown))) {
79 generator->execute_data = NULL;
80 return;
81 }
82
83 zend_vm_stack_free_extra_args(generator->execute_data);
84
85
86
87 if (UNEXPECTED(!finished_execution)) {
88 zend_generator_cleanup_unfinished_execution(generator);
89 }
90
91
92 if (EX_CALL_INFO() & ZEND_CALL_CLOSURE) {
93 OBJ_RELEASE((zend_object *) EX(func)->common.prototype);
94 }
95
96 efree(generator->stack);
97 generator->execute_data = NULL;
98 }
99 }
100
101
102 static zend_generator *zend_generator_get_child(zend_generator_node *node, zend_generator *leaf);
103
104 static void zend_generator_dtor_storage(zend_object *object)
105 {
106 zend_generator *generator = (zend_generator*) object;
107 zend_execute_data *ex = generator->execute_data;
108 uint32_t op_num, finally_op_num, finally_op_end;
109 int i;
110
111
112 if (UNEXPECTED(Z_TYPE(generator->values) != IS_UNDEF)) {
113 zval_ptr_dtor(&generator->values);
114 ZVAL_UNDEF(&generator->values);
115 }
116
117 if (EXPECTED(generator->node.children == 0)) {
118 zend_generator *root = generator->node.ptr.root, *next;
119 while (UNEXPECTED(root != generator)) {
120 next = zend_generator_get_child(&root->node, generator);
121 OBJ_RELEASE(&root->std);
122 root = next;
123 }
124 generator->node.parent = NULL;
125 }
126
127 if (EXPECTED(!ex) || EXPECTED(!(ex->func->op_array.fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK))) {
128 return;
129 }
130
131
132
133 op_num = ex->opline - ex->func->op_array.opcodes - 1;
134
135
136 finally_op_num = 0;
137 finally_op_end = 0;
138 for (i = 0; i < ex->func->op_array.last_try_catch; i++) {
139 zend_try_catch_element *try_catch = &ex->func->op_array.try_catch_array[i];
140
141 if (op_num < try_catch->try_op) {
142 break;
143 }
144
145 if (op_num < try_catch->finally_op) {
146 finally_op_num = try_catch->finally_op;
147 finally_op_end = try_catch->finally_end;
148 }
149 }
150
151
152
153 if (finally_op_num) {
154 zval *fast_call = ZEND_CALL_VAR(ex, ex->func->op_array.opcodes[finally_op_end].op1.var);
155
156 Z_OBJ_P(fast_call) = EG(exception);
157 EG(exception) = NULL;
158 fast_call->u2.lineno = (uint32_t)-1;
159
160 ex->opline = &ex->func->op_array.opcodes[finally_op_num];
161 generator->flags |= ZEND_GENERATOR_FORCED_CLOSE;
162 zend_generator_resume(generator);
163 }
164 }
165
166
167 static void zend_generator_free_storage(zend_object *object)
168 {
169 zend_generator *generator = (zend_generator*) object;
170
171 zend_generator_close(generator, 0);
172
173
174 zval_ptr_dtor(&generator->value);
175 zval_ptr_dtor(&generator->key);
176
177 if (EXPECTED(!Z_ISUNDEF(generator->retval))) {
178 zval_ptr_dtor(&generator->retval);
179 }
180
181 if (UNEXPECTED(generator->node.children > 4)) {
182 zend_hash_destroy(&generator->node.child.ht);
183 }
184
185 zend_object_std_dtor(&generator->std);
186
187 if (generator->iterator) {
188 zend_iterator_dtor(generator->iterator);
189 }
190 }
191
192
193 static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n)
194 {
195 zend_generator *generator = (zend_generator*) Z_OBJ_P(object);
196 *table = &generator->value;
197 *n = 3;
198 return NULL;
199 }
200
201
202 static zend_object *zend_generator_create(zend_class_entry *class_type)
203 {
204 zend_generator *generator;
205
206 generator = emalloc(sizeof(zend_generator));
207 memset(generator, 0, sizeof(zend_generator));
208
209
210 generator->largest_used_integer_key = -1;
211
212 ZVAL_UNDEF(&generator->retval);
213 ZVAL_UNDEF(&generator->values);
214
215
216 generator->node.parent = NULL;
217 generator->node.children = 0;
218 generator->node.ptr.root = generator;
219
220 zend_object_std_init(&generator->std, class_type);
221 generator->std.handlers = &zend_generator_handlers;
222
223 return (zend_object*)generator;
224 }
225
226
227
228 ZEND_API void zend_generator_create_zval(zend_execute_data *call, zend_op_array *op_array, zval *return_value)
229 {
230 zend_generator *generator;
231 zend_execute_data *current_execute_data;
232 zend_execute_data *execute_data;
233 zend_vm_stack current_stack = EG(vm_stack);
234
235 current_stack->top = EG(vm_stack_top);
236
237
238 current_execute_data = EG(current_execute_data);
239 execute_data = zend_create_generator_execute_data(call, op_array, return_value);
240 EG(current_execute_data) = current_execute_data;
241
242 object_init_ex(return_value, zend_ce_generator);
243
244 if (Z_OBJ(call->This)) {
245 Z_ADDREF(call->This);
246 }
247
248
249 generator = (zend_generator *) Z_OBJ_P(return_value);
250 generator->execute_data = execute_data;
251 generator->stack = EG(vm_stack);
252 generator->stack->top = EG(vm_stack_top);
253 EG(vm_stack_top) = current_stack->top;
254 EG(vm_stack_end) = current_stack->end;
255 EG(vm_stack) = current_stack;
256
257
258 execute_data->return_value = (zval*)generator;
259
260 memset(&generator->execute_fake, 0, sizeof(zend_execute_data));
261 Z_OBJ(generator->execute_fake.This) = (zend_object *) generator;
262 }
263
264
265 static ZEND_COLD zend_function *zend_generator_get_constructor(zend_object *object)
266 {
267 zend_throw_error(NULL, "The \"Generator\" class is reserved for internal use and cannot be manually instantiated");
268
269 return NULL;
270 }
271
272
273 ZEND_API zend_execute_data *zend_generator_check_placeholder_frame(zend_execute_data *ptr)
274 {
275 if (!ptr->func && Z_OBJ(ptr->This)) {
276 if (Z_OBJCE(ptr->This) == zend_ce_generator) {
277 zend_generator *generator = (zend_generator *) Z_OBJ(ptr->This);
278 zend_generator *root = (generator->node.children < 1 ? generator : generator->node.ptr.leaf)->node.ptr.root;
279 zend_execute_data *prev = ptr->prev_execute_data;
280 if (generator->node.parent != root) {
281 do {
282 generator->execute_data->prev_execute_data = prev;
283 prev = generator->execute_data;
284 generator = generator->node.parent;
285 } while (generator->node.parent != root);
286 }
287 generator->execute_data->prev_execute_data = prev;
288 ptr = generator->execute_data;
289 }
290 }
291 return ptr;
292 }
293
294 static void zend_generator_throw_exception(zend_generator *generator, zval *exception)
295 {
296
297 if (UNEXPECTED(Z_TYPE(generator->values) != IS_UNDEF)) {
298 zval_ptr_dtor(&generator->values);
299 ZVAL_UNDEF(&generator->values);
300 }
301
302
303
304 zend_execute_data *original_execute_data = EG(current_execute_data);
305 EG(current_execute_data) = generator->execute_data;
306 generator->execute_data->opline--;
307 if (exception) {
308 zend_throw_exception_object(exception);
309 } else {
310 zend_throw_exception_internal(NULL);
311 }
312 generator->execute_data->opline++;
313 EG(current_execute_data) = original_execute_data;
314 }
315
316 static zend_generator *zend_generator_get_child(zend_generator_node *node, zend_generator *leaf)
317 {
318 switch (node->children) {
319 case 0:
320 return NULL;
321 case 1:
322 return node->child.array[0].child;
323
324 #define ZEND_GEN_GET_CHILD(x) \
325 if (node->child.array[x].leaf == leaf) { \
326 return node->child.array[x].child; \
327 }
328 case 4:
329 ZEND_GEN_GET_CHILD(3)
330 case 3:
331 ZEND_GEN_GET_CHILD(2)
332 case 2:
333 ZEND_GEN_GET_CHILD(1)
334 ZEND_GEN_GET_CHILD(0)
335 ZEND_ASSERT(0);
336 }
337
338 return zend_hash_index_find_ptr(&node->child.ht, (zend_ulong) leaf);
339 }
340
341 static zend_generator_node *zend_generator_search_multi_children_node(zend_generator_node *node)
342 {
343 while (node->children == 1) {
344 node = &node->child.array[0].child->node;
345 }
346 return node->children > 1 ? node : NULL;
347 }
348
349 static void zend_generator_add_single_child(zend_generator_node *node, zend_generator *child, zend_generator *leaf)
350 {
351 if (node->children < 4) {
352 node->child.array[node->children].leaf = leaf;
353 node->child.array[node->children].child = child;
354 } else if (node->children > 4) {
355 zend_hash_index_add_ptr(&node->child.ht, (zend_ulong) leaf, child);
356 } else {
357 struct {
358 zend_generator *leaf;
359 zend_generator *child;
360 } array[4];
361 int i;
362
363 memcpy(&array, &node->child.array, sizeof(array));
364 zend_hash_init(&node->child.ht, 5, sigh, NULL, 0);
365 for (i = 0; i < 4; i++) {
366 zend_hash_index_add_ptr(&node->child.ht, (zend_ulong) array[i].leaf, array[i].child);
367 }
368 zend_hash_index_add_ptr(&node->child.ht, (zend_ulong) leaf, child);
369 }
370
371 node->children++;
372 }
373
374 static void zend_generator_merge_child_nodes(zend_generator_node *dest, zend_generator_node *src, zend_generator *child)
375 {
376 if (src->children <= 4) {
377 int i = src->children;
378 while (i--) {
379 zend_generator_add_single_child(dest, child, src->child.array[i].leaf);
380 }
381 } else {
382 zend_ulong leaf;
383 ZEND_HASH_FOREACH_NUM_KEY(&src->child.ht, leaf) {
384 zend_generator_add_single_child(dest, child, (zend_generator *) leaf);
385 } ZEND_HASH_FOREACH_END();
386 }
387 }
388
389
390 static void zend_generator_add_child(zend_generator *generator, zend_generator *child)
391 {
392 zend_generator *leaf = child->node.children ? child->node.ptr.leaf : child;
393 zend_generator_node *multi_children_node;
394 zend_bool was_leaf = generator->node.children == 0;
395
396 if (was_leaf) {
397 zend_generator *next = generator->node.parent;
398 leaf->node.ptr.root = generator->node.ptr.root;
399 ++GC_REFCOUNT(&generator->std);
400 generator->node.ptr.leaf = leaf;
401
402 while (next) {
403 if (next->node.children > 1) {
404 if (next->node.children > 4) {
405 zend_generator *child = zend_hash_index_find_ptr(&next->node.child.ht, (zend_ulong) generator);
406 zend_hash_index_del(&next->node.child.ht, (zend_ulong) generator);
407 zend_hash_index_add_ptr(&next->node.child.ht, (zend_ulong) leaf, child);
408 } else {
409 switch (next->node.children) {
410 #define ZEND_GEN_UPDATE_CHILD(x) \
411 if (next->node.child.array[x].leaf == generator) { \
412 next->node.child.array[x].leaf = leaf; \
413 break; \
414 }
415 case 4:
416 ZEND_GEN_UPDATE_CHILD(3)
417 case 3:
418 ZEND_GEN_UPDATE_CHILD(2)
419 case 2:
420 ZEND_GEN_UPDATE_CHILD(1)
421 ZEND_GEN_UPDATE_CHILD(0)
422 ZEND_ASSERT(0);
423 }
424 }
425 }
426
427 next->node.ptr.leaf = leaf;
428 next = next->node.parent;
429 }
430
431 zend_generator_add_single_child(&generator->node, child, leaf);
432 } else if (generator->node.children == 1) {
433 multi_children_node = zend_generator_search_multi_children_node(&generator->node);
434 if (multi_children_node) {
435 generator->node.children = 0;
436 zend_generator_merge_child_nodes(&generator->node, multi_children_node, generator->node.child.array[0].child);
437 }
438 }
439
440 if (!was_leaf) {
441 multi_children_node = zend_generator_search_multi_children_node(&child->node);
442 } else {
443 multi_children_node = (zend_generator_node *) 0x1;
444 }
445
446 {
447 zend_generator *parent = generator->node.parent, *cur = generator;
448
449 if (multi_children_node > (zend_generator_node *) 0x1) {
450 zend_generator_merge_child_nodes(&generator->node, multi_children_node, child);
451 } else {
452 zend_generator_add_single_child(&generator->node, child, leaf);
453 }
454 while (parent) {
455 if (parent->node.children > 1) {
456 if (multi_children_node == (zend_generator_node *) 0x1) {
457 multi_children_node = zend_generator_search_multi_children_node(&child->node);
458 }
459 if (multi_children_node) {
460 zend_generator_merge_child_nodes(&parent->node, multi_children_node, cur);
461 } else {
462 zend_generator_add_single_child(&parent->node, cur, leaf);
463 }
464 }
465 cur = parent;
466 parent = parent->node.parent;
467 }
468 }
469 }
470
471 void zend_generator_yield_from(zend_generator *generator, zend_generator *from)
472 {
473 zend_generator_add_child(from, generator);
474
475 generator->node.parent = from;
476 zend_generator_get_current(generator);
477 --GC_REFCOUNT(&from->std);
478 }
479
480 ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator, zend_generator *leaf)
481 {
482 zend_generator *old_root, *root = leaf->node.ptr.root;
483
484
485 if (root != generator) {
486 old_root = root;
487 root = zend_generator_get_child(&root->node, leaf);
488 } else {
489 old_root = NULL;
490 }
491
492 while (!root->execute_data && root != generator) {
493 OBJ_RELEASE(&old_root->std);
494 old_root = root;
495
496 root = zend_generator_get_child(&root->node, leaf);
497 }
498
499 if (root->node.parent) {
500 if (root->node.parent->execute_data == NULL) {
501 if (EXPECTED(EG(exception) == NULL)) {
502 zend_op *yield_from = (zend_op *) root->execute_data->opline - 1;
503
504 if (yield_from->opcode == ZEND_YIELD_FROM) {
505 if (Z_ISUNDEF(root->node.parent->retval)) {
506
507 zend_execute_data *original_execute_data = EG(current_execute_data);
508 EG(current_execute_data) = root->execute_data;
509
510 if (root == generator) {
511 root->execute_data->prev_execute_data = original_execute_data;
512 } else {
513 root->execute_data->prev_execute_data = &generator->execute_fake;
514 generator->execute_fake.prev_execute_data = original_execute_data;
515 }
516
517 zend_throw_exception(zend_ce_ClosedGeneratorException, "Generator yielded from aborted, no return value available", 0);
518
519 EG(current_execute_data) = original_execute_data;
520 } else {
521 zval_ptr_dtor(&root->value);
522 ZVAL_COPY(&root->value, &root->node.parent->value);
523 ZVAL_COPY(ZEND_CALL_VAR(root->execute_data, yield_from->result.var), &root->node.parent->retval);
524 }
525 }
526 }
527
528 root->node.parent = NULL;
529 } else {
530 do {
531 root = root->node.parent;
532 ++GC_REFCOUNT(&root->std);
533 } while (root->node.parent);
534 }
535 }
536
537 if (old_root) {
538 OBJ_RELEASE(&old_root->std);
539 }
540
541 return leaf->node.ptr.root = root;
542 }
543
544 static int zend_generator_get_next_delegated_value(zend_generator *generator)
545 {
546 zval *value;
547 if (Z_TYPE(generator->values) == IS_ARRAY) {
548 HashTable *ht = Z_ARR(generator->values);
549 HashPosition pos = Z_FE_POS(generator->values);
550
551 Bucket *p;
552 do {
553 if (UNEXPECTED(pos >= ht->nNumUsed)) {
554
555 goto failure;
556 }
557
558 p = &ht->arData[pos];
559 value = &p->val;
560 if (Z_TYPE_P(value) == IS_INDIRECT) {
561 value = Z_INDIRECT_P(value);
562 }
563 pos++;
564 } while (Z_ISUNDEF_P(value));
565
566 zval_ptr_dtor(&generator->value);
567 ZVAL_COPY(&generator->value, value);
568
569 zval_ptr_dtor(&generator->key);
570 if (p->key) {
571 ZVAL_STR_COPY(&generator->key, p->key);
572 } else {
573 ZVAL_LONG(&generator->key, p->h);
574 }
575
576 Z_FE_POS(generator->values) = pos;
577 } else {
578 zend_object_iterator *iter = (zend_object_iterator *) Z_OBJ(generator->values);
579
580 if (iter->index++ > 0) {
581 iter->funcs->move_forward(iter);
582 if (UNEXPECTED(EG(exception) != NULL)) {
583 goto exception;
584 }
585 }
586
587 if (iter->funcs->valid(iter) == FAILURE) {
588
589 goto failure;
590 }
591
592 value = iter->funcs->get_current_data(iter);
593 if (UNEXPECTED(EG(exception) != NULL)) {
594 goto exception;
595 } else if (UNEXPECTED(!value)) {
596 goto failure;
597 }
598
599 zval_ptr_dtor(&generator->value);
600 ZVAL_COPY(&generator->value, value);
601
602 zval_ptr_dtor(&generator->key);
603 if (iter->funcs->get_current_key) {
604 iter->funcs->get_current_key(iter, &generator->key);
605 if (UNEXPECTED(EG(exception) != NULL)) {
606 ZVAL_UNDEF(&generator->key);
607 goto exception;
608 }
609 } else {
610 ZVAL_LONG(&generator->key, iter->index);
611 }
612 }
613 return SUCCESS;
614
615 exception: {
616 zend_execute_data *ex = EG(current_execute_data);
617 EG(current_execute_data) = generator->execute_data;
618 zend_throw_exception_internal(NULL);
619 EG(current_execute_data) = ex;
620 }
621
622 failure:
623 zval_ptr_dtor(&generator->values);
624 ZVAL_UNDEF(&generator->values);
625 return FAILURE;
626 }
627
628
629 ZEND_API void zend_generator_resume(zend_generator *orig_generator)
630 {
631 zend_generator *generator;
632
633
634 if (UNEXPECTED(!orig_generator->execute_data)) {
635 return;
636 }
637
638 generator = zend_generator_get_current(orig_generator);
639
640 try_again:
641 if (generator->flags & ZEND_GENERATOR_CURRENTLY_RUNNING) {
642 zend_throw_error(NULL, "Cannot resume an already running generator");
643 return;
644 }
645
646 if (UNEXPECTED((orig_generator->flags & ZEND_GENERATOR_DO_INIT) != 0 && !Z_ISUNDEF(generator->value))) {
647
648 return;
649 }
650
651 if (UNEXPECTED(!Z_ISUNDEF(generator->values))) {
652 if (EXPECTED(zend_generator_get_next_delegated_value(generator) == SUCCESS)) {
653 return;
654 }
655
656
657 }
658
659
660 orig_generator->flags &= ~ZEND_GENERATOR_AT_FIRST_YIELD;
661
662 {
663
664 zend_execute_data *original_execute_data = EG(current_execute_data);
665 zend_class_entry *original_scope = EG(scope);
666 zend_vm_stack original_stack = EG(vm_stack);
667 original_stack->top = EG(vm_stack_top);
668
669
670 EG(current_execute_data) = generator->execute_data;
671 EG(scope) = generator->execute_data->func->common.scope;
672 EG(vm_stack_top) = generator->stack->top;
673 EG(vm_stack_end) = generator->stack->end;
674 EG(vm_stack) = generator->stack;
675
676
677
678
679 if (generator == orig_generator) {
680 generator->execute_data->prev_execute_data = original_execute_data;
681 } else {
682
683
684 generator->execute_data->prev_execute_data = &orig_generator->execute_fake;
685 orig_generator->execute_fake.prev_execute_data = original_execute_data;
686 }
687
688
689 generator->flags |= ZEND_GENERATOR_CURRENTLY_RUNNING;
690 zend_execute_ex(generator->execute_data);
691 generator->flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING;
692
693
694 if (EXPECTED(generator->execute_data)) {
695 generator->stack = EG(vm_stack);
696 generator->stack->top = EG(vm_stack_top);
697 }
698
699
700 EG(current_execute_data) = original_execute_data;
701 EG(scope) = original_scope;
702 EG(vm_stack_top) = original_stack->top;
703 EG(vm_stack_end) = original_stack->end;
704 EG(vm_stack) = original_stack;
705
706
707
708
709
710 if (UNEXPECTED(EG(exception) != NULL)) {
711 if (generator == orig_generator) {
712 zend_generator_close(generator, 0);
713 zend_throw_exception_internal(NULL);
714 } else {
715 generator = zend_generator_get_current(orig_generator);
716 zend_generator_throw_exception(generator, NULL);
717 goto try_again;
718 }
719 }
720
721
722 if (UNEXPECTED((generator != orig_generator && !Z_ISUNDEF(generator->retval)) || (generator->execute_data && (generator->execute_data->opline - 1)->opcode == ZEND_YIELD_FROM))) {
723 generator = zend_generator_get_current(orig_generator);
724 goto try_again;
725 }
726 }
727 }
728
729
730 static void inline zend_generator_ensure_initialized(zend_generator *generator)
731 {
732 if (UNEXPECTED(Z_TYPE(generator->value) == IS_UNDEF) && EXPECTED(generator->execute_data) && EXPECTED(generator->node.parent == NULL)) {
733 generator->flags |= ZEND_GENERATOR_DO_INIT;
734 zend_generator_resume(generator);
735 generator->flags &= ~ZEND_GENERATOR_DO_INIT;
736 generator->flags |= ZEND_GENERATOR_AT_FIRST_YIELD;
737 }
738 }
739
740
741 static void inline zend_generator_rewind(zend_generator *generator)
742 {
743 zend_generator_ensure_initialized(generator);
744
745 if (!(generator->flags & ZEND_GENERATOR_AT_FIRST_YIELD)) {
746 zend_throw_exception(NULL, "Cannot rewind a generator that was already run", 0);
747 }
748 }
749
750
751
752
753 ZEND_METHOD(Generator, rewind)
754 {
755 zend_generator *generator;
756
757 if (zend_parse_parameters_none() == FAILURE) {
758 return;
759 }
760
761 generator = (zend_generator *) Z_OBJ_P(getThis());
762
763 zend_generator_rewind(generator);
764 }
765
766
767
768
769 ZEND_METHOD(Generator, valid)
770 {
771 zend_generator *generator;
772
773 if (zend_parse_parameters_none() == FAILURE) {
774 return;
775 }
776
777 generator = (zend_generator *) Z_OBJ_P(getThis());
778
779 zend_generator_ensure_initialized(generator);
780
781 zend_generator_get_current(generator);
782
783 RETURN_BOOL(EXPECTED(generator->execute_data != NULL));
784 }
785
786
787
788
789 ZEND_METHOD(Generator, current)
790 {
791 zend_generator *generator, *root;
792
793 if (zend_parse_parameters_none() == FAILURE) {
794 return;
795 }
796
797 generator = (zend_generator *) Z_OBJ_P(getThis());
798
799 zend_generator_ensure_initialized(generator);
800
801 root = zend_generator_get_current(generator);
802 if (EXPECTED(generator->execute_data != NULL && Z_TYPE(root->value) != IS_UNDEF)) {
803 zval *value = &root->value;
804
805 ZVAL_DEREF(value);
806 ZVAL_COPY(return_value, value);
807 }
808 }
809
810
811
812
813 ZEND_METHOD(Generator, key)
814 {
815 zend_generator *generator, *root;
816
817 if (zend_parse_parameters_none() == FAILURE) {
818 return;
819 }
820
821 generator = (zend_generator *) Z_OBJ_P(getThis());
822
823 zend_generator_ensure_initialized(generator);
824
825 root = zend_generator_get_current(generator);
826 if (EXPECTED(generator->execute_data != NULL && Z_TYPE(root->key) != IS_UNDEF)) {
827 zval *key = &root->key;
828
829 ZVAL_DEREF(key);
830 ZVAL_COPY(return_value, key);
831 }
832 }
833
834
835
836
837 ZEND_METHOD(Generator, next)
838 {
839 zend_generator *generator;
840
841 if (zend_parse_parameters_none() == FAILURE) {
842 return;
843 }
844
845 generator = (zend_generator *) Z_OBJ_P(getThis());
846
847 zend_generator_ensure_initialized(generator);
848
849 zend_generator_resume(generator);
850 }
851
852
853
854
855 ZEND_METHOD(Generator, send)
856 {
857 zval *value;
858 zend_generator *generator, *root;
859
860 #ifndef FAST_ZPP
861 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &value) == FAILURE) {
862 return;
863 }
864 #else
865 ZEND_PARSE_PARAMETERS_START(1, 1)
866 Z_PARAM_ZVAL(value)
867 ZEND_PARSE_PARAMETERS_END();
868 #endif
869
870 generator = (zend_generator *) Z_OBJ_P(getThis());
871
872 zend_generator_ensure_initialized(generator);
873
874
875 if (UNEXPECTED(!generator->execute_data)) {
876 return;
877 }
878
879 root = zend_generator_get_current(generator);
880
881 if (root->send_target) {
882 ZVAL_COPY(root->send_target, value);
883 }
884
885 zend_generator_resume(generator);
886
887 root = zend_generator_get_current(generator);
888 if (EXPECTED(generator->execute_data)) {
889 zval *value = &root->value;
890
891 ZVAL_DEREF(value);
892 ZVAL_COPY(return_value, value);
893 }
894 }
895
896
897
898
899 ZEND_METHOD(Generator, throw)
900 {
901 zval *exception, exception_copy;
902 zend_generator *generator;
903
904 #ifndef FAST_ZPP
905 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &exception) == FAILURE) {
906 return;
907 }
908 #else
909 ZEND_PARSE_PARAMETERS_START(1, 1)
910 Z_PARAM_ZVAL(exception)
911 ZEND_PARSE_PARAMETERS_END();
912 #endif
913
914 ZVAL_DUP(&exception_copy, exception);
915
916 generator = (zend_generator *) Z_OBJ_P(getThis());
917
918 zend_generator_ensure_initialized(generator);
919
920 if (generator->execute_data) {
921 zend_generator *root = zend_generator_get_current(generator);
922
923 zend_generator_throw_exception(root, &exception_copy);
924
925 zend_generator_resume(generator);
926
927 root = zend_generator_get_current(generator);
928 if (generator->execute_data) {
929 zval *value = &root->value;
930
931 ZVAL_DEREF(value);
932 ZVAL_COPY(return_value, value);
933 }
934 } else {
935
936
937 zend_throw_exception_object(&exception_copy);
938 }
939 }
940
941
942
943
944 ZEND_METHOD(Generator, getReturn)
945 {
946 zend_generator *generator;
947
948 if (zend_parse_parameters_none() == FAILURE) {
949 return;
950 }
951
952 generator = (zend_generator *) Z_OBJ_P(getThis());
953
954 zend_generator_ensure_initialized(generator);
955 if (UNEXPECTED(EG(exception))) {
956 return;
957 }
958
959 if (Z_ISUNDEF(generator->retval)) {
960
961 zend_throw_exception(NULL,
962 "Cannot get return value of a generator that hasn't returned", 0);
963 return;
964 }
965
966 ZVAL_COPY(return_value, &generator->retval);
967 }
968
969
970
971
972 ZEND_METHOD(Generator, __wakeup)
973 {
974
975
976
977
978 if (zend_parse_parameters_none() == FAILURE) {
979 return;
980 }
981
982 zend_throw_exception(NULL, "Unserialization of 'Generator' is not allowed", 0);
983 }
984
985
986
987
988 static void zend_generator_iterator_dtor(zend_object_iterator *iterator)
989 {
990 zend_generator *generator = (zend_generator*)Z_OBJ(iterator->data);
991 generator->iterator = NULL;
992 zval_ptr_dtor(&iterator->data);
993 zend_iterator_dtor(iterator);
994 }
995
996
997 static int zend_generator_iterator_valid(zend_object_iterator *iterator)
998 {
999 zend_generator *generator = (zend_generator*)Z_OBJ(iterator->data);
1000
1001 zend_generator_ensure_initialized(generator);
1002
1003 zend_generator_get_current(generator);
1004
1005 return generator->execute_data ? SUCCESS : FAILURE;
1006 }
1007
1008
1009 static zval *zend_generator_iterator_get_data(zend_object_iterator *iterator)
1010 {
1011 zend_generator *generator = (zend_generator*)Z_OBJ(iterator->data), *root;
1012
1013 zend_generator_ensure_initialized(generator);
1014
1015 root = zend_generator_get_current(generator);
1016
1017 return &root->value;
1018 }
1019
1020
1021 static void zend_generator_iterator_get_key(zend_object_iterator *iterator, zval *key)
1022 {
1023 zend_generator *generator = (zend_generator*)Z_OBJ(iterator->data), *root;
1024
1025 zend_generator_ensure_initialized(generator);
1026
1027 root = zend_generator_get_current(generator);
1028
1029 if (EXPECTED(Z_TYPE(root->key) != IS_UNDEF)) {
1030 zval *zv = &root->key;
1031
1032 ZVAL_DEREF(zv);
1033 ZVAL_COPY(key, zv);
1034 } else {
1035 ZVAL_NULL(key);
1036 }
1037 }
1038
1039
1040 static void zend_generator_iterator_move_forward(zend_object_iterator *iterator)
1041 {
1042 zend_generator *generator = (zend_generator*)Z_OBJ(iterator->data);
1043
1044 zend_generator_ensure_initialized(generator);
1045
1046 zend_generator_resume(generator);
1047 }
1048
1049
1050 static void zend_generator_iterator_rewind(zend_object_iterator *iterator)
1051 {
1052 zend_generator *generator = (zend_generator*)Z_OBJ(iterator->data);
1053
1054 zend_generator_rewind(generator);
1055 }
1056
1057
1058 static zend_object_iterator_funcs zend_generator_iterator_functions = {
1059 zend_generator_iterator_dtor,
1060 zend_generator_iterator_valid,
1061 zend_generator_iterator_get_data,
1062 zend_generator_iterator_get_key,
1063 zend_generator_iterator_move_forward,
1064 zend_generator_iterator_rewind
1065 };
1066
1067 zend_object_iterator *zend_generator_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
1068 {
1069 zend_object_iterator *iterator;
1070 zend_generator *generator = (zend_generator*)Z_OBJ_P(object);
1071
1072 if (!generator->execute_data) {
1073 zend_throw_exception(NULL, "Cannot traverse an already closed generator", 0);
1074 return NULL;
1075 }
1076
1077 if (UNEXPECTED(by_ref) && !(generator->execute_data->func->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
1078 zend_throw_exception(NULL, "You can only iterate a generator by-reference if it declared that it yields by-reference", 0);
1079 return NULL;
1080 }
1081
1082 iterator = generator->iterator = emalloc(sizeof(zend_object_iterator));
1083
1084 zend_iterator_init(iterator);
1085
1086 iterator->funcs = &zend_generator_iterator_functions;
1087 ZVAL_COPY(&iterator->data, object);
1088
1089 return iterator;
1090 }
1091
1092
1093 ZEND_BEGIN_ARG_INFO(arginfo_generator_void, 0)
1094 ZEND_END_ARG_INFO()
1095
1096 ZEND_BEGIN_ARG_INFO_EX(arginfo_generator_send, 0, 0, 1)
1097 ZEND_ARG_INFO(0, value)
1098 ZEND_END_ARG_INFO()
1099
1100 ZEND_BEGIN_ARG_INFO_EX(arginfo_generator_throw, 0, 0, 1)
1101 ZEND_ARG_INFO(0, exception)
1102 ZEND_END_ARG_INFO()
1103
1104 static const zend_function_entry generator_functions[] = {
1105 ZEND_ME(Generator, rewind, arginfo_generator_void, ZEND_ACC_PUBLIC)
1106 ZEND_ME(Generator, valid, arginfo_generator_void, ZEND_ACC_PUBLIC)
1107 ZEND_ME(Generator, current, arginfo_generator_void, ZEND_ACC_PUBLIC)
1108 ZEND_ME(Generator, key, arginfo_generator_void, ZEND_ACC_PUBLIC)
1109 ZEND_ME(Generator, next, arginfo_generator_void, ZEND_ACC_PUBLIC)
1110 ZEND_ME(Generator, send, arginfo_generator_send, ZEND_ACC_PUBLIC)
1111 ZEND_ME(Generator, throw, arginfo_generator_throw, ZEND_ACC_PUBLIC)
1112 ZEND_ME(Generator, getReturn,arginfo_generator_void, ZEND_ACC_PUBLIC)
1113 ZEND_ME(Generator, __wakeup, arginfo_generator_void, ZEND_ACC_PUBLIC)
1114 ZEND_FE_END
1115 };
1116
1117 void zend_register_generator_ce(void)
1118 {
1119 zend_class_entry ce;
1120
1121 INIT_CLASS_ENTRY(ce, "Generator", generator_functions);
1122 zend_ce_generator = zend_register_internal_class(&ce);
1123 zend_ce_generator->ce_flags |= ZEND_ACC_FINAL;
1124 zend_ce_generator->create_object = zend_generator_create;
1125 zend_ce_generator->serialize = zend_class_serialize_deny;
1126 zend_ce_generator->unserialize = zend_class_unserialize_deny;
1127
1128
1129 zend_class_implements(zend_ce_generator, 1, zend_ce_iterator);
1130 zend_ce_generator->get_iterator = zend_generator_get_iterator;
1131 zend_ce_generator->iterator_funcs.funcs = &zend_generator_iterator_functions;
1132
1133 memcpy(&zend_generator_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1134 zend_generator_handlers.free_obj = zend_generator_free_storage;
1135 zend_generator_handlers.dtor_obj = zend_generator_dtor_storage;
1136 zend_generator_handlers.get_gc = zend_generator_get_gc;
1137 zend_generator_handlers.clone_obj = NULL;
1138 zend_generator_handlers.get_constructor = zend_generator_get_constructor;
1139
1140 INIT_CLASS_ENTRY(ce, "ClosedGeneratorException", NULL);
1141 zend_ce_ClosedGeneratorException = zend_register_internal_class_ex(&ce, zend_ce_exception);
1142 }
1143
1144
1145
1146
1147
1148
1149
1150
1151