zend_generators.c 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend Engine |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1998-2018 Zend Technologies Ltd. (http://www.zend.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 2.00 of the Zend license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.zend.com/license/2_00.txt. |
  11. | If you did not receive a copy of the Zend license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@zend.com so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Nikita Popov <nikic@php.net> |
  16. | Bob Weinand <bobwei9@hotmail.com> |
  17. +----------------------------------------------------------------------+
  18. */
  19. #include "zend.h"
  20. #include "zend_API.h"
  21. #include "zend_interfaces.h"
  22. #include "zend_exceptions.h"
  23. #include "zend_generators.h"
  24. #include "zend_closures.h"
  25. ZEND_API zend_class_entry *zend_ce_generator;
  26. ZEND_API zend_class_entry *zend_ce_ClosedGeneratorException;
  27. static zend_object_handlers zend_generator_handlers;
  28. static zend_object *zend_generator_create(zend_class_entry *class_type);
  29. ZEND_API void zend_generator_restore_call_stack(zend_generator *generator) /* {{{ */
  30. {
  31. zend_execute_data *call, *new_call, *prev_call = NULL;
  32. call = generator->frozen_call_stack;
  33. do {
  34. new_call = zend_vm_stack_push_call_frame(
  35. (ZEND_CALL_INFO(call) & ~ZEND_CALL_ALLOCATED),
  36. call->func,
  37. ZEND_CALL_NUM_ARGS(call),
  38. (Z_TYPE(call->This) == IS_UNDEF) ?
  39. (zend_class_entry*)Z_OBJ(call->This) : NULL,
  40. (Z_TYPE(call->This) != IS_UNDEF) ?
  41. Z_OBJ(call->This) : NULL);
  42. memcpy(((zval*)new_call) + ZEND_CALL_FRAME_SLOT, ((zval*)call) + ZEND_CALL_FRAME_SLOT, ZEND_CALL_NUM_ARGS(call) * sizeof(zval));
  43. new_call->prev_execute_data = prev_call;
  44. prev_call = new_call;
  45. call = call->prev_execute_data;
  46. } while (call);
  47. generator->execute_data->call = prev_call;
  48. efree(generator->frozen_call_stack);
  49. generator->frozen_call_stack = NULL;
  50. }
  51. /* }}} */
  52. ZEND_API zend_execute_data* zend_generator_freeze_call_stack(zend_execute_data *execute_data) /* {{{ */
  53. {
  54. size_t used_stack;
  55. zend_execute_data *call, *new_call, *prev_call = NULL;
  56. zval *stack;
  57. /* calculate required stack size */
  58. used_stack = 0;
  59. call = EX(call);
  60. do {
  61. used_stack += ZEND_CALL_FRAME_SLOT + ZEND_CALL_NUM_ARGS(call);
  62. call = call->prev_execute_data;
  63. } while (call);
  64. stack = emalloc(used_stack * sizeof(zval));
  65. /* save stack, linking frames in reverse order */
  66. call = EX(call);
  67. do {
  68. size_t frame_size = ZEND_CALL_FRAME_SLOT + ZEND_CALL_NUM_ARGS(call);
  69. new_call = (zend_execute_data*)(stack + used_stack - frame_size);
  70. memcpy(new_call, call, frame_size * sizeof(zval));
  71. used_stack -= frame_size;
  72. new_call->prev_execute_data = prev_call;
  73. prev_call = new_call;
  74. new_call = call->prev_execute_data;
  75. zend_vm_stack_free_call_frame(call);
  76. call = new_call;
  77. } while (call);
  78. execute_data->call = NULL;
  79. ZEND_ASSERT(prev_call == (zend_execute_data*)stack);
  80. return prev_call;
  81. }
  82. /* }}} */
  83. static void zend_generator_cleanup_unfinished_execution(
  84. zend_generator *generator, zend_execute_data *execute_data, uint32_t catch_op_num) /* {{{ */
  85. {
  86. if (execute_data->opline != execute_data->func->op_array.opcodes) {
  87. /* -1 required because we want the last run opcode, not the next to-be-run one. */
  88. uint32_t op_num = execute_data->opline - execute_data->func->op_array.opcodes - 1;
  89. if (UNEXPECTED(generator->frozen_call_stack)) {
  90. /* Temporarily restore generator->execute_data if it has been NULLed out already. */
  91. zend_execute_data *save_ex = generator->execute_data;
  92. generator->execute_data = execute_data;
  93. zend_generator_restore_call_stack(generator);
  94. generator->execute_data = save_ex;
  95. }
  96. zend_cleanup_unfinished_execution(execute_data, op_num, catch_op_num);
  97. }
  98. }
  99. /* }}} */
  100. ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished_execution) /* {{{ */
  101. {
  102. if (EXPECTED(generator->execute_data)) {
  103. zend_execute_data *execute_data = generator->execute_data;
  104. /* Null out execute_data early, to prevent double frees if GC runs while we're
  105. * already cleaning up execute_data. */
  106. generator->execute_data = NULL;
  107. if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) {
  108. zend_clean_and_cache_symbol_table(execute_data->symbol_table);
  109. }
  110. /* always free the CV's, in the symtable are only not-free'd IS_INDIRECT's */
  111. zend_free_compiled_variables(execute_data);
  112. if (EX_CALL_INFO() & ZEND_CALL_RELEASE_THIS) {
  113. OBJ_RELEASE(Z_OBJ(execute_data->This));
  114. }
  115. /* A fatal error / die occurred during the generator execution.
  116. * Trying to clean up the stack may not be safe in this case. */
  117. if (UNEXPECTED(CG(unclean_shutdown))) {
  118. generator->execute_data = NULL;
  119. return;
  120. }
  121. zend_vm_stack_free_extra_args(execute_data);
  122. /* Some cleanups are only necessary if the generator was closed
  123. * before it could finish execution (reach a return statement). */
  124. if (UNEXPECTED(!finished_execution)) {
  125. zend_generator_cleanup_unfinished_execution(generator, execute_data, 0);
  126. }
  127. /* Free closure object */
  128. if (EX_CALL_INFO() & ZEND_CALL_CLOSURE) {
  129. OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
  130. }
  131. /* Free GC buffer. GC for closed generators doesn't need an allocated buffer */
  132. if (generator->gc_buffer) {
  133. efree(generator->gc_buffer);
  134. generator->gc_buffer = NULL;
  135. }
  136. efree(execute_data);
  137. }
  138. }
  139. /* }}} */
  140. static zend_generator *zend_generator_get_child(zend_generator_node *node, zend_generator *leaf);
  141. static void zend_generator_dtor_storage(zend_object *object) /* {{{ */
  142. {
  143. zend_generator *generator = (zend_generator*) object;
  144. zend_execute_data *ex = generator->execute_data;
  145. uint32_t op_num, finally_op_num, finally_op_end;
  146. int i;
  147. /* leave yield from mode to properly allow finally execution */
  148. if (UNEXPECTED(Z_TYPE(generator->values) != IS_UNDEF)) {
  149. zval_ptr_dtor(&generator->values);
  150. ZVAL_UNDEF(&generator->values);
  151. }
  152. if (EXPECTED(generator->node.children == 0)) {
  153. zend_generator *root = generator->node.ptr.root, *next;
  154. while (UNEXPECTED(root != generator)) {
  155. next = zend_generator_get_child(&root->node, generator);
  156. generator->node.ptr.root = next;
  157. next->node.parent = NULL;
  158. OBJ_RELEASE(&root->std);
  159. root = next;
  160. }
  161. }
  162. if (EXPECTED(!ex) || EXPECTED(!(ex->func->op_array.fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK))
  163. || CG(unclean_shutdown)) {
  164. return;
  165. }
  166. /* -1 required because we want the last run opcode, not the
  167. * next to-be-run one. */
  168. op_num = ex->opline - ex->func->op_array.opcodes - 1;
  169. /* Find next finally block */
  170. finally_op_num = 0;
  171. finally_op_end = 0;
  172. for (i = 0; i < ex->func->op_array.last_try_catch; i++) {
  173. zend_try_catch_element *try_catch = &ex->func->op_array.try_catch_array[i];
  174. if (op_num < try_catch->try_op) {
  175. break;
  176. }
  177. if (op_num < try_catch->finally_op) {
  178. finally_op_num = try_catch->finally_op;
  179. finally_op_end = try_catch->finally_end;
  180. }
  181. }
  182. /* If a finally block was found we jump directly to it and
  183. * resume the generator. */
  184. if (finally_op_num) {
  185. zval *fast_call;
  186. zend_generator_cleanup_unfinished_execution(generator, ex, finally_op_num);
  187. fast_call = ZEND_CALL_VAR(ex, ex->func->op_array.opcodes[finally_op_end].op1.var);
  188. Z_OBJ_P(fast_call) = EG(exception);
  189. EG(exception) = NULL;
  190. Z_OPLINE_NUM_P(fast_call) = (uint32_t)-1;
  191. ex->opline = &ex->func->op_array.opcodes[finally_op_num];
  192. generator->flags |= ZEND_GENERATOR_FORCED_CLOSE;
  193. zend_generator_resume(generator);
  194. }
  195. }
  196. /* }}} */
  197. static void zend_generator_free_storage(zend_object *object) /* {{{ */
  198. {
  199. zend_generator *generator = (zend_generator*) object;
  200. zend_generator_close(generator, 0);
  201. /* we can't immediately free them in zend_generator_close() else yield from won't be able to fetch it */
  202. zval_ptr_dtor(&generator->value);
  203. zval_ptr_dtor(&generator->key);
  204. if (EXPECTED(!Z_ISUNDEF(generator->retval))) {
  205. zval_ptr_dtor(&generator->retval);
  206. }
  207. if (UNEXPECTED(generator->node.children > 1)) {
  208. zend_hash_destroy(generator->node.child.ht);
  209. efree(generator->node.child.ht);
  210. }
  211. zend_object_std_dtor(&generator->std);
  212. }
  213. /* }}} */
  214. static uint32_t calc_gc_buffer_size(zend_generator *generator) /* {{{ */
  215. {
  216. uint32_t size = 4; /* value, key, retval, values */
  217. if (generator->execute_data) {
  218. zend_execute_data *execute_data = generator->execute_data;
  219. zend_op_array *op_array = &EX(func)->op_array;
  220. /* Compiled variables */
  221. if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) {
  222. size += op_array->last_var;
  223. }
  224. /* Extra args */
  225. if (EX_CALL_INFO() & ZEND_CALL_FREE_EXTRA_ARGS) {
  226. size += EX_NUM_ARGS() - op_array->num_args;
  227. }
  228. size += (EX_CALL_INFO() & ZEND_CALL_RELEASE_THIS) != 0; /* $this */
  229. size += (EX_CALL_INFO() & ZEND_CALL_CLOSURE) != 0; /* Closure object */
  230. /* Live vars */
  231. if (execute_data->opline != op_array->opcodes) {
  232. /* -1 required because we want the last run opcode, not the next to-be-run one. */
  233. uint32_t i, op_num = execute_data->opline - op_array->opcodes - 1;
  234. for (i = 0; i < op_array->last_live_range; i++) {
  235. const zend_live_range *range = &op_array->live_range[i];
  236. if (range->start > op_num) {
  237. /* Further ranges will not be relevant... */
  238. break;
  239. } else if (op_num < range->end) {
  240. /* LIVE_ROPE and LIVE_SILENCE not relevant for GC */
  241. uint32_t kind = range->var & ZEND_LIVE_MASK;
  242. if (kind == ZEND_LIVE_TMPVAR || kind == ZEND_LIVE_LOOP) {
  243. size++;
  244. }
  245. }
  246. }
  247. }
  248. /* Yield from root references */
  249. if (generator->node.children == 0) {
  250. zend_generator *root = generator->node.ptr.root;
  251. while (root != generator) {
  252. root = zend_generator_get_child(&root->node, generator);
  253. size++;
  254. }
  255. }
  256. }
  257. return size;
  258. }
  259. /* }}} */
  260. static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* {{{ */
  261. {
  262. zend_generator *generator = (zend_generator*) Z_OBJ_P(object);
  263. zend_execute_data *execute_data = generator->execute_data;
  264. zend_op_array *op_array;
  265. zval *gc_buffer;
  266. uint32_t gc_buffer_size;
  267. if (!execute_data) {
  268. /* If the generator has been closed, it can only hold on to three values: The value, key
  269. * and retval. These three zvals are stored sequentially starting at &generator->value. */
  270. *table = &generator->value;
  271. *n = 3;
  272. return NULL;
  273. }
  274. op_array = &EX(func)->op_array;
  275. gc_buffer_size = calc_gc_buffer_size(generator);
  276. if (generator->gc_buffer_size < gc_buffer_size) {
  277. generator->gc_buffer = safe_erealloc(generator->gc_buffer, sizeof(zval), gc_buffer_size, 0);
  278. generator->gc_buffer_size = gc_buffer_size;
  279. }
  280. *n = gc_buffer_size;
  281. *table = gc_buffer = generator->gc_buffer;
  282. ZVAL_COPY_VALUE(gc_buffer++, &generator->value);
  283. ZVAL_COPY_VALUE(gc_buffer++, &generator->key);
  284. ZVAL_COPY_VALUE(gc_buffer++, &generator->retval);
  285. ZVAL_COPY_VALUE(gc_buffer++, &generator->values);
  286. if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) {
  287. uint32_t i, num_cvs = EX(func)->op_array.last_var;
  288. for (i = 0; i < num_cvs; i++) {
  289. ZVAL_COPY_VALUE(gc_buffer++, EX_VAR_NUM(i));
  290. }
  291. }
  292. if (EX_CALL_INFO() & ZEND_CALL_FREE_EXTRA_ARGS) {
  293. zval *zv = EX_VAR_NUM(op_array->last_var + op_array->T);
  294. zval *end = zv + (EX_NUM_ARGS() - op_array->num_args);
  295. while (zv != end) {
  296. ZVAL_COPY_VALUE(gc_buffer++, zv++);
  297. }
  298. }
  299. if (EX_CALL_INFO() & ZEND_CALL_RELEASE_THIS) {
  300. ZVAL_OBJ(gc_buffer++, Z_OBJ(execute_data->This));
  301. }
  302. if (EX_CALL_INFO() & ZEND_CALL_CLOSURE) {
  303. ZVAL_OBJ(gc_buffer++, ZEND_CLOSURE_OBJECT(EX(func)));
  304. }
  305. if (execute_data->opline != op_array->opcodes) {
  306. uint32_t i, op_num = execute_data->opline - op_array->opcodes - 1;
  307. for (i = 0; i < op_array->last_live_range; i++) {
  308. const zend_live_range *range = &op_array->live_range[i];
  309. if (range->start > op_num) {
  310. break;
  311. } else if (op_num < range->end) {
  312. uint32_t kind = range->var & ZEND_LIVE_MASK;
  313. uint32_t var_num = range->var & ~ZEND_LIVE_MASK;
  314. zval *var = EX_VAR(var_num);
  315. if (kind == ZEND_LIVE_TMPVAR || kind == ZEND_LIVE_LOOP) {
  316. ZVAL_COPY_VALUE(gc_buffer++, var);
  317. }
  318. }
  319. }
  320. }
  321. if (generator->node.children == 0) {
  322. zend_generator *root = generator->node.ptr.root;
  323. while (root != generator) {
  324. ZVAL_OBJ(gc_buffer++, &root->std);
  325. root = zend_generator_get_child(&root->node, generator);
  326. }
  327. }
  328. if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) {
  329. return execute_data->symbol_table;
  330. } else {
  331. return NULL;
  332. }
  333. }
  334. /* }}} */
  335. static zend_object *zend_generator_create(zend_class_entry *class_type) /* {{{ */
  336. {
  337. zend_generator *generator;
  338. generator = emalloc(sizeof(zend_generator));
  339. memset(generator, 0, sizeof(zend_generator));
  340. /* The key will be incremented on first use, so it'll start at 0 */
  341. generator->largest_used_integer_key = -1;
  342. ZVAL_UNDEF(&generator->retval);
  343. ZVAL_UNDEF(&generator->values);
  344. /* By default we have a tree of only one node */
  345. generator->node.parent = NULL;
  346. generator->node.children = 0;
  347. generator->node.ptr.root = generator;
  348. zend_object_std_init(&generator->std, class_type);
  349. generator->std.handlers = &zend_generator_handlers;
  350. return (zend_object*)generator;
  351. }
  352. /* }}} */
  353. static ZEND_COLD zend_function *zend_generator_get_constructor(zend_object *object) /* {{{ */
  354. {
  355. zend_throw_error(NULL, "The \"Generator\" class is reserved for internal use and cannot be manually instantiated");
  356. return NULL;
  357. }
  358. /* }}} */
  359. ZEND_API zend_execute_data *zend_generator_check_placeholder_frame(zend_execute_data *ptr)
  360. {
  361. if (!ptr->func && Z_TYPE(ptr->This) == IS_OBJECT) {
  362. if (Z_OBJCE(ptr->This) == zend_ce_generator) {
  363. zend_generator *generator = (zend_generator *) Z_OBJ(ptr->This);
  364. zend_generator *root = (generator->node.children < 1 ? generator : generator->node.ptr.leaf)->node.ptr.root;
  365. zend_execute_data *prev = ptr->prev_execute_data;
  366. if (generator->node.parent != root) {
  367. do {
  368. generator->execute_data->prev_execute_data = prev;
  369. prev = generator->execute_data;
  370. generator = generator->node.parent;
  371. } while (generator->node.parent != root);
  372. }
  373. generator->execute_data->prev_execute_data = prev;
  374. ptr = generator->execute_data;
  375. }
  376. }
  377. return ptr;
  378. }
  379. static void zend_generator_throw_exception(zend_generator *generator, zval *exception)
  380. {
  381. zend_execute_data *original_execute_data = EG(current_execute_data);
  382. /* if we don't stop an array/iterator yield from, the exception will only reach the generator after the values were all iterated over */
  383. if (UNEXPECTED(Z_TYPE(generator->values) != IS_UNDEF)) {
  384. zval_ptr_dtor(&generator->values);
  385. ZVAL_UNDEF(&generator->values);
  386. }
  387. /* Throw the exception in the context of the generator. Decrementing the opline
  388. * to pretend the exception happened during the YIELD opcode. */
  389. EG(current_execute_data) = generator->execute_data;
  390. generator->execute_data->opline--;
  391. if (exception) {
  392. zend_throw_exception_object(exception);
  393. } else {
  394. zend_rethrow_exception(EG(current_execute_data));
  395. }
  396. generator->execute_data->opline++;
  397. EG(current_execute_data) = original_execute_data;
  398. }
  399. static zend_generator *zend_generator_get_child(zend_generator_node *node, zend_generator *leaf)
  400. {
  401. if (node->children == 0) {
  402. return NULL;
  403. } else if (node->children == 1) {
  404. return node->child.single.child;
  405. } else {
  406. return zend_hash_index_find_ptr(node->child.ht, (zend_ulong) leaf);
  407. }
  408. }
  409. static zend_generator_node *zend_generator_search_multi_children_node(zend_generator_node *node)
  410. {
  411. while (node->children == 1) {
  412. node = &node->child.single.child->node;
  413. }
  414. return node->children > 1 ? node : NULL;
  415. }
  416. static void zend_generator_add_single_child(zend_generator_node *node, zend_generator *child, zend_generator *leaf)
  417. {
  418. if (node->children == 0) {
  419. node->child.single.leaf = leaf;
  420. node->child.single.child = child;
  421. } else {
  422. if (node->children == 1) {
  423. HashTable *ht = emalloc(sizeof(HashTable));
  424. zend_hash_init(ht, 0, NULL, NULL, 0);
  425. zend_hash_index_add_ptr(ht,
  426. (zend_ulong) node->child.single.leaf, node->child.single.child);
  427. node->child.ht = ht;
  428. }
  429. zend_hash_index_add_ptr(node->child.ht, (zend_ulong) leaf, child);
  430. }
  431. node->children++;
  432. }
  433. static void zend_generator_merge_child_nodes(zend_generator_node *dest, zend_generator_node *src, zend_generator *child)
  434. {
  435. zend_ulong leaf;
  436. ZEND_ASSERT(src->children > 1);
  437. ZEND_HASH_FOREACH_NUM_KEY(src->child.ht, leaf) {
  438. zend_generator_add_single_child(dest, child, (zend_generator *) leaf);
  439. } ZEND_HASH_FOREACH_END();
  440. }
  441. /* Pay attention so that the root of each subtree of the Generators tree is referenced
  442. * once per leaf */
  443. static void zend_generator_add_child(zend_generator *generator, zend_generator *child)
  444. {
  445. zend_generator *leaf = child->node.children ? child->node.ptr.leaf : child;
  446. zend_generator_node *multi_children_node;
  447. zend_bool was_leaf = generator->node.children == 0;
  448. if (was_leaf) {
  449. zend_generator *next = generator->node.parent;
  450. leaf->node.ptr.root = generator->node.ptr.root;
  451. 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 */
  452. generator->node.ptr.leaf = leaf;
  453. while (next) {
  454. if (next->node.children > 1) {
  455. zend_generator *child = zend_hash_index_find_ptr(next->node.child.ht, (zend_ulong) generator);
  456. zend_hash_index_del(next->node.child.ht, (zend_ulong) generator);
  457. zend_hash_index_add_ptr(next->node.child.ht, (zend_ulong) leaf, child);
  458. }
  459. next->node.ptr.leaf = leaf;
  460. next = next->node.parent;
  461. }
  462. } else if (generator->node.children == 1) {
  463. multi_children_node = zend_generator_search_multi_children_node(&generator->node);
  464. if (multi_children_node) {
  465. generator->node.children = 0;
  466. zend_generator_merge_child_nodes(&generator->node, multi_children_node, generator->node.child.single.child);
  467. }
  468. }
  469. if (!was_leaf) {
  470. multi_children_node = zend_generator_search_multi_children_node(&child->node);
  471. } else {
  472. multi_children_node = (zend_generator_node *) 0x1;
  473. }
  474. {
  475. zend_generator *parent = generator->node.parent, *cur = generator;
  476. if (multi_children_node > (zend_generator_node *) 0x1) {
  477. zend_generator_merge_child_nodes(&generator->node, multi_children_node, child);
  478. } else {
  479. zend_generator_add_single_child(&generator->node, child, leaf);
  480. }
  481. while (parent) {
  482. if (parent->node.children > 1) {
  483. if (multi_children_node == (zend_generator_node *) 0x1) {
  484. multi_children_node = zend_generator_search_multi_children_node(&child->node);
  485. }
  486. if (multi_children_node) {
  487. zend_generator_merge_child_nodes(&parent->node, multi_children_node, cur);
  488. } else {
  489. zend_generator_add_single_child(&parent->node, cur, leaf);
  490. }
  491. }
  492. cur = parent;
  493. parent = parent->node.parent;
  494. }
  495. }
  496. }
  497. void zend_generator_yield_from(zend_generator *generator, zend_generator *from)
  498. {
  499. zend_generator_add_child(from, generator);
  500. generator->node.parent = from;
  501. zend_generator_get_current(generator);
  502. GC_DELREF(&from->std);
  503. }
  504. ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator, zend_generator *leaf)
  505. {
  506. zend_generator *old_root, *root = leaf->node.ptr.root;
  507. /* generator at the root had stopped */
  508. if (root != generator) {
  509. old_root = root;
  510. root = zend_generator_get_child(&root->node, leaf);
  511. } else {
  512. old_root = NULL;
  513. }
  514. while (!root->execute_data && root != generator) {
  515. OBJ_RELEASE(&old_root->std);
  516. old_root = root;
  517. root = zend_generator_get_child(&root->node, leaf);
  518. }
  519. if (root->node.parent) {
  520. if (root->node.parent->execute_data == NULL) {
  521. if (EXPECTED(EG(exception) == NULL)) {
  522. zend_op *yield_from = (zend_op *) root->execute_data->opline - 1;
  523. if (yield_from->opcode == ZEND_YIELD_FROM) {
  524. if (Z_ISUNDEF(root->node.parent->retval)) {
  525. /* Throw the exception in the context of the generator */
  526. zend_execute_data *original_execute_data = EG(current_execute_data);
  527. EG(current_execute_data) = root->execute_data;
  528. if (root == generator) {
  529. root->execute_data->prev_execute_data = original_execute_data;
  530. } else {
  531. root->execute_data->prev_execute_data = &generator->execute_fake;
  532. generator->execute_fake.prev_execute_data = original_execute_data;
  533. }
  534. root->execute_data->opline--; /* ZEND_YIELD(_FROM) already advance, so decrement opline to throw from correct place */
  535. zend_throw_exception(zend_ce_ClosedGeneratorException, "Generator yielded from aborted, no return value available", 0);
  536. EG(current_execute_data) = original_execute_data;
  537. if (!((old_root ? old_root : generator)->flags & ZEND_GENERATOR_CURRENTLY_RUNNING)) {
  538. leaf->node.ptr.root = root;
  539. root->node.parent = NULL;
  540. if (old_root) {
  541. OBJ_RELEASE(&old_root->std);
  542. }
  543. zend_generator_resume(leaf);
  544. return leaf->node.ptr.root; /* this may be updated during zend_generator_resume! */
  545. }
  546. } else {
  547. zval_ptr_dtor(&root->value);
  548. ZVAL_COPY(&root->value, &root->node.parent->value);
  549. ZVAL_COPY(ZEND_CALL_VAR(root->execute_data, yield_from->result.var), &root->node.parent->retval);
  550. }
  551. }
  552. }
  553. root->node.parent = NULL;
  554. } else {
  555. do {
  556. root = root->node.parent;
  557. GC_ADDREF(&root->std);
  558. } while (root->node.parent);
  559. }
  560. }
  561. leaf->node.ptr.root = root;
  562. if (old_root) {
  563. OBJ_RELEASE(&old_root->std);
  564. }
  565. return root;
  566. }
  567. static int zend_generator_get_next_delegated_value(zend_generator *generator) /* {{{ */
  568. {
  569. zval *value;
  570. if (Z_TYPE(generator->values) == IS_ARRAY) {
  571. HashTable *ht = Z_ARR(generator->values);
  572. HashPosition pos = Z_FE_POS(generator->values);
  573. Bucket *p;
  574. do {
  575. if (UNEXPECTED(pos >= ht->nNumUsed)) {
  576. /* Reached end of array */
  577. goto failure;
  578. }
  579. p = &ht->arData[pos];
  580. value = &p->val;
  581. if (Z_TYPE_P(value) == IS_INDIRECT) {
  582. value = Z_INDIRECT_P(value);
  583. }
  584. pos++;
  585. } while (Z_ISUNDEF_P(value));
  586. zval_ptr_dtor(&generator->value);
  587. ZVAL_COPY(&generator->value, value);
  588. zval_ptr_dtor(&generator->key);
  589. if (p->key) {
  590. ZVAL_STR_COPY(&generator->key, p->key);
  591. } else {
  592. ZVAL_LONG(&generator->key, p->h);
  593. }
  594. Z_FE_POS(generator->values) = pos;
  595. } else {
  596. zend_object_iterator *iter = (zend_object_iterator *) Z_OBJ(generator->values);
  597. if (iter->index++ > 0) {
  598. iter->funcs->move_forward(iter);
  599. if (UNEXPECTED(EG(exception) != NULL)) {
  600. goto exception;
  601. }
  602. }
  603. if (iter->funcs->valid(iter) == FAILURE) {
  604. if (UNEXPECTED(EG(exception) != NULL)) {
  605. goto exception;
  606. }
  607. /* reached end of iteration */
  608. goto failure;
  609. }
  610. value = iter->funcs->get_current_data(iter);
  611. if (UNEXPECTED(EG(exception) != NULL)) {
  612. goto exception;
  613. } else if (UNEXPECTED(!value)) {
  614. goto failure;
  615. }
  616. zval_ptr_dtor(&generator->value);
  617. ZVAL_COPY(&generator->value, value);
  618. zval_ptr_dtor(&generator->key);
  619. if (iter->funcs->get_current_key) {
  620. iter->funcs->get_current_key(iter, &generator->key);
  621. if (UNEXPECTED(EG(exception) != NULL)) {
  622. ZVAL_UNDEF(&generator->key);
  623. goto exception;
  624. }
  625. } else {
  626. ZVAL_LONG(&generator->key, iter->index);
  627. }
  628. }
  629. return SUCCESS;
  630. exception:
  631. zend_generator_throw_exception(generator, NULL);
  632. failure:
  633. zval_ptr_dtor(&generator->values);
  634. ZVAL_UNDEF(&generator->values);
  635. return FAILURE;
  636. }
  637. /* }}} */
  638. ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */
  639. {
  640. zend_generator *generator = zend_generator_get_current(orig_generator);
  641. /* The generator is already closed, thus can't resume */
  642. if (UNEXPECTED(!generator->execute_data)) {
  643. return;
  644. }
  645. try_again:
  646. if (generator->flags & ZEND_GENERATOR_CURRENTLY_RUNNING) {
  647. zend_throw_error(NULL, "Cannot resume an already running generator");
  648. return;
  649. }
  650. if (UNEXPECTED((orig_generator->flags & ZEND_GENERATOR_DO_INIT) != 0 && !Z_ISUNDEF(generator->value))) {
  651. /* We must not advance Generator if we yield from a Generator being currently run */
  652. return;
  653. }
  654. if (UNEXPECTED(!Z_ISUNDEF(generator->values))) {
  655. if (EXPECTED(zend_generator_get_next_delegated_value(generator) == SUCCESS)) {
  656. return;
  657. }
  658. /* If there are no more deletegated values, resume the generator
  659. * after the "yield from" expression. */
  660. }
  661. /* Drop the AT_FIRST_YIELD flag */
  662. orig_generator->flags &= ~ZEND_GENERATOR_AT_FIRST_YIELD;
  663. {
  664. /* Backup executor globals */
  665. zend_execute_data *original_execute_data = EG(current_execute_data);
  666. /* Set executor globals */
  667. EG(current_execute_data) = generator->execute_data;
  668. /* We want the backtrace to look as if the generator function was
  669. * called from whatever method we are current running (e.g. next()).
  670. * So we have to link generator call frame with caller call frame. */
  671. if (generator == orig_generator) {
  672. generator->execute_data->prev_execute_data = original_execute_data;
  673. } else {
  674. /* We need some execute_data placeholder in stacktrace to be replaced
  675. * by the real stack trace when needed */
  676. generator->execute_data->prev_execute_data = &orig_generator->execute_fake;
  677. orig_generator->execute_fake.prev_execute_data = original_execute_data;
  678. }
  679. if (UNEXPECTED(generator->frozen_call_stack)) {
  680. /* Restore frozen call-stack */
  681. zend_generator_restore_call_stack(generator);
  682. }
  683. /* Resume execution */
  684. generator->flags |= ZEND_GENERATOR_CURRENTLY_RUNNING;
  685. zend_execute_ex(generator->execute_data);
  686. generator->flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING;
  687. generator->frozen_call_stack = NULL;
  688. if (EXPECTED(generator->execute_data) &&
  689. UNEXPECTED(generator->execute_data->call)) {
  690. /* Frize call-stack */
  691. generator->frozen_call_stack = zend_generator_freeze_call_stack(generator->execute_data);
  692. }
  693. /* Restore executor globals */
  694. EG(current_execute_data) = original_execute_data;
  695. /* If an exception was thrown in the generator we have to internally
  696. * rethrow it in the parent scope.
  697. * In case we did yield from, the Exception must be rethrown into
  698. * its calling frame (see above in if (check_yield_from). */
  699. if (UNEXPECTED(EG(exception) != NULL)) {
  700. if (generator == orig_generator) {
  701. zend_generator_close(generator, 0);
  702. if (!EG(current_execute_data)) {
  703. zend_throw_exception_internal(NULL);
  704. } else if (EG(current_execute_data)->func &&
  705. ZEND_USER_CODE(EG(current_execute_data)->func->common.type)) {
  706. zend_rethrow_exception(EG(current_execute_data));
  707. }
  708. } else {
  709. generator = zend_generator_get_current(orig_generator);
  710. zend_generator_throw_exception(generator, NULL);
  711. goto try_again;
  712. }
  713. }
  714. /* yield from was used, try another resume. */
  715. if (UNEXPECTED((generator != orig_generator && !Z_ISUNDEF(generator->retval)) || (generator->execute_data && (generator->execute_data->opline - 1)->opcode == ZEND_YIELD_FROM))) {
  716. generator = zend_generator_get_current(orig_generator);
  717. goto try_again;
  718. }
  719. }
  720. }
  721. /* }}} */
  722. static inline void zend_generator_ensure_initialized(zend_generator *generator) /* {{{ */
  723. {
  724. if (UNEXPECTED(Z_TYPE(generator->value) == IS_UNDEF) && EXPECTED(generator->execute_data) && EXPECTED(generator->node.parent == NULL)) {
  725. generator->flags |= ZEND_GENERATOR_DO_INIT;
  726. zend_generator_resume(generator);
  727. generator->flags &= ~ZEND_GENERATOR_DO_INIT;
  728. generator->flags |= ZEND_GENERATOR_AT_FIRST_YIELD;
  729. }
  730. }
  731. /* }}} */
  732. static inline void zend_generator_rewind(zend_generator *generator) /* {{{ */
  733. {
  734. zend_generator_ensure_initialized(generator);
  735. if (!(generator->flags & ZEND_GENERATOR_AT_FIRST_YIELD)) {
  736. zend_throw_exception(NULL, "Cannot rewind a generator that was already run", 0);
  737. }
  738. }
  739. /* }}} */
  740. /* {{{ proto void Generator::rewind()
  741. * Rewind the generator */
  742. ZEND_METHOD(Generator, rewind)
  743. {
  744. zend_generator *generator;
  745. if (zend_parse_parameters_none() == FAILURE) {
  746. return;
  747. }
  748. generator = (zend_generator *) Z_OBJ_P(getThis());
  749. zend_generator_rewind(generator);
  750. }
  751. /* }}} */
  752. /* {{{ proto bool Generator::valid()
  753. * Check whether the generator is valid */
  754. ZEND_METHOD(Generator, valid)
  755. {
  756. zend_generator *generator;
  757. if (zend_parse_parameters_none() == FAILURE) {
  758. return;
  759. }
  760. generator = (zend_generator *) Z_OBJ_P(getThis());
  761. zend_generator_ensure_initialized(generator);
  762. zend_generator_get_current(generator);
  763. RETURN_BOOL(EXPECTED(generator->execute_data != NULL));
  764. }
  765. /* }}} */
  766. /* {{{ proto mixed Generator::current()
  767. * Get the current value */
  768. ZEND_METHOD(Generator, current)
  769. {
  770. zend_generator *generator, *root;
  771. if (zend_parse_parameters_none() == FAILURE) {
  772. return;
  773. }
  774. generator = (zend_generator *) Z_OBJ_P(getThis());
  775. zend_generator_ensure_initialized(generator);
  776. root = zend_generator_get_current(generator);
  777. if (EXPECTED(generator->execute_data != NULL && Z_TYPE(root->value) != IS_UNDEF)) {
  778. zval *value = &root->value;
  779. ZVAL_COPY_DEREF(return_value, value);
  780. }
  781. }
  782. /* }}} */
  783. /* {{{ proto mixed Generator::key()
  784. * Get the current key */
  785. ZEND_METHOD(Generator, key)
  786. {
  787. zend_generator *generator, *root;
  788. if (zend_parse_parameters_none() == FAILURE) {
  789. return;
  790. }
  791. generator = (zend_generator *) Z_OBJ_P(getThis());
  792. zend_generator_ensure_initialized(generator);
  793. root = zend_generator_get_current(generator);
  794. if (EXPECTED(generator->execute_data != NULL && Z_TYPE(root->key) != IS_UNDEF)) {
  795. zval *key = &root->key;
  796. ZVAL_COPY_DEREF(return_value, key);
  797. }
  798. }
  799. /* }}} */
  800. /* {{{ proto void Generator::next()
  801. * Advances the generator */
  802. ZEND_METHOD(Generator, next)
  803. {
  804. zend_generator *generator;
  805. if (zend_parse_parameters_none() == FAILURE) {
  806. return;
  807. }
  808. generator = (zend_generator *) Z_OBJ_P(getThis());
  809. zend_generator_ensure_initialized(generator);
  810. zend_generator_resume(generator);
  811. }
  812. /* }}} */
  813. /* {{{ proto mixed Generator::send(mixed value)
  814. * Sends a value to the generator */
  815. ZEND_METHOD(Generator, send)
  816. {
  817. zval *value;
  818. zend_generator *generator, *root;
  819. ZEND_PARSE_PARAMETERS_START(1, 1)
  820. Z_PARAM_ZVAL(value)
  821. ZEND_PARSE_PARAMETERS_END();
  822. generator = (zend_generator *) Z_OBJ_P(getThis());
  823. zend_generator_ensure_initialized(generator);
  824. /* The generator is already closed, thus can't send anything */
  825. if (UNEXPECTED(!generator->execute_data)) {
  826. return;
  827. }
  828. root = zend_generator_get_current(generator);
  829. /* Put sent value in the target VAR slot, if it is used */
  830. if (root->send_target) {
  831. ZVAL_COPY(root->send_target, value);
  832. }
  833. zend_generator_resume(generator);
  834. root = zend_generator_get_current(generator);
  835. if (EXPECTED(generator->execute_data)) {
  836. zval *value = &root->value;
  837. ZVAL_COPY_DEREF(return_value, value);
  838. }
  839. }
  840. /* }}} */
  841. /* {{{ proto mixed Generator::throw(Exception exception)
  842. * Throws an exception into the generator */
  843. ZEND_METHOD(Generator, throw)
  844. {
  845. zval *exception;
  846. zend_generator *generator;
  847. ZEND_PARSE_PARAMETERS_START(1, 1)
  848. Z_PARAM_ZVAL(exception)
  849. ZEND_PARSE_PARAMETERS_END();
  850. Z_TRY_ADDREF_P(exception);
  851. generator = (zend_generator *) Z_OBJ_P(getThis());
  852. zend_generator_ensure_initialized(generator);
  853. if (generator->execute_data) {
  854. zend_generator *root = zend_generator_get_current(generator);
  855. zend_generator_throw_exception(root, exception);
  856. zend_generator_resume(generator);
  857. root = zend_generator_get_current(generator);
  858. if (generator->execute_data) {
  859. zval *value = &root->value;
  860. ZVAL_COPY_DEREF(return_value, value);
  861. }
  862. } else {
  863. /* If the generator is already closed throw the exception in the
  864. * current context */
  865. zend_throw_exception_object(exception);
  866. }
  867. }
  868. /* }}} */
  869. /* {{{ proto mixed Generator::getReturn()
  870. * Retrieves the return value of the generator */
  871. ZEND_METHOD(Generator, getReturn)
  872. {
  873. zend_generator *generator;
  874. if (zend_parse_parameters_none() == FAILURE) {
  875. return;
  876. }
  877. generator = (zend_generator *) Z_OBJ_P(getThis());
  878. zend_generator_ensure_initialized(generator);
  879. if (UNEXPECTED(EG(exception))) {
  880. return;
  881. }
  882. if (Z_ISUNDEF(generator->retval)) {
  883. /* Generator hasn't returned yet -> error! */
  884. zend_throw_exception(NULL,
  885. "Cannot get return value of a generator that hasn't returned", 0);
  886. return;
  887. }
  888. ZVAL_COPY(return_value, &generator->retval);
  889. }
  890. /* }}} */
  891. /* {{{ proto Generator::__wakeup()
  892. * Throws an Exception as generators can't be serialized */
  893. ZEND_METHOD(Generator, __wakeup)
  894. {
  895. /* Just specifying the zend_class_unserialize_deny handler is not enough,
  896. * because it is only invoked for C unserialization. For O the error has
  897. * to be thrown in __wakeup. */
  898. if (zend_parse_parameters_none() == FAILURE) {
  899. return;
  900. }
  901. zend_throw_exception(NULL, "Unserialization of 'Generator' is not allowed", 0);
  902. }
  903. /* }}} */
  904. /* get_iterator implementation */
  905. static void zend_generator_iterator_dtor(zend_object_iterator *iterator) /* {{{ */
  906. {
  907. zend_generator *generator = (zend_generator*)Z_OBJ(iterator->data);
  908. generator->iterator = NULL;
  909. zval_ptr_dtor(&iterator->data);
  910. }
  911. /* }}} */
  912. static int zend_generator_iterator_valid(zend_object_iterator *iterator) /* {{{ */
  913. {
  914. zend_generator *generator = (zend_generator*)Z_OBJ(iterator->data);
  915. zend_generator_ensure_initialized(generator);
  916. zend_generator_get_current(generator);
  917. return generator->execute_data ? SUCCESS : FAILURE;
  918. }
  919. /* }}} */
  920. static zval *zend_generator_iterator_get_data(zend_object_iterator *iterator) /* {{{ */
  921. {
  922. zend_generator *generator = (zend_generator*)Z_OBJ(iterator->data), *root;
  923. zend_generator_ensure_initialized(generator);
  924. root = zend_generator_get_current(generator);
  925. return &root->value;
  926. }
  927. /* }}} */
  928. static void zend_generator_iterator_get_key(zend_object_iterator *iterator, zval *key) /* {{{ */
  929. {
  930. zend_generator *generator = (zend_generator*)Z_OBJ(iterator->data), *root;
  931. zend_generator_ensure_initialized(generator);
  932. root = zend_generator_get_current(generator);
  933. if (EXPECTED(Z_TYPE(root->key) != IS_UNDEF)) {
  934. zval *zv = &root->key;
  935. ZVAL_COPY_DEREF(key, zv);
  936. } else {
  937. ZVAL_NULL(key);
  938. }
  939. }
  940. /* }}} */
  941. static void zend_generator_iterator_move_forward(zend_object_iterator *iterator) /* {{{ */
  942. {
  943. zend_generator *generator = (zend_generator*)Z_OBJ(iterator->data);
  944. zend_generator_ensure_initialized(generator);
  945. zend_generator_resume(generator);
  946. }
  947. /* }}} */
  948. static void zend_generator_iterator_rewind(zend_object_iterator *iterator) /* {{{ */
  949. {
  950. zend_generator *generator = (zend_generator*)Z_OBJ(iterator->data);
  951. zend_generator_rewind(generator);
  952. }
  953. /* }}} */
  954. static const zend_object_iterator_funcs zend_generator_iterator_functions = {
  955. zend_generator_iterator_dtor,
  956. zend_generator_iterator_valid,
  957. zend_generator_iterator_get_data,
  958. zend_generator_iterator_get_key,
  959. zend_generator_iterator_move_forward,
  960. zend_generator_iterator_rewind,
  961. NULL
  962. };
  963. zend_object_iterator *zend_generator_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
  964. {
  965. zend_object_iterator *iterator;
  966. zend_generator *generator = (zend_generator*)Z_OBJ_P(object);
  967. if (!generator->execute_data) {
  968. zend_throw_exception(NULL, "Cannot traverse an already closed generator", 0);
  969. return NULL;
  970. }
  971. if (UNEXPECTED(by_ref) && !(generator->execute_data->func->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
  972. zend_throw_exception(NULL, "You can only iterate a generator by-reference if it declared that it yields by-reference", 0);
  973. return NULL;
  974. }
  975. iterator = generator->iterator = emalloc(sizeof(zend_object_iterator));
  976. zend_iterator_init(iterator);
  977. iterator->funcs = &zend_generator_iterator_functions;
  978. ZVAL_COPY(&iterator->data, object);
  979. return iterator;
  980. }
  981. /* }}} */
  982. ZEND_BEGIN_ARG_INFO(arginfo_generator_void, 0)
  983. ZEND_END_ARG_INFO()
  984. ZEND_BEGIN_ARG_INFO_EX(arginfo_generator_send, 0, 0, 1)
  985. ZEND_ARG_INFO(0, value)
  986. ZEND_END_ARG_INFO()
  987. ZEND_BEGIN_ARG_INFO_EX(arginfo_generator_throw, 0, 0, 1)
  988. ZEND_ARG_INFO(0, exception)
  989. ZEND_END_ARG_INFO()
  990. static const zend_function_entry generator_functions[] = {
  991. ZEND_ME(Generator, rewind, arginfo_generator_void, ZEND_ACC_PUBLIC)
  992. ZEND_ME(Generator, valid, arginfo_generator_void, ZEND_ACC_PUBLIC)
  993. ZEND_ME(Generator, current, arginfo_generator_void, ZEND_ACC_PUBLIC)
  994. ZEND_ME(Generator, key, arginfo_generator_void, ZEND_ACC_PUBLIC)
  995. ZEND_ME(Generator, next, arginfo_generator_void, ZEND_ACC_PUBLIC)
  996. ZEND_ME(Generator, send, arginfo_generator_send, ZEND_ACC_PUBLIC)
  997. ZEND_ME(Generator, throw, arginfo_generator_throw, ZEND_ACC_PUBLIC)
  998. ZEND_ME(Generator, getReturn,arginfo_generator_void, ZEND_ACC_PUBLIC)
  999. ZEND_ME(Generator, __wakeup, arginfo_generator_void, ZEND_ACC_PUBLIC)
  1000. ZEND_FE_END
  1001. };
  1002. void zend_register_generator_ce(void) /* {{{ */
  1003. {
  1004. zend_class_entry ce;
  1005. INIT_CLASS_ENTRY(ce, "Generator", generator_functions);
  1006. zend_ce_generator = zend_register_internal_class(&ce);
  1007. zend_ce_generator->ce_flags |= ZEND_ACC_FINAL;
  1008. zend_ce_generator->create_object = zend_generator_create;
  1009. zend_ce_generator->serialize = zend_class_serialize_deny;
  1010. zend_ce_generator->unserialize = zend_class_unserialize_deny;
  1011. /* get_iterator has to be assigned *after* implementing the inferface */
  1012. zend_class_implements(zend_ce_generator, 1, zend_ce_iterator);
  1013. zend_ce_generator->get_iterator = zend_generator_get_iterator;
  1014. memcpy(&zend_generator_handlers, &std_object_handlers, sizeof(zend_object_handlers));
  1015. zend_generator_handlers.free_obj = zend_generator_free_storage;
  1016. zend_generator_handlers.dtor_obj = zend_generator_dtor_storage;
  1017. zend_generator_handlers.get_gc = zend_generator_get_gc;
  1018. zend_generator_handlers.clone_obj = NULL;
  1019. zend_generator_handlers.get_constructor = zend_generator_get_constructor;
  1020. INIT_CLASS_ENTRY(ce, "ClosedGeneratorException", NULL);
  1021. zend_ce_ClosedGeneratorException = zend_register_internal_class_ex(&ce, zend_ce_exception);
  1022. }
  1023. /* }}} */
  1024. /*
  1025. * Local variables:
  1026. * tab-width: 4
  1027. * c-basic-offset: 4
  1028. * indent-tabs-mode: t
  1029. * End:
  1030. * vim600: sw=4 ts=4 fdm=marker
  1031. * vim<600: sw=4 ts=4
  1032. */