Advertisement
Guest User

generators_revisited.diff.txt

a guest
Nov 28th, 2012
181
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 77.88 KB | None | 0 0
  1. diff --git a/UPGRADING b/UPGRADING
  2. index 18ab6bf..953d2db 100755
  3. --- a/UPGRADING
  4. +++ b/UPGRADING
  5. @@ -28,6 +28,27 @@ PHP 5.5 UPGRADE NOTES
  6.    zend_logo_guid() have been removed
  7.  - Removal of Logo GUIDs
  8.  
  9. +- extensions can't override zend_execute() any more, they should override
  10. +  zend_execute_ex() instead. The EG(current_execute_data) is already
  11. +  initialized in zend_execute_ex(), so for compatibility extensions
  12. +  may need to use EG(current_execute_data)->prev_execute_data instead.
  13. +- removed EG(arg_types_stack), EX(fbc), EX(called_scope), EX(current_object)
  14. +- added op_array->nested_calls. It's calculated at compile time.
  15. +- added EX(call_slots). It is an array to store informatin about syntaticaly
  16. +  nested calls (e.g. foo(bar())). It's preallocated together with execute_data.
  17. +- added EX(call) - pointer to a current calling function. Actually an
  18. +  element of EX(call_slots)
  19. +- opcodes INIT_METHOD_CALL, ZEND_INIT_STATIC_METHOD_CALL,
  20. +  ZEND_INIT_FCALL_BY_NAME, ZEND_INIT_NS_FCALL_BY_NAME use result.num as
  21. +  an index in EX(call_slots)
  22. +- opcode ZEND_NEW uses extended_vallue as an index in EX(call_slots)
  23. +- opcoes ZEND_DO_FCALL and ZEND_DO_FCALL_BY_NAME use op2.num as
  24. +  an index in EX(call_slots)
  25. +- added op_array->used_stack. It's calcualated at compile time and the
  26. +  corresponding stack space is preallocated together with execute_data.
  27. +  ZEND_SEND* and ZEND_DO_FCALL* don't need to check for stack overflow
  28. +  anymore.
  29. +
  30.  ========================================
  31.  2. New Features
  32.  ========================================
  33. diff --git a/Zend/zend.c b/Zend/zend.c
  34. index 9ab879a..fc6aed0 100644
  35. --- a/Zend/zend.c
  36. +++ b/Zend/zend.c
  37. @@ -683,11 +683,11 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions TS
  38.  #if HAVE_DTRACE
  39.  /* build with dtrace support */
  40.     zend_compile_file = dtrace_compile_file;
  41. -   zend_execute = dtrace_execute;
  42. +   zend_execute_ex = dtrace_execute_ex;
  43.     zend_execute_internal = dtrace_execute_internal;
  44.  #else
  45.     zend_compile_file = compile_file;
  46. -   zend_execute = execute;
  47. +   zend_execute_ex = execute_ex;
  48.     zend_execute_internal = NULL;
  49.  #endif /* HAVE_SYS_SDT_H */
  50.     zend_compile_string = compile_string;
  51. diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
  52. index de77068..e768996 100644
  53. --- a/Zend/zend_compile.c
  54. +++ b/Zend/zend_compile.c
  55. @@ -179,6 +179,8 @@ void zend_init_compiler_context(TSRMLS_D) /* {{{ */
  56.     CG(context).literals_size = 0;
  57.     CG(context).current_brk_cont = -1;
  58.     CG(context).backpatch_count = 0;
  59. +   CG(context).nested_calls = 0;
  60. +   CG(context).used_stack = 0;
  61.     CG(context).labels = NULL;
  62.  }
  63.  /* }}} */
  64. @@ -1950,6 +1952,9 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace
  65.     function_name->u.constant.value.str.val = lcname;
  66.    
  67.     zend_stack_push(&CG(function_call_stack), (void *) &function, sizeof(zend_function *));
  68. +   if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) {
  69. +       CG(active_op_array)->nested_calls = CG(context).nested_calls + 1;
  70. +   }
  71.     zend_do_extended_fcall_begin(TSRMLS_C);
  72.     return 0;
  73.  }
  74. @@ -1988,11 +1993,13 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
  75.             GET_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant);
  76.         }
  77.         last_op->opcode = ZEND_INIT_METHOD_CALL;
  78. -       SET_UNUSED(last_op->result);
  79. +       last_op->result_type = IS_UNUSED;
  80. +       last_op->result.num = CG(context).nested_calls;
  81.         Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME;
  82.     } else {
  83.         zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
  84.         opline->opcode = ZEND_INIT_FCALL_BY_NAME;
  85. +       opline->result.num = CG(context).nested_calls;
  86.         SET_UNUSED(opline->op1);
  87.         if (left_bracket->op_type == IS_CONST) {
  88.             opline->op2_type = IS_CONST;
  89. @@ -2004,6 +2011,9 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
  90.     }
  91.  
  92.     zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
  93. +   if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
  94. +       CG(active_op_array)->nested_calls = CG(context).nested_calls;
  95. +   }
  96.     zend_do_extended_fcall_begin(TSRMLS_C);
  97.  }
  98.  /* }}} */
  99. @@ -2031,12 +2041,14 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML
  100.         /* In run-time PHP will check for function with full name and
  101.            internal function with short name */
  102.         opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
  103. +       opline->result.num = CG(context).nested_calls;
  104.         SET_UNUSED(opline->op1);
  105.         opline->op2_type = IS_CONST;
  106.         opline->op2.constant = zend_add_ns_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC);
  107.         GET_CACHE_SLOT(opline->op2.constant);
  108.     } else {
  109.         opline->opcode = ZEND_INIT_FCALL_BY_NAME;
  110. +       opline->result.num = CG(context).nested_calls;
  111.         SET_UNUSED(opline->op1);
  112.         if (function_name->op_type == IS_CONST) {
  113.             opline->op2_type = IS_CONST;
  114. @@ -2048,6 +2060,9 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML
  115.     }
  116.  
  117.     zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
  118. +   if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
  119. +       CG(active_op_array)->nested_calls = CG(context).nested_calls;
  120. +   }
  121.     zend_do_extended_fcall_begin(TSRMLS_C);
  122.  }
  123.  /* }}} */
  124. @@ -2395,6 +2410,7 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na
  125.         opline->extended_value = class_node.EA  ;
  126.     }
  127.     opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
  128. +   opline->result.num = CG(context).nested_calls;
  129.     if (class_node.op_type == IS_CONST) {
  130.         opline->op1_type = IS_CONST;
  131.         opline->op1.constant =
  132. @@ -2416,6 +2432,9 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na
  133.     }
  134.  
  135.     zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
  136. +   if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
  137. +       CG(active_op_array)->nested_calls = CG(context).nested_calls;
  138. +   }
  139.     zend_do_extended_fcall_begin(TSRMLS_C);
  140.     return 1; /* Dynamic */
  141.  }
  142. @@ -2436,21 +2455,29 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode
  143.         if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) {
  144.             opline->opcode = ZEND_DO_FCALL;
  145.             SET_NODE(opline->op1, function_name);
  146. +           SET_UNUSED(opline->op2);
  147. +           opline->op2.num = CG(context).nested_calls;
  148.             CALCULATE_LITERAL_HASH(opline->op1.constant);
  149.             GET_CACHE_SLOT(opline->op1.constant);
  150.         } else {
  151.             opline->opcode = ZEND_DO_FCALL_BY_NAME;
  152.             SET_UNUSED(opline->op1);
  153. +           SET_UNUSED(opline->op2);
  154. +           opline->op2.num = --CG(context).nested_calls;
  155.         }
  156.     }
  157.  
  158.     opline->result.var = get_temporary_variable(CG(active_op_array));
  159.     opline->result_type = IS_VAR;
  160. -   GET_NODE(result, opline->result)    ;
  161. -   SET_UNUSED(opline->op2);
  162. +   GET_NODE(result, opline->result);
  163.  
  164.     zend_stack_del_top(&CG(function_call_stack));
  165.     opline->extended_value = Z_LVAL(argument_list->u.constant);
  166. +
  167. +   if (CG(context).used_stack + 1 > CG(active_op_array)->used_stack) {
  168. +       CG(active_op_array)->used_stack = CG(context).used_stack + 1;
  169. +   }
  170. +   CG(context).used_stack -= Z_LVAL(argument_list->u.constant);
  171.  }
  172.  /* }}} */
  173.  
  174. @@ -2558,6 +2585,10 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{
  175.     SET_NODE(opline->op1, param);
  176.     opline->op2.opline_num = offset;
  177.     SET_UNUSED(opline->op2);
  178. +
  179. +   if (++CG(context).used_stack > CG(active_op_array)->used_stack) {
  180. +       CG(active_op_array)->used_stack = CG(context).used_stack;
  181. +   }
  182.  }
  183.  /* }}} */
  184.  
  185. @@ -5547,12 +5578,16 @@ void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC) /*
  186.     new_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
  187.     opline = get_next_op(CG(active_op_array) TSRMLS_CC);
  188.     opline->opcode = ZEND_NEW;
  189. +   opline->extended_value = CG(context).nested_calls;
  190.     opline->result_type = IS_VAR;
  191.     opline->result.var = get_temporary_variable(CG(active_op_array));
  192.     SET_NODE(opline->op1, class_type);
  193.     SET_UNUSED(opline->op2);
  194.  
  195.     zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(unsigned char *));
  196. +   if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
  197. +       CG(active_op_array)->nested_calls = CG(context).nested_calls;
  198. +   }
  199.  }
  200.  /* }}} */
  201.  
  202. @@ -5765,6 +5800,13 @@ void zend_do_shell_exec(znode *result, const znode *cmd TSRMLS_DC) /* {{{ */
  203.     opline->extended_value = 1;
  204.     SET_UNUSED(opline->op2);
  205.     GET_NODE(result, opline->result);
  206. +
  207. +   if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) {
  208. +       CG(active_op_array)->nested_calls = CG(context).nested_calls + 1;
  209. +   }
  210. +   if (CG(context).used_stack + 2 > CG(active_op_array)->used_stack) {
  211. +       CG(active_op_array)->used_stack = CG(context).used_stack + 2;
  212. +   }
  213.  }
  214.  /* }}} */
  215.  
  216. diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
  217. index e46c1a3..def6341 100644
  218. --- a/Zend/zend_compile.h
  219. +++ b/Zend/zend_compile.h
  220. @@ -59,6 +59,8 @@ typedef struct _zend_compiler_context {
  221.     int        literals_size;
  222.     int        current_brk_cont;
  223.     int        backpatch_count;
  224. +   int        nested_calls;
  225. +   int        used_stack;
  226.     HashTable *labels;
  227.  } zend_compiler_context;
  228.  
  229. @@ -279,6 +281,9 @@ struct _zend_op_array {
  230.  
  231.     zend_uint T;
  232.  
  233. +   zend_uint nested_calls;
  234. +   zend_uint used_stack;
  235. +
  236.     zend_brk_cont_element *brk_cont_array;
  237.     int last_brk_cont;
  238.  
  239. @@ -369,11 +374,17 @@ typedef struct _list_llist_element {
  240.  
  241.  union _temp_variable;
  242.  
  243. +typedef struct _call_slot {
  244. +   zend_function     *fbc;
  245. +   zval              *object;
  246. +   zend_class_entry  *called_scope;
  247. +   zend_bool          is_ctor_call;
  248. +   zend_bool          is_ctor_result_used;
  249. +} call_slot;
  250. +
  251.  struct _zend_execute_data {
  252.     struct _zend_op *opline;
  253.     zend_function_state function_state;
  254. -   zend_function *fbc; /* Function Being Called */
  255. -   zend_class_entry *called_scope;
  256.     zend_op_array *op_array;
  257.     zval *object;
  258.     union _temp_variable *Ts;
  259. @@ -386,8 +397,9 @@ struct _zend_execute_data {
  260.     zend_class_entry *current_scope;
  261.     zend_class_entry *current_called_scope;
  262.     zval *current_this;
  263. -   zval *current_object;
  264.     struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */
  265. +   call_slot *call_slots;
  266. +   call_slot *call;
  267.  };
  268.  
  269.  #define EX(element) execute_data.element
  270. diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
  271. index 361afc6..5f04ba7 100644
  272. --- a/Zend/zend_execute.c
  273. +++ b/Zend/zend_execute.c
  274. @@ -1570,25 +1570,6 @@ void zend_free_compiled_variables(zval ***CVs, int num) /* {{{ */
  275.  }
  276.  /* }}} */
  277.  
  278. -void** zend_copy_arguments(void **arguments_end) /* {{{ */
  279. -{
  280. -   int arguments_count = (int) (zend_uintptr_t) *arguments_end;
  281. -   size_t arguments_size = (arguments_count + 1) * sizeof(void **);
  282. -   void **arguments_start = arguments_end - arguments_count;
  283. -   void **copied_arguments_start = emalloc(arguments_size);
  284. -   void **copied_arguments_end = copied_arguments_start + arguments_count;
  285. -   int i;
  286. -
  287. -   memcpy(copied_arguments_start, arguments_start, arguments_size);
  288. -
  289. -   for (i = 0; i < arguments_count; i++) {
  290. -       Z_ADDREF_P((zval *) arguments_start[i]);
  291. -   }
  292. -
  293. -   return copied_arguments_end;
  294. -}
  295. -/* }}} */
  296. -
  297.  /*
  298.   * Local variables:
  299.   * tab-width: 4
  300. diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h
  301. index 4594eba..fdd9f56 100644
  302. --- a/Zend/zend_execute.h
  303. +++ b/Zend/zend_execute.h
  304. @@ -50,14 +50,14 @@ typedef union _temp_variable {
  305.  
  306.  BEGIN_EXTERN_C()
  307.  struct _zend_fcall_info;
  308. -ZEND_API extern void (*zend_execute)(zend_op_array *op_array TSRMLS_DC);
  309. +ZEND_API extern void (*zend_execute_ex)(zend_execute_data *execute_data TSRMLS_DC);
  310.  ZEND_API extern void (*zend_execute_internal)(zend_execute_data *execute_data_ptr, struct _zend_fcall_info *fci, int return_value_used TSRMLS_DC);
  311.  
  312.  void init_executor(TSRMLS_D);
  313.  void shutdown_executor(TSRMLS_D);
  314.  void shutdown_destructors(TSRMLS_D);
  315.  zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC);
  316. -ZEND_API void execute(zend_op_array *op_array TSRMLS_DC);
  317. +ZEND_API void zend_execute(zend_op_array *op_array TSRMLS_DC);
  318.  ZEND_API void execute_ex(zend_execute_data *execute_data TSRMLS_DC);
  319.  ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, struct _zend_fcall_info *fci, int return_value_used TSRMLS_DC);
  320.  ZEND_API int zend_is_true(zval *op);
  321. @@ -222,12 +222,6 @@ static zend_always_inline void **zend_vm_stack_top(TSRMLS_D)
  322.  
  323.  static zend_always_inline void zend_vm_stack_push(void *ptr TSRMLS_DC)
  324.  {
  325. -   ZEND_VM_STACK_GROW_IF_NEEDED(1);
  326. -   *(EG(argument_stack)->top++) = ptr;
  327. -}
  328. -
  329. -static zend_always_inline void zend_vm_stack_push_nocheck(void *ptr TSRMLS_DC)
  330. -{
  331.     *(EG(argument_stack)->top++) = ptr;
  332.  }
  333.  
  334. @@ -235,11 +229,6 @@ static zend_always_inline void *zend_vm_stack_pop(TSRMLS_D)
  335.  {
  336.     void *el = *(--EG(argument_stack)->top);
  337.  
  338. -   if (UNEXPECTED(EG(argument_stack)->top == ZEND_VM_STACK_ELEMETS(EG(argument_stack)))) {
  339. -       zend_vm_stack p = EG(argument_stack);
  340. -       EG(argument_stack) = p->prev;
  341. -       efree(p);
  342. -   }
  343.     return el;
  344.  }
  345.  
  346. @@ -272,6 +261,12 @@ static zend_always_inline void *zend_vm_stack_alloc(size_t size TSRMLS_DC)
  347.     return ret;
  348.  }
  349.  
  350. +static zend_always_inline void** zend_vm_stack_frame_base(zend_execute_data *ex)
  351. +{
  352. +   return (void**)((char*)ex->call_slots +
  353. +       ZEND_MM_ALIGNED_SIZE(sizeof(call_slot)) * ex->op_array->nested_calls);
  354. +}
  355. +
  356.  static zend_always_inline void zend_vm_stack_free_int(void *ptr TSRMLS_DC)
  357.  {
  358.     if (UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (void**)ptr)) {
  359. @@ -302,35 +297,6 @@ static zend_always_inline void zend_vm_stack_free(void *ptr TSRMLS_DC)
  360.     }
  361.  }
  362.  
  363. -static zend_always_inline void** zend_vm_stack_push_args(int count TSRMLS_DC)
  364. -{
  365. -
  366. -   if (UNEXPECTED(EG(argument_stack)->top - ZEND_VM_STACK_ELEMETS(EG(argument_stack)) < count)  ||
  367. -       UNEXPECTED(EG(argument_stack)->top == EG(argument_stack)->end)) {
  368. -       zend_vm_stack p = EG(argument_stack);
  369. -
  370. -       zend_vm_stack_extend(count + 1 TSRMLS_CC);
  371. -
  372. -       EG(argument_stack)->top += count;
  373. -       *(EG(argument_stack)->top) = (void*)(zend_uintptr_t)count;
  374. -       while (count-- > 0) {
  375. -           void *data = *(--p->top);
  376. -
  377. -           if (UNEXPECTED(p->top == ZEND_VM_STACK_ELEMETS(p))) {
  378. -               zend_vm_stack r = p;
  379. -
  380. -               EG(argument_stack)->prev = p->prev;
  381. -               p = p->prev;
  382. -               efree(r);
  383. -           }
  384. -           *(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + count) = data;
  385. -       }
  386. -       return EG(argument_stack)->top++;
  387. -   }
  388. -   *(EG(argument_stack)->top) = (void*)(zend_uintptr_t)count;
  389. -   return EG(argument_stack)->top++;
  390. -}
  391. -
  392.  static zend_always_inline void zend_vm_stack_clear_multiple(TSRMLS_D)
  393.  {
  394.     void **p = EG(argument_stack)->top - 1;
  395. @@ -344,9 +310,19 @@ static zend_always_inline void zend_vm_stack_clear_multiple(TSRMLS_D)
  396.     zend_vm_stack_free_int(p TSRMLS_CC);
  397.  }
  398.  
  399. -static zend_always_inline zval** zend_vm_stack_get_arg(int requested_arg TSRMLS_DC)
  400. +static zend_always_inline int zend_vm_stack_get_args_count_ex(zend_execute_data *ex)
  401. +{
  402. +   if (ex) {
  403. +       void **p = ex->function_state.arguments;
  404. +       return (int)(zend_uintptr_t) *p;
  405. +   } else {
  406. +       return 0;          
  407. +   }
  408. +}
  409. +
  410. +static zend_always_inline zval** zend_vm_stack_get_arg_ex(zend_execute_data *ex, int requested_arg)
  411.  {
  412. -   void **p = EG(current_execute_data)->prev_execute_data->function_state.arguments;
  413. +   void **p = ex->function_state.arguments;
  414.     int arg_count = (int)(zend_uintptr_t) *p;
  415.  
  416.     if (UNEXPECTED(requested_arg > arg_count)) {
  417. @@ -355,25 +331,14 @@ static zend_always_inline zval** zend_vm_stack_get_arg(int requested_arg TSRMLS_
  418.     return (zval**)p - arg_count + requested_arg - 1;
  419.  }
  420.  
  421. -static zend_always_inline void zend_arg_types_stack_2_pop(zend_ptr_stack *stack, zval **object, zend_function **fbc)
  422. +static zend_always_inline int zend_vm_stack_get_args_count(TSRMLS_D)
  423.  {
  424. -   void *a, *b;
  425. -
  426. -   zend_ptr_stack_2_pop(stack, &a, &b);
  427. -
  428. -   *object = (zval *) a;
  429. -   *fbc = (zend_function *) b;
  430. +   return zend_vm_stack_get_args_count_ex(EG(current_execute_data)->prev_execute_data);
  431.  }
  432.  
  433. -static zend_always_inline void zend_arg_types_stack_3_pop(zend_ptr_stack *stack, zend_class_entry **called_scope, zval **object, zend_function **fbc)
  434. +static zend_always_inline zval** zend_vm_stack_get_arg(int requested_arg TSRMLS_DC)
  435.  {
  436. -   void *a, *b, *c;
  437. -
  438. -   zend_ptr_stack_3_pop(stack, &a, &b, &c);
  439. -
  440. -   *called_scope = (zend_class_entry *) a;
  441. -   *object = (zval *) b;
  442. -   *fbc = (zend_function *) c;
  443. +   return zend_vm_stack_get_arg_ex(EG(current_execute_data)->prev_execute_data, requested_arg);
  444.  }
  445.  
  446.  void execute_new_code(TSRMLS_D);
  447. @@ -436,7 +401,6 @@ ZEND_API int zend_do_fcall(ZEND_OPCODE_HANDLER_ARGS);
  448.  
  449.  void zend_clean_and_cache_symbol_table(HashTable *symbol_table TSRMLS_DC);
  450.  void zend_free_compiled_variables(zval ***CVs, int num);
  451. -void **zend_copy_arguments(void **arguments_end);
  452.  
  453.  #define CACHED_PTR(num) \
  454.     EG(active_op_array)->run_time_cache[(num)]
  455. diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
  456. index 9787966..3df0ca2 100644
  457. --- a/Zend/zend_execute_API.c
  458. +++ b/Zend/zend_execute_API.c
  459. @@ -38,7 +38,7 @@
  460.  #include <sys/time.h>
  461.  #endif
  462.  
  463. -ZEND_API void (*zend_execute)(zend_op_array *op_array TSRMLS_DC);
  464. +ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data TSRMLS_DC);
  465.  ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data_ptr, zend_fcall_info *fci, int return_value_used TSRMLS_DC);
  466.  
  467.  /* true globals */
  468. @@ -137,7 +137,6 @@ void init_executor(TSRMLS_D) /* {{{ */
  469.     INIT_ZVAL(EG(error_zval));
  470.     EG(uninitialized_zval_ptr)=&EG(uninitialized_zval);
  471.     EG(error_zval_ptr)=&EG(error_zval);
  472. -   zend_ptr_stack_init(&EG(arg_types_stack));
  473.  /* destroys stack frame, therefore makes core dumps worthless */
  474.  #if 0&&ZEND_DEBUG
  475.     original_sigsegv_handler = signal(SIGSEGV, zend_handle_sigsegv);
  476. @@ -293,10 +292,10 @@ void shutdown_executor(TSRMLS_D) /* {{{ */
  477.     } zend_end_try();
  478.  
  479.     zend_try {
  480. -       zend_vm_stack_destroy(TSRMLS_C);
  481. -
  482.         zend_objects_store_free_object_storage(&EG(objects_store) TSRMLS_CC);
  483.  
  484. +       zend_vm_stack_destroy(TSRMLS_C);
  485. +
  486.         /* Destroy all op arrays */
  487.         if (EG(full_tables_cleanup)) {
  488.             zend_hash_reverse_apply(EG(function_table), (apply_func_t) clean_non_persistent_function_full TSRMLS_CC);
  489. @@ -324,7 +323,6 @@ void shutdown_executor(TSRMLS_D) /* {{{ */
  490.  
  491.         zend_hash_destroy(&EG(included_files));
  492.  
  493. -       zend_ptr_stack_destroy(&EG(arg_types_stack));
  494.         zend_stack_destroy(&EG(user_error_handlers_error_reporting));
  495.         zend_ptr_stack_destroy(&EG(user_error_handlers));
  496.         zend_ptr_stack_destroy(&EG(user_exception_handlers));
  497. @@ -862,7 +860,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
  498.                     !ARG_MAY_BE_SENT_BY_REF(EX(function_state).function, i + 1)) {
  499.                     if (i || UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (EG(argument_stack)->top))) {
  500.                         /* hack to clean up the stack */
  501. -                       zend_vm_stack_push_nocheck((void *) (zend_uintptr_t)i TSRMLS_CC);
  502. +                       zend_vm_stack_push((void *) (zend_uintptr_t)i TSRMLS_CC);
  503.                         zend_vm_stack_clear_multiple(TSRMLS_C);
  504.                     }
  505.  
  506. @@ -899,11 +897,11 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
  507.             *param = **(fci->params[i]);
  508.             INIT_PZVAL(param);
  509.         }
  510. -       zend_vm_stack_push_nocheck(param TSRMLS_CC);
  511. +       zend_vm_stack_push(param TSRMLS_CC);
  512.     }
  513.  
  514.     EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C);
  515. -   zend_vm_stack_push_nocheck((void*)(zend_uintptr_t)fci->param_count TSRMLS_CC);
  516. +   zend_vm_stack_push((void*)(zend_uintptr_t)fci->param_count TSRMLS_CC);
  517.  
  518.     current_scope = EG(scope);
  519.     EG(scope) = calling_scope;
  520. diff --git a/Zend/zend_extensions.h b/Zend/zend_extensions.h
  521. index 703e03c..17804cb 100644
  522. --- a/Zend/zend_extensions.h
  523. +++ b/Zend/zend_extensions.h
  524. @@ -28,7 +28,7 @@
  525.  /* The first number is the engine version and the rest is the date.
  526.   * This way engine 2/3 API no. is always greater than engine 1 API no..
  527.   */
  528. -#define ZEND_EXTENSION_API_NO  220121113
  529. +#define ZEND_EXTENSION_API_NO  220121128
  530.  
  531.  typedef struct _zend_extension_version_info {
  532.     int zend_extension_api_no;
  533. diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
  534. index 1895305..493e99d 100644
  535. --- a/Zend/zend_generators.c
  536. +++ b/Zend/zend_generators.c
  537. @@ -32,41 +32,7 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio
  538.     if (generator->execute_data) {
  539.         zend_execute_data *execute_data = generator->execute_data;
  540.         zend_op_array *op_array = execute_data->op_array;
  541. -
  542. -       if (!finished_execution) {
  543. -           if (op_array->has_finally_block) {
  544. -               /* -1 required because we want the last run opcode, not the
  545. -                * next to-be-run one. */
  546. -               zend_uint op_num = execute_data->opline - op_array->opcodes - 1;
  547. -               zend_uint finally_op_num = 0;
  548. -
  549. -               /* Find next finally block */
  550. -               int i;
  551. -               for (i = 0; i < op_array->last_try_catch; i++) {
  552. -                   zend_try_catch_element *try_catch = &op_array->try_catch_array[i];
  553. -
  554. -                   if (op_num < try_catch->try_op) {
  555. -                       break;
  556. -                   }
  557. -
  558. -                   if (op_num < try_catch->finally_op) {
  559. -                       finally_op_num = try_catch->finally_op;
  560. -                   }
  561. -               }
  562. -
  563. -               /* If a finally block was found we jump directly to it and
  564. -                * resume the generator. Furthermore we abort this close call
  565. -                * because the generator will already be closed somewhere in
  566. -                * the resume. */
  567. -               if (finally_op_num) {
  568. -                   execute_data->opline = &op_array->opcodes[finally_op_num];
  569. -                   execute_data->fast_ret = NULL;
  570. -                   generator->flags |= ZEND_GENERATOR_FORCED_CLOSE;
  571. -                   zend_generator_resume(generator TSRMLS_CC);
  572. -                   return;
  573. -               }
  574. -           }
  575. -       }
  576. +       void **stack_frame;
  577.  
  578.         if (!execute_data->symbol_table) {
  579.             zend_free_compiled_variables(execute_data->CVs, op_array->last_var);
  580. @@ -78,10 +44,6 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio
  581.             zval_ptr_dtor(&execute_data->current_this);
  582.         }
  583.  
  584. -       if (execute_data->object) {
  585. -           zval_ptr_dtor(&execute_data->object);
  586. -       }
  587. -
  588.         /* If the generator is closed before it can finish execution (reach
  589.          * a return statement) we have to free loop variables manually, as
  590.          * we don't know whether the SWITCH_FREE / FREE opcodes have run */
  591. @@ -120,32 +82,20 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio
  592.         }
  593.  
  594.         /* Clear any backed up stack arguments */
  595. -       if (generator->backed_up_stack) {
  596. -           zval **zvals = (zval **) generator->backed_up_stack;
  597. -           size_t zval_num = generator->backed_up_stack_size / sizeof(zval *);
  598. -           int i;
  599. -
  600. -           for (i = 0; i < zval_num; i++) {
  601. -               zval_ptr_dtor(&zvals[i]);
  602. +       if (generator->stack != EG(argument_stack)) {
  603. +           stack_frame = zend_vm_stack_frame_base(execute_data);
  604. +           while (generator->stack->top != stack_frame) {
  605. +               zval_ptr_dtor((zval**)stack_frame);
  606. +               stack_frame++;
  607.             }
  608. -
  609. -           efree(generator->backed_up_stack);
  610.         }
  611.  
  612. -       if (generator->backed_up_arg_types_stack) {
  613. -           /* The arg types stack contains three elements per call: fbc, object
  614. -            * and called_scope. Here we traverse the stack from top to bottom
  615. -            * and dtor the object. */
  616. -           int i = generator->backed_up_arg_types_stack_count / 3;
  617. -           while (i--) {
  618. -               zval *object = (zval *) generator->backed_up_arg_types_stack[3*i + 1];
  619. -               if (object) {
  620. -                   zval_ptr_dtor(&object);
  621. -               }
  622. +       while (execute_data->call >= execute_data->call_slots) {
  623. +           if (execute_data->call->object) {
  624. +               zval_ptr_dtor(&execute_data->call->object);
  625.             }
  626. -
  627. -           efree(generator->backed_up_arg_types_stack);
  628. -       }
  629. +           execute_data->call--;
  630. +       }
  631.  
  632.         /* We have added an additional stack frame in prev_execute_data, so we
  633.          * have to free it. It also contains the arguments passed to the
  634. @@ -162,11 +112,7 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio
  635.                 for (i = 0; i < arguments_count; ++i) {
  636.                     zval_ptr_dtor(arguments_start + i);
  637.                 }
  638. -
  639. -               efree(arguments_start);
  640.             }
  641. -
  642. -           efree(prev_execute_data);
  643.         }
  644.  
  645.         /* Free a clone of closure */
  646. @@ -175,7 +121,11 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio
  647.             efree(op_array);
  648.         }
  649.  
  650. -       efree(execute_data);
  651. +       efree(generator->stack);
  652. +       if (generator->stack == EG(argument_stack)) {
  653. +           /* abnormal exit for running generator */
  654. +           EG(argument_stack) = NULL;
  655. +       }
  656.         generator->execute_data = NULL;
  657.     }
  658.  
  659. @@ -210,27 +160,39 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator **
  660.         zend_execute_data *execute_data = orig->execute_data;
  661.         zend_op_array *op_array = execute_data->op_array;
  662.         HashTable *symbol_table = execute_data->symbol_table;
  663. -
  664. -       /* Alloc separate execution context, as well as separate sections for
  665. -        * compiled variables and temporary variables */
  666. -       size_t execute_data_size = ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data));
  667. -       size_t CVs_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval **) * op_array->last_var * (symbol_table ? 1 : 2));
  668. -       size_t Ts_size = ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T;
  669. -       size_t total_size = execute_data_size + CVs_size + Ts_size;
  670. -
  671. -       clone->execute_data = emalloc(total_size);
  672. -
  673. -       /* Copy the zend_execute_data struct */
  674. -       memcpy(clone->execute_data, execute_data, execute_data_size);
  675. -
  676. -       /* Set the pointers to the memory segments for the compiled and
  677. -        * temporary variables (which are located after the execute_data) */
  678. -       clone->execute_data->CVs = (zval ***) ((char *) clone->execute_data + execute_data_size);
  679. -       clone->execute_data->Ts = (temp_variable *) ((char *) clone->execute_data->CVs + CVs_size);
  680. -
  681. -       /* Zero out the compiled variables section */
  682. -       memset(clone->execute_data->CVs, 0, sizeof(zval **) * op_array->last_var);
  683. -
  684. +       zend_execute_data *current_execute_data;
  685. +       zend_op **opline_ptr;
  686. +       HashTable *current_symbol_table;
  687. +       zend_vm_stack current_stack;
  688. +       zval *current_this;
  689. +       void **stack_frame, **orig_stack_frame;
  690. +
  691. +       /* Create new execution context. We have to back up and restore
  692. +        * EG(current_execute_data), EG(opline_ptr), EG(active_symbol_table)
  693. +        * and EG(This) here because the function modifies or uses them  */
  694. +       current_execute_data = EG(current_execute_data);
  695. +       EG(current_execute_data) = execute_data->prev_execute_data;
  696. +       opline_ptr = EG(opline_ptr);
  697. +       current_symbol_table = EG(active_symbol_table);
  698. +       EG(active_symbol_table) = execute_data->symbol_table;
  699. +       current_this = EG(This);
  700. +       EG(This) = NULL;
  701. +       current_stack = EG(argument_stack);
  702. +       clone->execute_data = zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC);
  703. +       clone->stack = EG(argument_stack);
  704. +       EG(argument_stack) = current_stack;
  705. +       EG(This) = current_this;
  706. +       EG(active_symbol_table) = current_symbol_table;
  707. +       EG(current_execute_data) = current_execute_data;
  708. +       EG(opline_ptr) = opline_ptr;
  709. +
  710. +       /* copy */
  711. +       clone->execute_data->opline = execute_data->opline;
  712. +       clone->execute_data->function_state = execute_data->function_state;
  713. +       clone->execute_data->current_scope = execute_data->current_scope;
  714. +       clone->execute_data->current_called_scope = execute_data->current_called_scope;
  715. +       clone->execute_data->fast_ret = execute_data->fast_ret;
  716. +      
  717.         if (!symbol_table) {
  718.             int i;
  719.  
  720. @@ -238,7 +200,7 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator **
  721.             for (i = 0; i < op_array->last_var; i++) {
  722.                 if (execute_data->CVs[i]) {
  723.                     clone->execute_data->CVs[i] = (zval **) clone->execute_data->CVs + op_array->last_var + i;
  724. -                   *clone->execute_data->CVs[i] = (zval *) orig->execute_data->CVs[op_array->last_var + i];
  725. +                   *clone->execute_data->CVs[i] = (zval *) execute_data->CVs[op_array->last_var + i];
  726.                     Z_ADDREF_PP(clone->execute_data->CVs[i]);
  727.                 }
  728.             }
  729. @@ -259,8 +221,39 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator **
  730.             }
  731.         }
  732.  
  733. +       /* Copy nested-calls stack */
  734. +       if (execute_data->call) {
  735. +           clone->execute_data->call = clone->execute_data->call_slots +
  736. +               (execute_data->call - execute_data->call_slots);
  737. +       } else {
  738. +           clone->execute_data->call = NULL;
  739. +       }
  740. +       memcpy(clone->execute_data->call_slots, execute_data->call_slots, sizeof(call_slot) * op_array->nested_calls);
  741. +       if (clone->execute_data->call >= clone->execute_data->call_slots) {
  742. +           call_slot *call = clone->execute_data->call;
  743. +  
  744. +           while (call >= clone->execute_data->call_slots) {
  745. +               if (call->object) {
  746. +                   Z_ADDREF_P(call->object);
  747. +               }
  748. +               call--;
  749. +           }
  750. +       }
  751. +
  752.         /* Copy the temporary variables */
  753. -       memcpy(clone->execute_data->Ts, orig->execute_data->Ts, Ts_size);
  754. +       memcpy(clone->execute_data->Ts, execute_data->Ts, sizeof(temp_variable) * op_array->T);
  755. +
  756. +       /* Copy arguments passed on stack */
  757. +       stack_frame = zend_vm_stack_frame_base(clone->execute_data);
  758. +       orig_stack_frame = zend_vm_stack_frame_base(execute_data);
  759. +       clone->stack->top = stack_frame + (orig->stack->top - orig_stack_frame);
  760. +       if (clone->stack->top != stack_frame) {
  761. +           memcpy(stack_frame, orig_stack_frame, sizeof(zval*) * (orig->stack->top - orig_stack_frame));
  762. +           while (clone->stack->top != stack_frame) {
  763. +               Z_ADDREF_PP((zval**)stack_frame);
  764. +               stack_frame++;
  765. +           }
  766. +       }
  767.  
  768.         /* Add references to loop variables */
  769.         {
  770. @@ -286,42 +279,6 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator **
  771.             }
  772.         }
  773.  
  774. -       if (orig->backed_up_stack) {
  775. -           /* Copy backed up stack */
  776. -           clone->backed_up_stack = emalloc(orig->backed_up_stack_size);
  777. -           memcpy(clone->backed_up_stack, orig->backed_up_stack, orig->backed_up_stack_size);
  778. -
  779. -           /* Add refs to stack variables */
  780. -           {
  781. -               zval **zvals = (zval **) orig->backed_up_stack;
  782. -               size_t zval_num = orig->backed_up_stack_size / sizeof(zval *);
  783. -               int i;
  784. -
  785. -               for (i = 0; i < zval_num; i++) {
  786. -                   Z_ADDREF_P(zvals[i]);
  787. -               }
  788. -           }
  789. -       }
  790. -
  791. -       if (orig->backed_up_arg_types_stack) {
  792. -           size_t stack_size = orig->backed_up_arg_types_stack_count * sizeof(void *);
  793. -
  794. -           clone->backed_up_arg_types_stack = emalloc(stack_size);
  795. -           memcpy(clone->backed_up_arg_types_stack, orig->backed_up_arg_types_stack, stack_size);
  796. -
  797. -           /* We have to add refs to the objects in the arg types stack (the
  798. -            * object is always the second element of a three-pack. */
  799. -           {
  800. -               int i, stack_frames = clone->backed_up_arg_types_stack_count / 3;
  801. -               for (i = 0; i < stack_frames; i++) {
  802. -                   zval *object = (zval *) clone->backed_up_arg_types_stack[3*i + 1];
  803. -                   if (object) {
  804. -                       Z_ADDREF_P(object);
  805. -                   }
  806. -               }
  807. -           }
  808. -       }
  809. -
  810.         /* Update the send_target to use the temporary variable with the same
  811.          * offset as the original generator, but in our temporary variable
  812.          * memory segment. */
  813. @@ -334,24 +291,14 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator **
  814.         }
  815.  
  816.         if (execute_data->current_this) {
  817. +           clone->execute_data->current_this = execute_data->current_this;
  818.             Z_ADDREF_P(execute_data->current_this);
  819.         }
  820.  
  821.         if (execute_data->object) {
  822. +           clone->execute_data->object = execute_data->object;
  823.             Z_ADDREF_P(execute_data->object);
  824.         }
  825. -
  826. -       /* Prev execute data contains an additional stack frame (for proper
  827. -        * backtraces) which has to be copied. */
  828. -       clone->execute_data->prev_execute_data = emalloc(sizeof(zend_execute_data));
  829. -       memcpy(clone->execute_data->prev_execute_data, execute_data->prev_execute_data, sizeof(zend_execute_data));
  830. -
  831. -       /* It also contains the arguments passed to the generator, which also
  832. -        * have to be copied */
  833. -       if (execute_data->prev_execute_data->function_state.arguments) {
  834. -           clone->execute_data->prev_execute_data->function_state.arguments
  835. -               = zend_copy_arguments(execute_data->prev_execute_data->function_state.arguments);
  836. -       }
  837.     }
  838.  
  839.     /* The value and key are known not to be references, so simply add refs */
  840. @@ -399,7 +346,9 @@ zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC) /* {{{ */
  841.     zend_generator *generator;
  842.     zend_execute_data *current_execute_data;
  843.     zend_op **opline_ptr;
  844. +   HashTable *current_symbol_table;
  845.     zend_execute_data *execute_data;
  846. +   zend_vm_stack current_stack = EG(argument_stack);
  847.  
  848.     /* Create a clone of closure, because it may be destroyed */
  849.     if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
  850. @@ -410,11 +359,14 @@ zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC) /* {{{ */
  851.     }
  852.    
  853.     /* Create new execution context. We have to back up and restore
  854. -    * EG(current_execute_data) and EG(opline_ptr) here because the function
  855. -    * modifies it. */
  856. +    * EG(current_execute_data), EG(opline_ptr) and EG(active_symbol_table)
  857. +    * here because the function modifies or uses them  */
  858.     current_execute_data = EG(current_execute_data);
  859.     opline_ptr = EG(opline_ptr);
  860. +   current_symbol_table = EG(active_symbol_table);
  861. +   EG(active_symbol_table) = NULL;
  862.     execute_data = zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC);
  863. +   EG(active_symbol_table) = current_symbol_table;
  864.     EG(current_execute_data) = current_execute_data;
  865.     EG(opline_ptr) = opline_ptr;
  866.  
  867. @@ -434,18 +386,8 @@ zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC) /* {{{ */
  868.     /* Save execution context in generator object. */
  869.     generator = (zend_generator *) zend_object_store_get_object(return_value TSRMLS_CC);
  870.     generator->execute_data = execute_data;
  871. -
  872. -   /* We have to add another stack frame so the generator function shows
  873. -    * up in backtraces and func_get_all() can access the function
  874. -    * arguments. */
  875. -   execute_data->prev_execute_data = emalloc(sizeof(zend_execute_data));
  876. -   memset(execute_data->prev_execute_data, 0, sizeof(zend_execute_data));
  877. -   execute_data->prev_execute_data->function_state.function = (zend_function *) op_array;
  878. -   if (EG(current_execute_data)) {
  879. -       execute_data->prev_execute_data->function_state.arguments = zend_copy_arguments(EG(current_execute_data)->function_state.arguments);
  880. -   } else {
  881. -       execute_data->prev_execute_data->function_state.arguments = NULL;
  882. -   }
  883. +   generator->stack = EG(argument_stack);
  884. +   EG(argument_stack) = current_stack;
  885.  
  886.     return return_value;
  887.  }
  888. @@ -487,28 +429,7 @@ void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */
  889.         zval *original_This = EG(This);
  890.         zend_class_entry *original_scope = EG(scope);
  891.         zend_class_entry *original_called_scope = EG(called_scope);
  892. -       int original_arg_types_stack_count = EG(arg_types_stack).top;
  893. -
  894. -       /* Remember the current stack position so we can back up pushed args */
  895. -       generator->original_stack_top = zend_vm_stack_top(TSRMLS_C);
  896. -
  897. -       /* If there is a backed up stack copy it to the VM stack */
  898. -       if (generator->backed_up_stack) {
  899. -           void *stack = zend_vm_stack_alloc(generator->backed_up_stack_size TSRMLS_CC);
  900. -           memcpy(stack, generator->backed_up_stack, generator->backed_up_stack_size);
  901. -           efree(generator->backed_up_stack);
  902. -           generator->backed_up_stack = NULL;
  903. -       }
  904. -
  905. -       if (generator->backed_up_arg_types_stack) {
  906. -           zend_ptr_stack_push_from_memory(
  907. -               &EG(arg_types_stack),
  908. -               generator->backed_up_arg_types_stack_count,
  909. -               generator->backed_up_arg_types_stack
  910. -           );
  911. -           efree(generator->backed_up_arg_types_stack);
  912. -           generator->backed_up_arg_types_stack = NULL;
  913. -       }
  914. +       zend_vm_stack original_stack = EG(argument_stack);
  915.  
  916.         /* We (mis)use the return_value_ptr_ptr to provide the generator object
  917.          * to the executor, so YIELD will be able to set the yielded value */
  918. @@ -522,6 +443,7 @@ void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */
  919.         EG(This) = generator->execute_data->current_this;
  920.         EG(scope) = generator->execute_data->current_scope;
  921.         EG(called_scope) = generator->execute_data->current_called_scope;
  922. +       EG(argument_stack) = generator->stack;
  923.  
  924.         /* We want the backtrace to look as if the generator function was
  925.          * called from whatever method we are current running (e.g. next()).
  926. @@ -533,7 +455,7 @@ void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */
  927.  
  928.         /* Resume execution */
  929.         generator->flags |= ZEND_GENERATOR_CURRENTLY_RUNNING;
  930. -       execute_ex(generator->execute_data TSRMLS_CC);
  931. +       zend_execute_ex(generator->execute_data TSRMLS_CC);
  932.         generator->flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING;
  933.  
  934.         /* Restore executor globals */
  935. @@ -545,27 +467,7 @@ void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */
  936.         EG(This) = original_This;
  937.         EG(scope) = original_scope;
  938.         EG(called_scope) = original_called_scope;
  939. -
  940. -       /* The stack top before and after the execution differ, i.e. there are
  941. -        * arguments pushed to the stack. */
  942. -       if (generator->original_stack_top != zend_vm_stack_top(TSRMLS_C)) {
  943. -           generator->backed_up_stack_size = (zend_vm_stack_top(TSRMLS_C) - generator->original_stack_top) * sizeof(void *);
  944. -           generator->backed_up_stack = emalloc(generator->backed_up_stack_size);
  945. -           memcpy(generator->backed_up_stack, generator->original_stack_top, generator->backed_up_stack_size);
  946. -           zend_vm_stack_free(generator->original_stack_top TSRMLS_CC);
  947. -       }
  948. -
  949. -       if (original_arg_types_stack_count != EG(arg_types_stack).top) {
  950. -           generator->backed_up_arg_types_stack_count =
  951. -               EG(arg_types_stack).top - original_arg_types_stack_count;
  952. -
  953. -           generator->backed_up_arg_types_stack = emalloc(generator->backed_up_arg_types_stack_count * sizeof(void *));
  954. -           zend_ptr_stack_pop_into_memory(
  955. -               &EG(arg_types_stack),
  956. -               generator->backed_up_arg_types_stack_count,
  957. -               generator->backed_up_arg_types_stack
  958. -           );
  959. -       }
  960. +       EG(argument_stack) = original_stack;
  961.  
  962.         /* If an exception was thrown in the generator we have to internally
  963.          * rethrow it in the parent scope. */
  964. @@ -741,21 +643,11 @@ ZEND_METHOD(Generator, __wakeup)
  965.  
  966.  /* get_iterator implementation */
  967.  
  968. -typedef struct _zend_generator_iterator {
  969. -   zend_object_iterator intern;
  970. -
  971. -   /* The generator object zval has to be stored, because the iterator is
  972. -    * holding a ref to it, which has to be dtored. */
  973. -   zval *object;
  974. -} zend_generator_iterator;
  975. -
  976.  static void zend_generator_iterator_dtor(zend_object_iterator *iterator TSRMLS_DC) /* {{{ */
  977.  {
  978.     zval *object = ((zend_generator_iterator *) iterator)->object;
  979.  
  980.     zval_ptr_dtor(&object);
  981. -
  982. -   efree(iterator);
  983.  }
  984.  /* }}} */
  985.  
  986. @@ -854,7 +746,7 @@ zend_object_iterator *zend_generator_get_iterator(zend_class_entry *ce, zval *ob
  987.         return NULL;
  988.     }
  989.  
  990. -   iterator = emalloc(sizeof(zend_generator_iterator));
  991. +   iterator = &generator->iterator;
  992.     iterator->intern.funcs = &zend_generator_iterator_functions;
  993.     iterator->intern.data = (void *) generator;
  994.  
  995. diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h
  996. index 3dc3e6f..90f8160 100644
  997. --- a/Zend/zend_generators.h
  998. +++ b/Zend/zend_generators.h
  999. @@ -25,25 +25,24 @@ BEGIN_EXTERN_C()
  1000.  extern ZEND_API zend_class_entry *zend_ce_generator;
  1001.  END_EXTERN_C()
  1002.  
  1003. +typedef struct _zend_generator_iterator {
  1004. +   zend_object_iterator intern;
  1005. +
  1006. +   /* The generator object zval has to be stored, because the iterator is
  1007. +    * holding a ref to it, which has to be dtored. */
  1008. +   zval *object;
  1009. +} zend_generator_iterator;
  1010. +
  1011.  typedef struct _zend_generator {
  1012.     zend_object std;
  1013.  
  1014. +   zend_generator_iterator iterator;
  1015. +
  1016.     /* The suspended execution context. */
  1017.     zend_execute_data *execute_data;
  1018.  
  1019. -   /* If the execution is suspended during a function call there may be
  1020. -    * arguments pushed to the stack, so it has to be backed up. */
  1021. -   void *backed_up_stack;
  1022. -   size_t backed_up_stack_size;
  1023. -
  1024. -   /* For method calls PHP also pushes various type information on a second
  1025. -    * stack, which also needs to be backed up. */
  1026. -   void **backed_up_arg_types_stack;
  1027. -   int backed_up_arg_types_stack_count;
  1028. -
  1029. -   /* The original stack top before resuming the generator. This is required
  1030. -    * for proper cleanup during exception handling. */
  1031. -   void **original_stack_top;
  1032. +   /* The separate stack used by generator */
  1033. +   zend_vm_stack stack;
  1034.  
  1035.     /* Current value */
  1036.     zval *value;
  1037. diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h
  1038. index e5aba0d..6ad9768 100644
  1039. --- a/Zend/zend_globals.h
  1040. +++ b/Zend/zend_globals.h
  1041. @@ -167,8 +167,6 @@ struct _zend_executor_globals {
  1042.     zval error_zval;
  1043.     zval *error_zval_ptr;
  1044.  
  1045. -   zend_ptr_stack arg_types_stack;
  1046. -
  1047.     /* symbol table cache */
  1048.     HashTable *symtable_cache[SYMTABLE_CACHE_SIZE];
  1049.     HashTable **symtable_cache_limit;
  1050. diff --git a/Zend/zend_modules.h b/Zend/zend_modules.h
  1051. index 442535b..bfea3e0 100644
  1052. --- a/Zend/zend_modules.h
  1053. +++ b/Zend/zend_modules.h
  1054. @@ -33,7 +33,7 @@
  1055.  #define ZEND_MODULE_INFO_FUNC_ARGS zend_module_entry *zend_module TSRMLS_DC
  1056.  #define ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU zend_module TSRMLS_CC
  1057.  
  1058. -#define ZEND_MODULE_API_NO 20121113
  1059. +#define ZEND_MODULE_API_NO 20121128
  1060.  #ifdef ZTS
  1061.  #define USING_ZTS 1
  1062.  #else
  1063. diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
  1064. index 563c843..2fd8f52 100644
  1065. --- a/Zend/zend_opcode.c
  1066. +++ b/Zend/zend_opcode.c
  1067. @@ -70,6 +70,9 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz
  1068.  
  1069.     op_array->T = 0;
  1070.  
  1071. +   op_array->nested_calls = 0;
  1072. +   op_array->used_stack = 0;
  1073. +
  1074.     op_array->function_name = NULL;
  1075.     op_array->filename = zend_get_compiled_filename(TSRMLS_C);
  1076.     op_array->doc_comment = NULL;
  1077. @@ -541,6 +544,15 @@ static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num,
  1078.  
  1079.             /* generate a FAST_CALL to finaly block */
  1080.             start_op = get_next_op_number(op_array);
  1081. +
  1082. +           if (op_array->opcodes[op_num].opcode == ZEND_YIELD) {
  1083. +               /* Disable yield in finally block */
  1084. +               opline = get_next_op(op_array TSRMLS_CC);
  1085. +               opline->opcode = ZEND_GENERATOR_FLAG;
  1086. +               opline->extended_value = 1;
  1087. +               SET_UNUSED(opline->op1);
  1088. +               SET_UNUSED(opline->op2);
  1089. +           }
  1090.             opline = get_next_op(op_array TSRMLS_CC);
  1091.             opline->opcode = ZEND_FAST_CALL;
  1092.             SET_UNUSED(opline->op1);
  1093. @@ -567,6 +579,14 @@ static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num,
  1094.                     opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
  1095.                 }
  1096.             }
  1097. +           if (op_array->opcodes[op_num].opcode == ZEND_YIELD) {
  1098. +               /* Re-enable yield */
  1099. +               opline = get_next_op(op_array TSRMLS_CC);
  1100. +               opline->opcode = ZEND_GENERATOR_FLAG;
  1101. +               opline->extended_value = 0;
  1102. +               SET_UNUSED(opline->op1);
  1103. +               SET_UNUSED(opline->op2);
  1104. +           }
  1105.  
  1106.             /* Finish the sequence with original opcode */
  1107.             opline = get_next_op(op_array TSRMLS_CC);
  1108. @@ -622,6 +642,7 @@ static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC)
  1109.         switch (opline->opcode) {
  1110.             case ZEND_RETURN:
  1111.             case ZEND_RETURN_BY_REF:
  1112. +           case ZEND_YIELD:
  1113.                 zend_resolve_finally_call(op_array, i, (zend_uint)-1 TSRMLS_CC);
  1114.                 break;
  1115.             case ZEND_BRK:
  1116. diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
  1117. index 4ae4ca1..966827d 100644
  1118. --- a/Zend/zend_vm_def.h
  1119. +++ b/Zend/zend_vm_def.h
  1120. @@ -1161,7 +1161,7 @@ ZEND_VM_HANDLER(92, ZEND_FETCH_FUNC_ARG, CONST|TMP|VAR|CV, UNUSED|CONST|VAR)
  1121.     USE_OPLINE
  1122.  
  1123.     ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type,
  1124. -       ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R);
  1125. +       ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R);
  1126.  }
  1127.  
  1128.  ZEND_VM_HANDLER(95, ZEND_FETCH_UNSET, CONST|TMP|VAR|CV, UNUSED|CONST|VAR)
  1129. @@ -1283,7 +1283,7 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
  1130.  
  1131.     SAVE_OPLINE();
  1132.  
  1133. -   if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) {
  1134. +   if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) {
  1135.         container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
  1136.         if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
  1137.             zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
  1138. @@ -1519,7 +1519,7 @@ ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, VAR|UNUSED|CV, CONST|TMP|VAR|CV)
  1139.  {
  1140.     USE_OPLINE
  1141.  
  1142. -   if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) {
  1143. +   if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) {
  1144.         /* Behave like FETCH_OBJ_W */
  1145.         zend_free_op free_op1, free_op2;
  1146.         zval *property;
  1147. @@ -1889,7 +1889,6 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
  1148.  
  1149.             EX(function_state).function = (zend_function *) EX(op_array);
  1150.             EX(function_state).arguments = NULL;
  1151. -           EX(object) = EX(current_object);
  1152.  
  1153.             EG(opline_ptr) = &EX(opline);
  1154.             EG(active_op_array) = EX(op_array);
  1155. @@ -1925,8 +1924,8 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
  1156.             EX(function_state).arguments = NULL;
  1157.  
  1158.             if (EG(This)) {
  1159. -               if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) {
  1160. -                   if (IS_CTOR_USED(EX(called_scope))) {
  1161. +               if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) {
  1162. +                   if (EX(call)->is_ctor_result_used) {
  1163.                         Z_DELREF_P(EG(This));
  1164.                     }
  1165.                     if (Z_REFCOUNT_P(EG(This)) == 1) {
  1166. @@ -1939,8 +1938,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
  1167.             EG(scope) = EX(current_scope);
  1168.             EG(called_scope) = EX(current_called_scope);
  1169.  
  1170. -           EX(object) = EX(current_object);
  1171. -           EX(called_scope) = DECODE_CTOR(EX(called_scope));
  1172. +           EX(call)--;
  1173.  
  1174.             zend_vm_stack_clear_multiple(TSRMLS_C);
  1175.  
  1176. @@ -1966,6 +1964,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
  1177.     zend_function *fbc = EX(function_state).function;
  1178.  
  1179.     SAVE_OPLINE();
  1180. +   EX(object) = EX(call)->object;
  1181.     if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) {
  1182.         if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) {
  1183.             zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name, fbc->common.function_name);
  1184. @@ -2000,11 +1999,11 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
  1185.         EX(current_called_scope) = EG(called_scope);
  1186.         EG(This) = EX(object);
  1187.         EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ? fbc->common.scope : NULL;
  1188. -       EG(called_scope) = EX(called_scope);
  1189. +       EG(called_scope) = EX(call)->called_scope;
  1190.     }
  1191.  
  1192. -   zend_arg_types_stack_3_pop(&EG(arg_types_stack), &EX(called_scope), &EX(current_object), &EX(fbc));
  1193. -   EX(function_state).arguments = zend_vm_stack_push_args(opline->extended_value TSRMLS_CC);
  1194. +   EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C);
  1195. +   zend_vm_stack_push((void*)(zend_uintptr_t)opline->extended_value TSRMLS_CC);
  1196.     LOAD_OPLINE();
  1197.  
  1198.     if (fbc->type == ZEND_INTERNAL_FUNCTION) {
  1199. @@ -2054,7 +2053,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
  1200.             if (RETURN_VALUE_USED(opline)) {
  1201.                 EX_T(opline->result.var).var.ptr = zend_generator_create_zval(EG(active_op_array) TSRMLS_CC);
  1202.             }
  1203. -       } else if (EXPECTED(zend_execute == execute)) {
  1204. +       } else if (EXPECTED(zend_execute_ex == execute_ex)) {
  1205.             if (EXPECTED(EG(exception) == NULL)) {
  1206.                 ZEND_VM_ENTER();
  1207.             }
  1208. @@ -2100,8 +2099,8 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
  1209.  
  1210.     if (should_change_scope) {
  1211.         if (EG(This)) {
  1212. -           if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) {
  1213. -               if (IS_CTOR_USED(EX(called_scope))) {
  1214. +           if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) {
  1215. +               if (EX(call)->is_ctor_result_used) {
  1216.                     Z_DELREF_P(EG(This));
  1217.                 }
  1218.                 if (Z_REFCOUNT_P(EG(This)) == 1) {
  1219. @@ -2115,8 +2114,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
  1220.         EG(called_scope) = EX(current_called_scope);
  1221.     }
  1222.  
  1223. -   EX(object) = EX(current_object);
  1224. -   EX(called_scope) = DECODE_CTOR(EX(called_scope));
  1225. +   EX(call)--;
  1226.  
  1227.     zend_vm_stack_clear_multiple(TSRMLS_C);
  1228.  
  1229. @@ -2463,9 +2461,9 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV)
  1230.     char *function_name_strval;
  1231.     int function_name_strlen;
  1232.     zend_free_op free_op1, free_op2;
  1233. +   call_slot *call = EX(call_slots) + opline->result.num;
  1234.  
  1235.     SAVE_OPLINE();
  1236. -   zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
  1237.  
  1238.     function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
  1239.  
  1240. @@ -2477,49 +2475,51 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV)
  1241.     function_name_strval = Z_STRVAL_P(function_name);
  1242.     function_name_strlen = Z_STRLEN_P(function_name);
  1243.  
  1244. -   EX(object) = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R);
  1245. +   call->object = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R);
  1246.  
  1247. -   if (EXPECTED(EX(object) != NULL) &&
  1248. -       EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) {
  1249. -       EX(called_scope) = Z_OBJCE_P(EX(object));
  1250. +   if (EXPECTED(call->object != NULL) &&
  1251. +       EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) {
  1252. +       call->called_scope = Z_OBJCE_P(call->object);
  1253.  
  1254.         if (OP2_TYPE != IS_CONST ||
  1255. -           (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) {
  1256. -           zval *object = EX(object);
  1257. +           (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) {
  1258. +           zval *object = call->object;
  1259.  
  1260. -           if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) {
  1261. +           if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) {
  1262.                 zend_error_noreturn(E_ERROR, "Object does not support method calls");
  1263.             }
  1264.  
  1265.             /* First, locate the function. */
  1266. -           EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((OP2_TYPE == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC);
  1267. -           if (UNEXPECTED(EX(fbc) == NULL)) {
  1268. -               zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval);
  1269. +           call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((OP2_TYPE == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC);
  1270. +           if (UNEXPECTED(call->fbc == NULL)) {
  1271. +               zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval);
  1272.             }
  1273.             if (OP2_TYPE == IS_CONST &&
  1274. -               EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) &&
  1275. -               EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
  1276. -               EXPECTED(EX(object) == object)) {
  1277. -               CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc));
  1278. +               EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) &&
  1279. +               EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
  1280. +               EXPECTED(call->object == object)) {
  1281. +               CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc);
  1282.             }
  1283.         }
  1284.     } else {
  1285.         zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
  1286.     }
  1287.  
  1288. -   if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) {
  1289. -       EX(object) = NULL;
  1290. +   if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
  1291. +       call->object = NULL;
  1292.     } else {
  1293. -       if (!PZVAL_IS_REF(EX(object))) {
  1294. -           Z_ADDREF_P(EX(object)); /* For $this pointer */
  1295. +       if (!PZVAL_IS_REF(call->object)) {
  1296. +           Z_ADDREF_P(call->object); /* For $this pointer */
  1297.         } else {
  1298.             zval *this_ptr;
  1299.             ALLOC_ZVAL(this_ptr);
  1300. -           INIT_PZVAL_COPY(this_ptr, EX(object));
  1301. +           INIT_PZVAL_COPY(this_ptr, call->object);
  1302.             zval_copy_ctor(this_ptr);
  1303. -           EX(object) = this_ptr;
  1304. +           call->object = this_ptr;
  1305.         }
  1306.     }
  1307. +   call->is_ctor_call = 0;
  1308. +   EX(call) = call;
  1309.  
  1310.     FREE_OP2();
  1311.     FREE_OP1_IF_VAR();
  1312. @@ -2533,9 +2533,9 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS
  1313.     USE_OPLINE
  1314.     zval *function_name;
  1315.     zend_class_entry *ce;
  1316. +   call_slot *call = EX(call_slots) + opline->result.num;
  1317.  
  1318.     SAVE_OPLINE();
  1319. -   zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
  1320.  
  1321.     if (OP1_TYPE == IS_CONST) {
  1322.         /* no function found. try a static method in class */
  1323. @@ -2549,24 +2549,24 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS
  1324.             }
  1325.             CACHE_PTR(opline->op1.literal->cache_slot, ce);
  1326.         }
  1327. -       EX(called_scope) = ce;
  1328. +       call->called_scope = ce;
  1329.     } else {
  1330.         ce = EX_T(opline->op1.var).class_entry;
  1331.  
  1332.         if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) {
  1333. -           EX(called_scope) = EG(called_scope);
  1334. +           call->called_scope = EG(called_scope);
  1335.         } else {
  1336. -           EX(called_scope) = ce;
  1337. +           call->called_scope = ce;
  1338.         }
  1339.     }
  1340.  
  1341.     if (OP1_TYPE == IS_CONST &&
  1342.         OP2_TYPE == IS_CONST &&
  1343.         CACHED_PTR(opline->op2.literal->cache_slot)) {
  1344. -       EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot);
  1345. +       call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
  1346.     } else if (OP1_TYPE != IS_CONST &&
  1347.                OP2_TYPE == IS_CONST &&
  1348. -              (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) {
  1349. +              (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) {
  1350.         /* do nothing */
  1351.     } else if (OP2_TYPE != IS_UNUSED) {
  1352.         char *function_name_strval = NULL;
  1353. @@ -2589,20 +2589,20 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS
  1354.  
  1355.         if (function_name_strval) {
  1356.             if (ce->get_static_method) {
  1357. -               EX(fbc) = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC);
  1358. +               call->fbc = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC);
  1359.             } else {
  1360. -               EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((OP2_TYPE == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC);
  1361. +               call->fbc = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((OP2_TYPE == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC);
  1362.             }
  1363. -           if (UNEXPECTED(EX(fbc) == NULL)) {
  1364. +           if (UNEXPECTED(call->fbc == NULL)) {
  1365.                 zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);
  1366.             }
  1367.             if (OP2_TYPE == IS_CONST &&
  1368. -               EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) &&
  1369. -               EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
  1370. +               EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) &&
  1371. +               EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
  1372.                 if (OP1_TYPE == IS_CONST) {
  1373. -                   CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
  1374. +                   CACHE_PTR(opline->op2.literal->cache_slot, call->fbc);
  1375.                 } else {
  1376. -                   CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc));
  1377. +                   CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, call->fbc);
  1378.                 }
  1379.             }
  1380.         }
  1381. @@ -2616,29 +2616,31 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS
  1382.         if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) {
  1383.             zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name);
  1384.         }
  1385. -       EX(fbc) = ce->constructor;
  1386. +       call->fbc = ce->constructor;
  1387.     }
  1388.  
  1389. -   if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
  1390. -       EX(object) = NULL;
  1391. +   if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) {
  1392. +       call->object = NULL;
  1393.     } else {
  1394.         if (EG(This) &&
  1395.             Z_OBJ_HT_P(EG(This))->get_class_entry &&
  1396.             !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) {
  1397.             /* We are calling method of the other (incompatible) class,
  1398.                but passing $this. This is done for compatibility with php-4. */
  1399. -           if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
  1400. -               zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name);
  1401. +           if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
  1402. +               zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", call->fbc->common.scope->name, call->fbc->common.function_name);
  1403.             } else {
  1404.                 /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */
  1405. -               zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name);
  1406. +               zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically, assuming $this from incompatible context", call->fbc->common.scope->name, call->fbc->common.function_name);
  1407.             }
  1408.         }
  1409. -       if ((EX(object) = EG(This))) {
  1410. -           Z_ADDREF_P(EX(object));
  1411. -           EX(called_scope) = Z_OBJCE_P(EX(object));
  1412. +       if ((call->object = EG(This))) {
  1413. +           Z_ADDREF_P(call->object);
  1414. +           call->called_scope = Z_OBJCE_P(call->object);
  1415.         }
  1416.     }
  1417. +   call->is_ctor_call = 0;
  1418. +   EX(call) = call;
  1419.  
  1420.     CHECK_EXCEPTION();
  1421.     ZEND_VM_NEXT_OPCODE();
  1422. @@ -2648,19 +2650,21 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
  1423.  {
  1424.     USE_OPLINE
  1425.     zval *function_name;
  1426. -   zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
  1427. +   call_slot *call = EX(call_slots) + opline->result.num;
  1428.  
  1429.     if (OP2_TYPE == IS_CONST) {
  1430.         function_name = (zval*)(opline->op2.literal+1);
  1431.         if (CACHED_PTR(opline->op2.literal->cache_slot)) {
  1432. -           EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot);
  1433. -       } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &EX(fbc)) == FAILURE)) {
  1434. +           call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
  1435. +       } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &call->fbc) == FAILURE)) {
  1436.             SAVE_OPLINE();
  1437.             zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
  1438.         } else {
  1439. -           CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
  1440. +           CACHE_PTR(opline->op2.literal->cache_slot, call->fbc);
  1441.         }
  1442. -       EX(object) = NULL;
  1443. +       call->object = NULL;
  1444. +       call->is_ctor_call = 0;
  1445. +       EX(call) = call;
  1446.         /*CHECK_EXCEPTION();*/
  1447.         ZEND_VM_NEXT_OPCODE();
  1448.     } else {
  1449. @@ -2680,28 +2684,32 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
  1450.             } else {
  1451.                 lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen);
  1452.             }
  1453. -           if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &EX(fbc)) == FAILURE)) {
  1454. +           if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) {
  1455.                 zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval);
  1456.             }
  1457.             efree(lcname);
  1458.             FREE_OP2();
  1459. -           EX(object) = NULL;
  1460. +           call->object = NULL;
  1461. +           call->is_ctor_call = 0;
  1462. +           EX(call) = call;
  1463.             CHECK_EXCEPTION();
  1464.             ZEND_VM_NEXT_OPCODE();
  1465.         } else if (OP2_TYPE != IS_CONST && OP2_TYPE != IS_TMP_VAR &&
  1466.             EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
  1467.             Z_OBJ_HANDLER_P(function_name, get_closure) &&
  1468. -           Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) {
  1469. -           if (EX(object)) {
  1470. -               Z_ADDREF_P(EX(object));
  1471. +           Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) {
  1472. +           if (call->object) {
  1473. +               Z_ADDREF_P(call->object);
  1474.             }
  1475.             if (OP2_TYPE == IS_VAR && OP2_FREE &&
  1476. -               EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) {
  1477. +               call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) {
  1478.                 /* Delay closure destruction until its invocation */
  1479. -               EX(fbc)->common.prototype = (zend_function*)function_name;
  1480. +               call->fbc->common.prototype = (zend_function*)function_name;
  1481.             } else {
  1482.                 FREE_OP2();
  1483.             }
  1484. +           call->is_ctor_call = 0;
  1485. +           EX(call) = call;
  1486.             CHECK_EXCEPTION();
  1487.             ZEND_VM_NEXT_OPCODE();
  1488.         } else if (OP2_TYPE != IS_CONST &&
  1489. @@ -2732,41 +2740,43 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
  1490.                     CHECK_EXCEPTION();
  1491.                     ZEND_VM_NEXT_OPCODE();
  1492.                 }
  1493. -               EX(called_scope) = ce;
  1494. -               EX(object) = NULL;
  1495. +               call->called_scope = ce;
  1496. +               call->object = NULL;
  1497.  
  1498.                 if (ce->get_static_method) {
  1499. -                   EX(fbc) = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC);
  1500. +                   call->fbc = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC);
  1501.                 } else {
  1502. -                   EX(fbc) = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
  1503. +                   call->fbc = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
  1504.                 }
  1505.             } else {
  1506. -               EX(object) = *obj;
  1507. -               ce = EX(called_scope) = Z_OBJCE_PP(obj);
  1508. +               call->object = *obj;
  1509. +               ce = call->called_scope = Z_OBJCE_PP(obj);
  1510.  
  1511. -               EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
  1512. -               if (UNEXPECTED(EX(fbc) == NULL)) {
  1513. -                   zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method));
  1514. +               call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC);
  1515. +               if (UNEXPECTED(call->fbc == NULL)) {
  1516. +                   zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_PP(method));
  1517.                 }
  1518.  
  1519. -               if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) {
  1520. -                   EX(object) = NULL;
  1521. +               if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
  1522. +                   call->object = NULL;
  1523.                 } else {
  1524. -                   if (!PZVAL_IS_REF(EX(object))) {
  1525. -                       Z_ADDREF_P(EX(object)); /* For $this pointer */
  1526. +                   if (!PZVAL_IS_REF(call->object)) {
  1527. +                       Z_ADDREF_P(call->object); /* For $this pointer */
  1528.                     } else {
  1529.                         zval *this_ptr;
  1530.                         ALLOC_ZVAL(this_ptr);
  1531. -                       INIT_PZVAL_COPY(this_ptr, EX(object));
  1532. +                       INIT_PZVAL_COPY(this_ptr, call->object);
  1533.                         zval_copy_ctor(this_ptr);
  1534. -                       EX(object) = this_ptr;
  1535. +                       call->object = this_ptr;
  1536.                     }
  1537.                 }
  1538.             }
  1539.  
  1540. -           if (UNEXPECTED(EX(fbc) == NULL)) {
  1541. +           if (UNEXPECTED(call->fbc == NULL)) {
  1542.                 zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method));
  1543.             }
  1544. +           call->is_ctor_call = 0;
  1545. +           EX(call) = call;
  1546.             FREE_OP2();
  1547.             CHECK_EXCEPTION();
  1548.             ZEND_VM_NEXT_OPCODE();
  1549. @@ -2781,31 +2791,32 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST)
  1550.  {
  1551.     USE_OPLINE
  1552.     zend_literal *func_name;
  1553. -
  1554. -   zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
  1555. +   call_slot *call = EX(call_slots) + opline->result.num;
  1556.  
  1557.     func_name = opline->op2.literal + 1;
  1558.     if (CACHED_PTR(opline->op2.literal->cache_slot)) {
  1559. -       EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot);
  1560. -   } else if (zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &EX(fbc))==FAILURE) {
  1561. +       call->fbc = CACHED_PTR(opline->op2.literal->cache_slot);
  1562. +   } else if (zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &call->fbc)==FAILURE) {
  1563.         func_name++;
  1564. -       if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &EX(fbc))==FAILURE)) {
  1565. +       if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL(func_name->constant), Z_STRLEN(func_name->constant)+1, func_name->hash_value, (void **) &call->fbc)==FAILURE)) {
  1566.             SAVE_OPLINE();
  1567.             zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
  1568.         } else {
  1569. -           CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
  1570. +           CACHE_PTR(opline->op2.literal->cache_slot, call->fbc);
  1571.         }
  1572.     } else {
  1573. -       CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
  1574. +       CACHE_PTR(opline->op2.literal->cache_slot, call->fbc);
  1575.     }
  1576.  
  1577. -   EX(object) = NULL;
  1578. +   call->object = NULL;
  1579. +   call->is_ctor_call = 0;
  1580. +   EX(call) = call;
  1581.     ZEND_VM_NEXT_OPCODE();
  1582.  }
  1583.  
  1584.  ZEND_VM_HANDLER(61, ZEND_DO_FCALL_BY_NAME, ANY, ANY)
  1585.  {
  1586. -   EX(function_state).function = EX(fbc);
  1587. +   EX(function_state).function = EX(call)->fbc;
  1588.     ZEND_VM_DISPATCH_TO_HELPER(zend_do_fcall_common_helper);
  1589.  }
  1590.  
  1591. @@ -2814,8 +2825,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY)
  1592.     USE_OPLINE
  1593.     zend_free_op free_op1;
  1594.     zval *fname = GET_OP1_ZVAL_PTR(BP_VAR_R);
  1595. -
  1596. -   zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
  1597. +   call_slot *call = EX(call_slots) + opline->op2.num;
  1598.  
  1599.     if (CACHED_PTR(opline->op1.literal->cache_slot)) {
  1600.         EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot);
  1601. @@ -2825,7 +2835,10 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY)
  1602.     } else {
  1603.         CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function);
  1604.     }
  1605. -   EX(object) = NULL;
  1606. +   call->fbc = EX(function_state).function;
  1607. +   call->object = NULL;
  1608. +   call->is_ctor_call = 0;
  1609. +   EX(call) = call;
  1610.  
  1611.     FREE_OP1();
  1612.  
  1613. @@ -3052,7 +3065,7 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, ANY)
  1614.  
  1615.     SAVE_OPLINE();
  1616.     if (opline->extended_value==ZEND_DO_FCALL_BY_NAME
  1617. -       && ARG_MUST_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) {
  1618. +       && ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) {
  1619.             zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.opline_num);
  1620.     }
  1621.     {
  1622. @@ -3113,7 +3126,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY)
  1623.         if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) {
  1624.             ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper);
  1625.         }
  1626. -   } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) {
  1627. +   } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) {
  1628.         ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper);
  1629.     }
  1630.  
  1631. @@ -3139,7 +3152,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY)
  1632.  
  1633.         if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ?
  1634.             !(opline->extended_value & ZEND_ARG_SEND_SILENT) :
  1635. -           !ARG_MAY_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) {
  1636. +           !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) {
  1637.             zend_error(E_STRICT, "Only variables should be passed by reference");
  1638.         }
  1639.         ALLOC_ZVAL(valptr);
  1640. @@ -3175,7 +3188,7 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY)
  1641.         ZEND_VM_NEXT_OPCODE();
  1642.     }
  1643.  
  1644. -   if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && !ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) {
  1645. +   if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && !ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) {
  1646.         ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper);
  1647.     }
  1648.  
  1649. @@ -3194,7 +3207,7 @@ ZEND_VM_HANDLER(66, ZEND_SEND_VAR, VAR|CV, ANY)
  1650.     USE_OPLINE
  1651.  
  1652.     if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME)
  1653. -       && ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) {
  1654. +       && ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) {
  1655.         ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF);
  1656.     }
  1657.     SAVE_OPLINE();
  1658. @@ -3400,17 +3413,20 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY)
  1659.         }
  1660.         ZEND_VM_JMP(EX(op_array)->opcodes + opline->op2.opline_num);
  1661.     } else {
  1662. +       call_slot *call = EX(call_slots) + opline->extended_value;
  1663. +
  1664.         if (RETURN_VALUE_USED(opline)) {
  1665.             PZVAL_LOCK(object_zval);
  1666.             AI_SET_PTR(&EX_T(opline->result.var), object_zval);
  1667.         }
  1668.  
  1669. -       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), ENCODE_CTOR(EX(called_scope), RETURN_VALUE_USED(opline)));
  1670. -
  1671.         /* We are not handling overloaded classes right now */
  1672. -       EX(object) = object_zval;
  1673. -       EX(fbc) = constructor;
  1674. -       EX(called_scope) = EX_T(opline->op1.var).class_entry;
  1675. +       call->fbc = constructor;
  1676. +       call->object = object_zval;
  1677. +       call->called_scope = EX_T(opline->op1.var).class_entry;
  1678. +       call->is_ctor_call = 1;
  1679. +       call->is_ctor_result_used = RETURN_VALUE_USED(opline);
  1680. +       EX(call) = call;
  1681.  
  1682.         CHECK_EXCEPTION();
  1683.         ZEND_VM_NEXT_OPCODE();
  1684. @@ -3829,8 +3845,6 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY)
  1685.             EG(return_value_ptr_ptr) = NULL;
  1686.         }
  1687.  
  1688. -       EX(current_object) = EX(object);
  1689. -
  1690.         EX(function_state).function = (zend_function *) new_op_array;
  1691.         EX(object) = NULL;
  1692.  
  1693. @@ -3838,14 +3852,13 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY)
  1694.             zend_rebuild_symbol_table(TSRMLS_C);
  1695.         }
  1696.  
  1697. -       if (EXPECTED(zend_execute == execute)) {
  1698. +       if (EXPECTED(zend_execute_ex == execute_ex)) {
  1699.             ZEND_VM_ENTER();
  1700.         } else {
  1701.             zend_execute(new_op_array TSRMLS_CC);
  1702.         }
  1703.  
  1704.         EX(function_state).function = (zend_function *) EX(op_array);
  1705. -       EX(object) = EX(current_object);
  1706.  
  1707.         EG(opline_ptr) = &EX(opline);
  1708.         EG(active_op_array) = EX(op_array);
  1709. @@ -5022,19 +5035,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
  1710.  
  1711.     /* Figure out where the next stack frame (which maybe contains pushed
  1712.      * arguments that have to be dtor'ed) starts */
  1713. -   if (EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) {
  1714. -       /* The generator object is stored in return_value_ptr_ptr */
  1715. -       zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
  1716. -
  1717. -       /* For generators the next stack frame is conveniently stored in the
  1718. -        * generator object. */
  1719. -       stack_frame = generator->original_stack_top;
  1720. -   } else {
  1721. -       /* In all other cases the next stack frame starts after the temporary
  1722. -        * variables section of the current execution context */
  1723. -       stack_frame = (void **) ((char *) EX_Ts() +
  1724. -           ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * EX(op_array)->T);
  1725. -   }
  1726. +   stack_frame = zend_vm_stack_frame_base(EXECUTE_DATA);
  1727.  
  1728.     /* If the exception was thrown during a function call there might be
  1729.      * arguments pushed to the stack that have to be dtor'ed. */
  1730. @@ -5056,21 +5057,23 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
  1731.         }
  1732.     }
  1733.  
  1734. -   while (EX(fbc)) {
  1735. -       EX(called_scope) = (zend_class_entry*)zend_ptr_stack_pop(&EG(arg_types_stack));
  1736. -       if (EX(object)) {
  1737. -           if (IS_CTOR_CALL(EX(called_scope))) {
  1738. -               if (IS_CTOR_USED(EX(called_scope))) {
  1739. -                   Z_DELREF_P(EX(object));
  1740. -               }
  1741. -               if (Z_REFCOUNT_P(EX(object)) == 1) {
  1742. -                   zend_object_store_ctor_failed(EX(object) TSRMLS_CC);
  1743. +   if (EX(call) >= EX(call_slots)) {
  1744. +       call_slot *call = EX(call);
  1745. +       do {
  1746. +           if (call->object) {
  1747. +               if (call->is_ctor_call) {
  1748. +                   if (call->is_ctor_result_used) {
  1749. +                       Z_DELREF_P(call->object);
  1750. +                   }
  1751. +                   if (Z_REFCOUNT_P(call->object) == 1) {
  1752. +                       zend_object_store_ctor_failed(call->object TSRMLS_CC);
  1753. +                   }
  1754.                 }
  1755. +               zval_ptr_dtor(&call->object);
  1756.             }
  1757. -           zval_ptr_dtor(&EX(object));
  1758. -       }
  1759. -       EX(called_scope) = DECODE_CTOR(EX(called_scope));
  1760. -       zend_arg_types_stack_2_pop(&EG(arg_types_stack), &EX(object), &EX(fbc));
  1761. +           call--;
  1762. +       } while (call >= EX(call_slots));
  1763. +       EX(call) = NULL;
  1764.     }
  1765.  
  1766.     for (i=0; i<EX(op_array)->last_brk_cont; i++) {
  1767. @@ -5240,6 +5243,19 @@ ZEND_VM_HANDLER(156, ZEND_SEPARATE, VAR, UNUSED)
  1768.     ZEND_VM_NEXT_OPCODE();
  1769.  }
  1770.  
  1771. +ZEND_VM_HANDLER(159, ZEND_GENERATOR_FLAG, ANY, ANY)
  1772. +{
  1773. +   USE_OPLINE
  1774. +   zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
  1775. +
  1776. +   if (opline->extended_value) {
  1777. +       generator->flags |= ZEND_GENERATOR_FORCED_CLOSE;
  1778. +   } else {
  1779. +       generator->flags &= ~ZEND_GENERATOR_FORCED_CLOSE;
  1780. +   }
  1781. +   ZEND_VM_NEXT_OPCODE();
  1782. +}
  1783. +
  1784.  ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSED)
  1785.  {
  1786.     USE_OPLINE
  1787. diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl
  1788. index e2d5dd1..85d3dfb 100644
  1789. --- a/Zend/zend_vm_execute.skl
  1790. +++ b/Zend/zend_vm_execute.skl
  1791. @@ -1,6 +1,49 @@
  1792.  {%DEFINES%}
  1793.  
  1794. -zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC) {
  1795. +/*  
  1796. + * Stack Frame Layout (the whole stack frame is allocated at once)
  1797. + * ==================
  1798. + *
  1799. + *                             +========================================+
  1800. + *                             | zend_execute_data                      |<---+
  1801. + *                             |     EX(function_state).arguments       |--+ |
  1802. + *                             |  ...                                   |  | |
  1803. + *                             | ARGUMENT [1]                           |  | |
  1804. + *                             | ...                                    |  | |
  1805. + *                             | ARGUMENT [ARGS_NUMBER]                 |  | |
  1806. + *                             | ARGS_NUMBER                            |<-+ |
  1807. + *                             +========================================+    |
  1808. + *                                                                           |
  1809. + *                             +========================================+    |
  1810. + * EG(current_execute_data) -> | zend_execute_data                      |    |
  1811. + *                             |     EX(prev_execute_data)              |----+
  1812. + *                             +----------------------------------------+
  1813. + *           EX(Ts) ---------> | EX(Ts)[0]                              |
  1814. + *                             | ...                                    |
  1815. + *                             | EX(Tx)[op_arrat->T]                    |
  1816. + *                             +----------------------------------------+
  1817. + *           EX(CVs) --------> | EX(CVs)[0]                             |--+
  1818. + *                             | ...                                    |  |
  1819. + *                             | EX(CVs)[op_array->last_var]            |  |
  1820. + *                             +----------------------------------------+  |
  1821. + *                             | Optional slot for CV[0] zval*          |<-+
  1822. + *                             | ...                                    |
  1823. + *                             | ...  for CV [op_array->last_var] zval* |
  1824. + *                             +----------------------------------------+
  1825. + *           EX(call_slots) -> | EX(call_slots)[0]                      |
  1826. + *                             | ...                                    |
  1827. + *                             | EX(call_slots)[op_array->nested_calls] |
  1828. + *                             +----------------------------------------+
  1829. + * zend_vm_stack_frame_base -> | ARGUMENTS STACK [0]                    |
  1830. + *                             | ...                                    |
  1831. + * zend_vm_stack_top --------> | ...                                    |
  1832. + *                             | ...                                    |
  1833. + *                             | ARGUMENTS STACK [op_array->used_stack] |
  1834. + *                             +----------------------------------------+
  1835. + */
  1836. +
  1837. +zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC)
  1838. +{
  1839.     zend_execute_data *execute_data;
  1840.  
  1841.     /*
  1842. @@ -15,7 +58,9 @@ zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_arra
  1843.     size_t execute_data_size = ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data));
  1844.     size_t CVs_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval **) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2));
  1845.     size_t Ts_size = ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T;
  1846. -   size_t total_size = execute_data_size + CVs_size + Ts_size;
  1847. +   size_t call_slots_size = ZEND_MM_ALIGNED_SIZE(sizeof(call_slot)) * op_array->nested_calls;
  1848. +   size_t stack_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * op_array->used_stack;
  1849. +   size_t total_size = execute_data_size + Ts_size + CVs_size + call_slots_size + stack_size;
  1850.  
  1851.     /*
  1852.      * Normally the execute_data is allocated on the VM stack (because it does
  1853. @@ -27,23 +72,58 @@ zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_arra
  1854.      * by replacing a pointer.
  1855.      */
  1856.     if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
  1857. -       execute_data = emalloc(total_size);
  1858. +       /* Prepend the regular stack frame with copy on prev_execute_data
  1859. +        * and passed arguments
  1860. +        */
  1861. +       int args_count = zend_vm_stack_get_args_count_ex(EG(current_execute_data));
  1862. +       size_t args_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * (args_count + 1);
  1863. +
  1864. +       total_size += args_size + execute_data_size;
  1865. +
  1866. +       EG(argument_stack) = zend_vm_stack_new_page((total_size + (sizeof(void*) - 1)) / sizeof(void*));
  1867. +       EG(argument_stack)->prev = NULL;
  1868. +       execute_data = (zend_execute_data*)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + args_size + execute_data_size);
  1869. +
  1870. +       /* copy prev_execute_data */
  1871. +       EX(prev_execute_data) = (zend_execute_data*)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + args_size);
  1872. +       memset(EX(prev_execute_data), 0, sizeof(zend_execute_data));
  1873. +       EX(prev_execute_data)->function_state.function = (zend_function*)op_array;
  1874. +       EX(prev_execute_data)->function_state.arguments = (void**)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * args_count);
  1875. +
  1876. +       /* copy arguemnts */
  1877. +       *EX(prev_execute_data)->function_state.arguments = (void*)(zend_uintptr_t)args_count;
  1878. +       if (args_count > 0) {
  1879. +           zval **arg_src = (zval**)zend_vm_stack_get_arg_ex(EG(current_execute_data), 1);
  1880. +           zval **arg_dst = (zval**)zend_vm_stack_get_arg_ex(EX(prev_execute_data), 1);
  1881. +           int i;
  1882. +
  1883. +           for (i = 0; i < args_count; i++) {
  1884. +               arg_dst[i] = arg_src[i];
  1885. +               Z_ADDREF_P(arg_dst[i]);
  1886. +           }
  1887. +       }
  1888.     } else {
  1889.         execute_data = zend_vm_stack_alloc(total_size TSRMLS_CC);
  1890. +       EX(prev_execute_data) = EG(current_execute_data);
  1891.     }
  1892.  
  1893. -   EX(CVs) = (zval ***) ((char *) execute_data + execute_data_size);
  1894. +   EX(Ts) = (temp_variable *) ((char *) execute_data + execute_data_size);
  1895. +
  1896. +   EX(CVs) = (zval ***) ((char *) EX(Ts) + Ts_size);
  1897.     memset(EX(CVs), 0, sizeof(zval **) * op_array->last_var);
  1898.  
  1899. -   EX(Ts) = (temp_variable *) ((char *) EX(CVs) + CVs_size);
  1900. +   EX(call_slots) = (call_slot*)((char *) EX(CVs) + CVs_size);
  1901. +
  1902. +
  1903. +   EX(op_array) = op_array;
  1904. +
  1905. +   EG(argument_stack)->top = zend_vm_stack_frame_base(execute_data);
  1906.  
  1907. -   EX(fbc) = NULL;
  1908. -   EX(called_scope) = NULL;
  1909.     EX(object) = NULL;
  1910. +   EX(current_this) = NULL;
  1911.     EX(old_error_reporting) = NULL;
  1912. -   EX(op_array) = op_array;
  1913.     EX(symbol_table) = EG(active_symbol_table);
  1914. -   EX(prev_execute_data) = EG(current_execute_data);
  1915. +   EX(call) = NULL;
  1916.     EG(current_execute_data) = execute_data;
  1917.     EX(nested) = nested;
  1918.  
  1919. @@ -103,12 +183,12 @@ ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *execute_data TSRMLS_DC)
  1920.     zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen");
  1921.  }
  1922.  
  1923. -ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC)
  1924. +ZEND_API void zend_{%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC)
  1925.  {
  1926.     if (EG(exception)) {
  1927.         return;
  1928.     }
  1929. -   {%EXECUTOR_NAME%}_ex(zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC) TSRMLS_CC);
  1930. +   zend_{%EXECUTOR_NAME%}_ex(zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC) TSRMLS_CC);
  1931.  }
  1932.  
  1933.  {%EXTERNAL_EXECUTOR%}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement