diff options
author | Dmitry Stogov <dmitry@zend.com> | 2012-11-30 13:39:23 +0400 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2012-11-30 13:39:23 +0400 |
commit | 70f83f35d089d0cafae12ae231a38541f5c8e41c (patch) | |
tree | 1dee0f4716d742a57558d59a9285392805b25a9b /Zend | |
parent | 9f7e53fde8b0feac271230cbc6731e9de90f2a03 (diff) | |
download | php-git-70f83f35d089d0cafae12ae231a38541f5c8e41c.tar.gz |
. The VM stacks for passing function arguments and syntaticaly nested calls were merged into a single stack. The stack size needed for op_array execution is calculated at compile time and preallocated at once. As result all the stack push operatins don't require checks for stack overflow any more.
. Generators implementation was improved using the new VM stack. Now it's a bit more clear and faster.
Diffstat (limited to 'Zend')
-rw-r--r-- | Zend/zend.c | 4 | ||||
-rw-r--r-- | Zend/zend_compile.c | 48 | ||||
-rw-r--r-- | Zend/zend_compile.h | 18 | ||||
-rw-r--r-- | Zend/zend_execute.c | 19 | ||||
-rw-r--r-- | Zend/zend_execute.h | 84 | ||||
-rw-r--r-- | Zend/zend_execute_API.c | 14 | ||||
-rw-r--r-- | Zend/zend_extensions.h | 2 | ||||
-rw-r--r-- | Zend/zend_generators.c | 304 | ||||
-rw-r--r-- | Zend/zend_generators.h | 25 | ||||
-rw-r--r-- | Zend/zend_globals.h | 2 | ||||
-rw-r--r-- | Zend/zend_modules.h | 2 | ||||
-rw-r--r-- | Zend/zend_opcode.c | 21 | ||||
-rw-r--r-- | Zend/zend_ptr_stack.c | 17 | ||||
-rw-r--r-- | Zend/zend_ptr_stack.h | 2 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 294 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 1799 | ||||
-rw-r--r-- | Zend/zend_vm_execute.skl | 102 | ||||
-rw-r--r-- | Zend/zend_vm_opcodes.h | 1 |
18 files changed, 1451 insertions, 1307 deletions
diff --git a/Zend/zend.c b/Zend/zend.c index 9ab879a2a4..fc6aed08cc 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -683,11 +683,11 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions TS #if HAVE_DTRACE /* build with dtrace support */ zend_compile_file = dtrace_compile_file; - zend_execute = dtrace_execute; + zend_execute_ex = dtrace_execute_ex; zend_execute_internal = dtrace_execute_internal; #else zend_compile_file = compile_file; - zend_execute = execute; + zend_execute_ex = execute_ex; zend_execute_internal = NULL; #endif /* HAVE_SYS_SDT_H */ zend_compile_string = compile_string; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index de77068db5..e768996272 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -179,6 +179,8 @@ void zend_init_compiler_context(TSRMLS_D) /* {{{ */ CG(context).literals_size = 0; CG(context).current_brk_cont = -1; CG(context).backpatch_count = 0; + CG(context).nested_calls = 0; + CG(context).used_stack = 0; CG(context).labels = NULL; } /* }}} */ @@ -1950,6 +1952,9 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace function_name->u.constant.value.str.val = lcname; zend_stack_push(&CG(function_call_stack), (void *) &function, sizeof(zend_function *)); + if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) { + CG(active_op_array)->nested_calls = CG(context).nested_calls + 1; + } zend_do_extended_fcall_begin(TSRMLS_C); return 0; } @@ -1988,11 +1993,13 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */ GET_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant); } last_op->opcode = ZEND_INIT_METHOD_CALL; - SET_UNUSED(last_op->result); + last_op->result_type = IS_UNUSED; + last_op->result.num = CG(context).nested_calls; Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME; } else { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_INIT_FCALL_BY_NAME; + opline->result.num = CG(context).nested_calls; SET_UNUSED(opline->op1); if (left_bracket->op_type == IS_CONST) { opline->op2_type = IS_CONST; @@ -2004,6 +2011,9 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */ } zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); + if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { + CG(active_op_array)->nested_calls = CG(context).nested_calls; + } zend_do_extended_fcall_begin(TSRMLS_C); } /* }}} */ @@ -2031,12 +2041,14 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML /* In run-time PHP will check for function with full name and internal function with short name */ opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME; + opline->result.num = CG(context).nested_calls; SET_UNUSED(opline->op1); opline->op2_type = IS_CONST; opline->op2.constant = zend_add_ns_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC); GET_CACHE_SLOT(opline->op2.constant); } else { opline->opcode = ZEND_INIT_FCALL_BY_NAME; + opline->result.num = CG(context).nested_calls; SET_UNUSED(opline->op1); if (function_name->op_type == IS_CONST) { opline->op2_type = IS_CONST; @@ -2048,6 +2060,9 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML } zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); + if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { + CG(active_op_array)->nested_calls = CG(context).nested_calls; + } zend_do_extended_fcall_begin(TSRMLS_C); } /* }}} */ @@ -2395,6 +2410,7 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na opline->extended_value = class_node.EA ; } opline->opcode = ZEND_INIT_STATIC_METHOD_CALL; + opline->result.num = CG(context).nested_calls; if (class_node.op_type == IS_CONST) { opline->op1_type = IS_CONST; opline->op1.constant = @@ -2416,6 +2432,9 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na } zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); + if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { + CG(active_op_array)->nested_calls = CG(context).nested_calls; + } zend_do_extended_fcall_begin(TSRMLS_C); return 1; /* Dynamic */ } @@ -2436,21 +2455,29 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) { opline->opcode = ZEND_DO_FCALL; SET_NODE(opline->op1, function_name); + SET_UNUSED(opline->op2); + opline->op2.num = CG(context).nested_calls; CALCULATE_LITERAL_HASH(opline->op1.constant); GET_CACHE_SLOT(opline->op1.constant); } else { opline->opcode = ZEND_DO_FCALL_BY_NAME; SET_UNUSED(opline->op1); + SET_UNUSED(opline->op2); + opline->op2.num = --CG(context).nested_calls; } } opline->result.var = get_temporary_variable(CG(active_op_array)); opline->result_type = IS_VAR; - GET_NODE(result, opline->result) ; - SET_UNUSED(opline->op2); + GET_NODE(result, opline->result); zend_stack_del_top(&CG(function_call_stack)); opline->extended_value = Z_LVAL(argument_list->u.constant); + + if (CG(context).used_stack + 1 > CG(active_op_array)->used_stack) { + CG(active_op_array)->used_stack = CG(context).used_stack + 1; + } + CG(context).used_stack -= Z_LVAL(argument_list->u.constant); } /* }}} */ @@ -2558,6 +2585,10 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ SET_NODE(opline->op1, param); opline->op2.opline_num = offset; SET_UNUSED(opline->op2); + + if (++CG(context).used_stack > CG(active_op_array)->used_stack) { + CG(active_op_array)->used_stack = CG(context).used_stack; + } } /* }}} */ @@ -5547,12 +5578,16 @@ void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC) /* new_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_NEW; + opline->extended_value = CG(context).nested_calls; opline->result_type = IS_VAR; opline->result.var = get_temporary_variable(CG(active_op_array)); SET_NODE(opline->op1, class_type); SET_UNUSED(opline->op2); zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(unsigned char *)); + if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { + CG(active_op_array)->nested_calls = CG(context).nested_calls; + } } /* }}} */ @@ -5765,6 +5800,13 @@ void zend_do_shell_exec(znode *result, const znode *cmd TSRMLS_DC) /* {{{ */ opline->extended_value = 1; SET_UNUSED(opline->op2); GET_NODE(result, opline->result); + + if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) { + CG(active_op_array)->nested_calls = CG(context).nested_calls + 1; + } + if (CG(context).used_stack + 2 > CG(active_op_array)->used_stack) { + CG(active_op_array)->used_stack = CG(context).used_stack + 2; + } } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index e46c1a39ce..def634175a 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -59,6 +59,8 @@ typedef struct _zend_compiler_context { int literals_size; int current_brk_cont; int backpatch_count; + int nested_calls; + int used_stack; HashTable *labels; } zend_compiler_context; @@ -279,6 +281,9 @@ struct _zend_op_array { zend_uint T; + zend_uint nested_calls; + zend_uint used_stack; + zend_brk_cont_element *brk_cont_array; int last_brk_cont; @@ -369,11 +374,17 @@ typedef struct _list_llist_element { union _temp_variable; +typedef struct _call_slot { + zend_function *fbc; + zval *object; + zend_class_entry *called_scope; + zend_bool is_ctor_call; + zend_bool is_ctor_result_used; +} call_slot; + struct _zend_execute_data { struct _zend_op *opline; zend_function_state function_state; - zend_function *fbc; /* Function Being Called */ - zend_class_entry *called_scope; zend_op_array *op_array; zval *object; union _temp_variable *Ts; @@ -386,8 +397,9 @@ struct _zend_execute_data { zend_class_entry *current_scope; zend_class_entry *current_called_scope; zval *current_this; - zval *current_object; struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */ + call_slot *call_slots; + call_slot *call; }; #define EX(element) execute_data.element diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 361afc6f13..5f04ba7465 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1570,25 +1570,6 @@ void zend_free_compiled_variables(zval ***CVs, int num) /* {{{ */ } /* }}} */ -void** zend_copy_arguments(void **arguments_end) /* {{{ */ -{ - int arguments_count = (int) (zend_uintptr_t) *arguments_end; - size_t arguments_size = (arguments_count + 1) * sizeof(void **); - void **arguments_start = arguments_end - arguments_count; - void **copied_arguments_start = emalloc(arguments_size); - void **copied_arguments_end = copied_arguments_start + arguments_count; - int i; - - memcpy(copied_arguments_start, arguments_start, arguments_size); - - for (i = 0; i < arguments_count; i++) { - Z_ADDREF_P((zval *) arguments_start[i]); - } - - return copied_arguments_end; -} -/* }}} */ - /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 4594eba9ef..fdd9f5697d 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -50,14 +50,14 @@ typedef union _temp_variable { BEGIN_EXTERN_C() struct _zend_fcall_info; -ZEND_API extern void (*zend_execute)(zend_op_array *op_array TSRMLS_DC); +ZEND_API extern void (*zend_execute_ex)(zend_execute_data *execute_data TSRMLS_DC); ZEND_API extern void (*zend_execute_internal)(zend_execute_data *execute_data_ptr, struct _zend_fcall_info *fci, int return_value_used TSRMLS_DC); void init_executor(TSRMLS_D); void shutdown_executor(TSRMLS_D); void shutdown_destructors(TSRMLS_D); zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC); -ZEND_API void execute(zend_op_array *op_array TSRMLS_DC); +ZEND_API void zend_execute(zend_op_array *op_array TSRMLS_DC); ZEND_API void execute_ex(zend_execute_data *execute_data TSRMLS_DC); ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, struct _zend_fcall_info *fci, int return_value_used TSRMLS_DC); ZEND_API int zend_is_true(zval *op); @@ -222,12 +222,6 @@ static zend_always_inline void **zend_vm_stack_top(TSRMLS_D) static zend_always_inline void zend_vm_stack_push(void *ptr TSRMLS_DC) { - ZEND_VM_STACK_GROW_IF_NEEDED(1); - *(EG(argument_stack)->top++) = ptr; -} - -static zend_always_inline void zend_vm_stack_push_nocheck(void *ptr TSRMLS_DC) -{ *(EG(argument_stack)->top++) = ptr; } @@ -235,11 +229,6 @@ static zend_always_inline void *zend_vm_stack_pop(TSRMLS_D) { void *el = *(--EG(argument_stack)->top); - if (UNEXPECTED(EG(argument_stack)->top == ZEND_VM_STACK_ELEMETS(EG(argument_stack)))) { - zend_vm_stack p = EG(argument_stack); - EG(argument_stack) = p->prev; - efree(p); - } return el; } @@ -272,6 +261,12 @@ static zend_always_inline void *zend_vm_stack_alloc(size_t size TSRMLS_DC) return ret; } +static zend_always_inline void** zend_vm_stack_frame_base(zend_execute_data *ex) +{ + return (void**)((char*)ex->call_slots + + ZEND_MM_ALIGNED_SIZE(sizeof(call_slot)) * ex->op_array->nested_calls); +} + static zend_always_inline void zend_vm_stack_free_int(void *ptr TSRMLS_DC) { if (UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (void**)ptr)) { @@ -302,35 +297,6 @@ static zend_always_inline void zend_vm_stack_free(void *ptr TSRMLS_DC) } } -static zend_always_inline void** zend_vm_stack_push_args(int count TSRMLS_DC) -{ - - if (UNEXPECTED(EG(argument_stack)->top - ZEND_VM_STACK_ELEMETS(EG(argument_stack)) < count) || - UNEXPECTED(EG(argument_stack)->top == EG(argument_stack)->end)) { - zend_vm_stack p = EG(argument_stack); - - zend_vm_stack_extend(count + 1 TSRMLS_CC); - - EG(argument_stack)->top += count; - *(EG(argument_stack)->top) = (void*)(zend_uintptr_t)count; - while (count-- > 0) { - void *data = *(--p->top); - - if (UNEXPECTED(p->top == ZEND_VM_STACK_ELEMETS(p))) { - zend_vm_stack r = p; - - EG(argument_stack)->prev = p->prev; - p = p->prev; - efree(r); - } - *(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + count) = data; - } - return EG(argument_stack)->top++; - } - *(EG(argument_stack)->top) = (void*)(zend_uintptr_t)count; - return EG(argument_stack)->top++; -} - static zend_always_inline void zend_vm_stack_clear_multiple(TSRMLS_D) { void **p = EG(argument_stack)->top - 1; @@ -344,9 +310,19 @@ static zend_always_inline void zend_vm_stack_clear_multiple(TSRMLS_D) zend_vm_stack_free_int(p TSRMLS_CC); } -static zend_always_inline zval** zend_vm_stack_get_arg(int requested_arg TSRMLS_DC) +static zend_always_inline int zend_vm_stack_get_args_count_ex(zend_execute_data *ex) +{ + if (ex) { + void **p = ex->function_state.arguments; + return (int)(zend_uintptr_t) *p; + } else { + return 0; + } +} + +static zend_always_inline zval** zend_vm_stack_get_arg_ex(zend_execute_data *ex, int requested_arg) { - void **p = EG(current_execute_data)->prev_execute_data->function_state.arguments; + void **p = ex->function_state.arguments; int arg_count = (int)(zend_uintptr_t) *p; if (UNEXPECTED(requested_arg > arg_count)) { @@ -355,25 +331,14 @@ static zend_always_inline zval** zend_vm_stack_get_arg(int requested_arg TSRMLS_ return (zval**)p - arg_count + requested_arg - 1; } -static zend_always_inline void zend_arg_types_stack_2_pop(zend_ptr_stack *stack, zval **object, zend_function **fbc) +static zend_always_inline int zend_vm_stack_get_args_count(TSRMLS_D) { - void *a, *b; - - zend_ptr_stack_2_pop(stack, &a, &b); - - *object = (zval *) a; - *fbc = (zend_function *) b; + return zend_vm_stack_get_args_count_ex(EG(current_execute_data)->prev_execute_data); } -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) +static zend_always_inline zval** zend_vm_stack_get_arg(int requested_arg TSRMLS_DC) { - void *a, *b, *c; - - zend_ptr_stack_3_pop(stack, &a, &b, &c); - - *called_scope = (zend_class_entry *) a; - *object = (zval *) b; - *fbc = (zend_function *) c; + return zend_vm_stack_get_arg_ex(EG(current_execute_data)->prev_execute_data, requested_arg); } void execute_new_code(TSRMLS_D); @@ -436,7 +401,6 @@ ZEND_API int zend_do_fcall(ZEND_OPCODE_HANDLER_ARGS); void zend_clean_and_cache_symbol_table(HashTable *symbol_table TSRMLS_DC); void zend_free_compiled_variables(zval ***CVs, int num); -void **zend_copy_arguments(void **arguments_end); #define CACHED_PTR(num) \ EG(active_op_array)->run_time_cache[(num)] diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 9787966f27..3df0ca2396 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -38,7 +38,7 @@ #include <sys/time.h> #endif -ZEND_API void (*zend_execute)(zend_op_array *op_array TSRMLS_DC); +ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data TSRMLS_DC); ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data_ptr, zend_fcall_info *fci, int return_value_used TSRMLS_DC); /* true globals */ @@ -137,7 +137,6 @@ void init_executor(TSRMLS_D) /* {{{ */ INIT_ZVAL(EG(error_zval)); EG(uninitialized_zval_ptr)=&EG(uninitialized_zval); EG(error_zval_ptr)=&EG(error_zval); - zend_ptr_stack_init(&EG(arg_types_stack)); /* destroys stack frame, therefore makes core dumps worthless */ #if 0&&ZEND_DEBUG original_sigsegv_handler = signal(SIGSEGV, zend_handle_sigsegv); @@ -293,10 +292,10 @@ void shutdown_executor(TSRMLS_D) /* {{{ */ } zend_end_try(); zend_try { - zend_vm_stack_destroy(TSRMLS_C); - zend_objects_store_free_object_storage(&EG(objects_store) TSRMLS_CC); + zend_vm_stack_destroy(TSRMLS_C); + /* Destroy all op arrays */ if (EG(full_tables_cleanup)) { zend_hash_reverse_apply(EG(function_table), (apply_func_t) clean_non_persistent_function_full TSRMLS_CC); @@ -324,7 +323,6 @@ void shutdown_executor(TSRMLS_D) /* {{{ */ zend_hash_destroy(&EG(included_files)); - zend_ptr_stack_destroy(&EG(arg_types_stack)); zend_stack_destroy(&EG(user_error_handlers_error_reporting)); zend_ptr_stack_destroy(&EG(user_error_handlers)); zend_ptr_stack_destroy(&EG(user_exception_handlers)); @@ -862,7 +860,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS !ARG_MAY_BE_SENT_BY_REF(EX(function_state).function, i + 1)) { if (i || UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (EG(argument_stack)->top))) { /* hack to clean up the stack */ - zend_vm_stack_push_nocheck((void *) (zend_uintptr_t)i TSRMLS_CC); + zend_vm_stack_push((void *) (zend_uintptr_t)i TSRMLS_CC); zend_vm_stack_clear_multiple(TSRMLS_C); } @@ -899,11 +897,11 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS *param = **(fci->params[i]); INIT_PZVAL(param); } - zend_vm_stack_push_nocheck(param TSRMLS_CC); + zend_vm_stack_push(param TSRMLS_CC); } EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C); - zend_vm_stack_push_nocheck((void*)(zend_uintptr_t)fci->param_count TSRMLS_CC); + zend_vm_stack_push((void*)(zend_uintptr_t)fci->param_count TSRMLS_CC); current_scope = EG(scope); EG(scope) = calling_scope; diff --git a/Zend/zend_extensions.h b/Zend/zend_extensions.h index 703e03c3f6..17804cb740 100644 --- a/Zend/zend_extensions.h +++ b/Zend/zend_extensions.h @@ -28,7 +28,7 @@ /* The first number is the engine version and the rest is the date. * This way engine 2/3 API no. is always greater than engine 1 API no.. */ -#define ZEND_EXTENSION_API_NO 220121113 +#define ZEND_EXTENSION_API_NO 220121128 typedef struct _zend_extension_version_info { int zend_extension_api_no; diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 1895305875..493e99dd0e 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -32,41 +32,7 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio if (generator->execute_data) { zend_execute_data *execute_data = generator->execute_data; zend_op_array *op_array = execute_data->op_array; - - if (!finished_execution) { - if (op_array->has_finally_block) { - /* -1 required because we want the last run opcode, not the - * next to-be-run one. */ - zend_uint op_num = execute_data->opline - op_array->opcodes - 1; - zend_uint finally_op_num = 0; - - /* Find next finally block */ - int i; - for (i = 0; i < op_array->last_try_catch; i++) { - zend_try_catch_element *try_catch = &op_array->try_catch_array[i]; - - if (op_num < try_catch->try_op) { - break; - } - - if (op_num < try_catch->finally_op) { - finally_op_num = try_catch->finally_op; - } - } - - /* If a finally block was found we jump directly to it and - * resume the generator. Furthermore we abort this close call - * because the generator will already be closed somewhere in - * the resume. */ - if (finally_op_num) { - execute_data->opline = &op_array->opcodes[finally_op_num]; - execute_data->fast_ret = NULL; - generator->flags |= ZEND_GENERATOR_FORCED_CLOSE; - zend_generator_resume(generator TSRMLS_CC); - return; - } - } - } + void **stack_frame; if (!execute_data->symbol_table) { zend_free_compiled_variables(execute_data->CVs, op_array->last_var); @@ -78,10 +44,6 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio zval_ptr_dtor(&execute_data->current_this); } - if (execute_data->object) { - zval_ptr_dtor(&execute_data->object); - } - /* If the generator is closed before it can finish execution (reach * a return statement) we have to free loop variables manually, as * we don't know whether the SWITCH_FREE / FREE opcodes have run */ @@ -120,32 +82,20 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio } /* Clear any backed up stack arguments */ - if (generator->backed_up_stack) { - zval **zvals = (zval **) generator->backed_up_stack; - size_t zval_num = generator->backed_up_stack_size / sizeof(zval *); - int i; - - for (i = 0; i < zval_num; i++) { - zval_ptr_dtor(&zvals[i]); + if (generator->stack != EG(argument_stack)) { + stack_frame = zend_vm_stack_frame_base(execute_data); + while (generator->stack->top != stack_frame) { + zval_ptr_dtor((zval**)stack_frame); + stack_frame++; } - - efree(generator->backed_up_stack); } - if (generator->backed_up_arg_types_stack) { - /* The arg types stack contains three elements per call: fbc, object - * and called_scope. Here we traverse the stack from top to bottom - * and dtor the object. */ - int i = generator->backed_up_arg_types_stack_count / 3; - while (i--) { - zval *object = (zval *) generator->backed_up_arg_types_stack[3*i + 1]; - if (object) { - zval_ptr_dtor(&object); - } + while (execute_data->call >= execute_data->call_slots) { + if (execute_data->call->object) { + zval_ptr_dtor(&execute_data->call->object); } - - efree(generator->backed_up_arg_types_stack); - } + execute_data->call--; + } /* We have added an additional stack frame in prev_execute_data, so we * have to free it. It also contains the arguments passed to the @@ -162,11 +112,7 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio for (i = 0; i < arguments_count; ++i) { zval_ptr_dtor(arguments_start + i); } - - efree(arguments_start); } - - efree(prev_execute_data); } /* Free a clone of closure */ @@ -175,7 +121,11 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio efree(op_array); } - efree(execute_data); + efree(generator->stack); + if (generator->stack == EG(argument_stack)) { + /* abnormal exit for running generator */ + EG(argument_stack) = NULL; + } generator->execute_data = NULL; } @@ -210,27 +160,39 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator ** zend_execute_data *execute_data = orig->execute_data; zend_op_array *op_array = execute_data->op_array; HashTable *symbol_table = execute_data->symbol_table; - - /* Alloc separate execution context, as well as separate sections for - * compiled variables and temporary variables */ - size_t execute_data_size = ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)); - size_t CVs_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval **) * op_array->last_var * (symbol_table ? 1 : 2)); - size_t Ts_size = ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T; - size_t total_size = execute_data_size + CVs_size + Ts_size; - - clone->execute_data = emalloc(total_size); - - /* Copy the zend_execute_data struct */ - memcpy(clone->execute_data, execute_data, execute_data_size); - - /* Set the pointers to the memory segments for the compiled and - * temporary variables (which are located after the execute_data) */ - clone->execute_data->CVs = (zval ***) ((char *) clone->execute_data + execute_data_size); - clone->execute_data->Ts = (temp_variable *) ((char *) clone->execute_data->CVs + CVs_size); - - /* Zero out the compiled variables section */ - memset(clone->execute_data->CVs, 0, sizeof(zval **) * op_array->last_var); - + zend_execute_data *current_execute_data; + zend_op **opline_ptr; + HashTable *current_symbol_table; + zend_vm_stack current_stack; + zval *current_this; + void **stack_frame, **orig_stack_frame; + + /* Create new execution context. We have to back up and restore + * EG(current_execute_data), EG(opline_ptr), EG(active_symbol_table) + * and EG(This) here because the function modifies or uses them */ + current_execute_data = EG(current_execute_data); + EG(current_execute_data) = execute_data->prev_execute_data; + opline_ptr = EG(opline_ptr); + current_symbol_table = EG(active_symbol_table); + EG(active_symbol_table) = execute_data->symbol_table; + current_this = EG(This); + EG(This) = NULL; + current_stack = EG(argument_stack); + clone->execute_data = zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC); + clone->stack = EG(argument_stack); + EG(argument_stack) = current_stack; + EG(This) = current_this; + EG(active_symbol_table) = current_symbol_table; + EG(current_execute_data) = current_execute_data; + EG(opline_ptr) = opline_ptr; + + /* copy */ + clone->execute_data->opline = execute_data->opline; + clone->execute_data->function_state = execute_data->function_state; + clone->execute_data->current_scope = execute_data->current_scope; + clone->execute_data->current_called_scope = execute_data->current_called_scope; + clone->execute_data->fast_ret = execute_data->fast_ret; + if (!symbol_table) { int i; @@ -238,7 +200,7 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator ** for (i = 0; i < op_array->last_var; i++) { if (execute_data->CVs[i]) { clone->execute_data->CVs[i] = (zval **) clone->execute_data->CVs + op_array->last_var + i; - *clone->execute_data->CVs[i] = (zval *) orig->execute_data->CVs[op_array->last_var + i]; + *clone->execute_data->CVs[i] = (zval *) execute_data->CVs[op_array->last_var + i]; Z_ADDREF_PP(clone->execute_data->CVs[i]); } } @@ -259,8 +221,39 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator ** } } + /* Copy nested-calls stack */ + if (execute_data->call) { + clone->execute_data->call = clone->execute_data->call_slots + + (execute_data->call - execute_data->call_slots); + } else { + clone->execute_data->call = NULL; + } + memcpy(clone->execute_data->call_slots, execute_data->call_slots, sizeof(call_slot) * op_array->nested_calls); + if (clone->execute_data->call >= clone->execute_data->call_slots) { + call_slot *call = clone->execute_data->call; + + while (call >= clone->execute_data->call_slots) { + if (call->object) { + Z_ADDREF_P(call->object); + } + call--; + } + } + /* Copy the temporary variables */ - memcpy(clone->execute_data->Ts, orig->execute_data->Ts, Ts_size); + memcpy(clone->execute_data->Ts, execute_data->Ts, sizeof(temp_variable) * op_array->T); + + /* Copy arguments passed on stack */ + stack_frame = zend_vm_stack_frame_base(clone->execute_data); + orig_stack_frame = zend_vm_stack_frame_base(execute_data); + clone->stack->top = stack_frame + (orig->stack->top - orig_stack_frame); + if (clone->stack->top != stack_frame) { + memcpy(stack_frame, orig_stack_frame, sizeof(zval*) * (orig->stack->top - orig_stack_frame)); + while (clone->stack->top != stack_frame) { + Z_ADDREF_PP((zval**)stack_frame); + stack_frame++; + } + } /* Add references to loop variables */ { @@ -286,42 +279,6 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator ** } } - if (orig->backed_up_stack) { - /* Copy backed up stack */ - clone->backed_up_stack = emalloc(orig->backed_up_stack_size); - memcpy(clone->backed_up_stack, orig->backed_up_stack, orig->backed_up_stack_size); - - /* Add refs to stack variables */ - { - zval **zvals = (zval **) orig->backed_up_stack; - size_t zval_num = orig->backed_up_stack_size / sizeof(zval *); - int i; - - for (i = 0; i < zval_num; i++) { - Z_ADDREF_P(zvals[i]); - } - } - } - - if (orig->backed_up_arg_types_stack) { - size_t stack_size = orig->backed_up_arg_types_stack_count * sizeof(void *); - - clone->backed_up_arg_types_stack = emalloc(stack_size); - memcpy(clone->backed_up_arg_types_stack, orig->backed_up_arg_types_stack, stack_size); - - /* We have to add refs to the objects in the arg types stack (the - * object is always the second element of a three-pack. */ - { - int i, stack_frames = clone->backed_up_arg_types_stack_count / 3; - for (i = 0; i < stack_frames; i++) { - zval *object = (zval *) clone->backed_up_arg_types_stack[3*i + 1]; - if (object) { - Z_ADDREF_P(object); - } - } - } - } - /* Update the send_target to use the temporary variable with the same * offset as the original generator, but in our temporary variable * memory segment. */ @@ -334,24 +291,14 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator ** } if (execute_data->current_this) { + clone->execute_data->current_this = execute_data->current_this; Z_ADDREF_P(execute_data->current_this); } if (execute_data->object) { + clone->execute_data->object = execute_data->object; Z_ADDREF_P(execute_data->object); } - - /* Prev execute data contains an additional stack frame (for proper - * backtraces) which has to be copied. */ - clone->execute_data->prev_execute_data = emalloc(sizeof(zend_execute_data)); - memcpy(clone->execute_data->prev_execute_data, execute_data->prev_execute_data, sizeof(zend_execute_data)); - - /* It also contains the arguments passed to the generator, which also - * have to be copied */ - if (execute_data->prev_execute_data->function_state.arguments) { - clone->execute_data->prev_execute_data->function_state.arguments - = zend_copy_arguments(execute_data->prev_execute_data->function_state.arguments); - } } /* The value and key are known not to be references, so simply add refs */ @@ -399,7 +346,9 @@ zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC) /* {{{ */ zend_generator *generator; zend_execute_data *current_execute_data; zend_op **opline_ptr; + HashTable *current_symbol_table; zend_execute_data *execute_data; + zend_vm_stack current_stack = EG(argument_stack); /* Create a clone of closure, because it may be destroyed */ if (op_array->fn_flags & ZEND_ACC_CLOSURE) { @@ -410,11 +359,14 @@ zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC) /* {{{ */ } /* Create new execution context. We have to back up and restore - * EG(current_execute_data) and EG(opline_ptr) here because the function - * modifies it. */ + * EG(current_execute_data), EG(opline_ptr) and EG(active_symbol_table) + * here because the function modifies or uses them */ current_execute_data = EG(current_execute_data); opline_ptr = EG(opline_ptr); + current_symbol_table = EG(active_symbol_table); + EG(active_symbol_table) = NULL; execute_data = zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC); + EG(active_symbol_table) = current_symbol_table; EG(current_execute_data) = current_execute_data; EG(opline_ptr) = opline_ptr; @@ -434,18 +386,8 @@ zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC) /* {{{ */ /* Save execution context in generator object. */ generator = (zend_generator *) zend_object_store_get_object(return_value TSRMLS_CC); generator->execute_data = execute_data; - - /* We have to add another stack frame so the generator function shows - * up in backtraces and func_get_all() can access the function - * arguments. */ - execute_data->prev_execute_data = emalloc(sizeof(zend_execute_data)); - memset(execute_data->prev_execute_data, 0, sizeof(zend_execute_data)); - execute_data->prev_execute_data->function_state.function = (zend_function *) op_array; - if (EG(current_execute_data)) { - execute_data->prev_execute_data->function_state.arguments = zend_copy_arguments(EG(current_execute_data)->function_state.arguments); - } else { - execute_data->prev_execute_data->function_state.arguments = NULL; - } + generator->stack = EG(argument_stack); + EG(argument_stack) = current_stack; return return_value; } @@ -487,28 +429,7 @@ void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */ zval *original_This = EG(This); zend_class_entry *original_scope = EG(scope); zend_class_entry *original_called_scope = EG(called_scope); - int original_arg_types_stack_count = EG(arg_types_stack).top; - - /* Remember the current stack position so we can back up pushed args */ - generator->original_stack_top = zend_vm_stack_top(TSRMLS_C); - - /* If there is a backed up stack copy it to the VM stack */ - if (generator->backed_up_stack) { - void *stack = zend_vm_stack_alloc(generator->backed_up_stack_size TSRMLS_CC); - memcpy(stack, generator->backed_up_stack, generator->backed_up_stack_size); - efree(generator->backed_up_stack); - generator->backed_up_stack = NULL; - } - - if (generator->backed_up_arg_types_stack) { - zend_ptr_stack_push_from_memory( - &EG(arg_types_stack), - generator->backed_up_arg_types_stack_count, - generator->backed_up_arg_types_stack - ); - efree(generator->backed_up_arg_types_stack); - generator->backed_up_arg_types_stack = NULL; - } + zend_vm_stack original_stack = EG(argument_stack); /* We (mis)use the return_value_ptr_ptr to provide the generator object * to the executor, so YIELD will be able to set the yielded value */ @@ -522,6 +443,7 @@ void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */ EG(This) = generator->execute_data->current_this; EG(scope) = generator->execute_data->current_scope; EG(called_scope) = generator->execute_data->current_called_scope; + EG(argument_stack) = generator->stack; /* We want the backtrace to look as if the generator function was * called from whatever method we are current running (e.g. next()). @@ -533,7 +455,7 @@ void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */ /* Resume execution */ generator->flags |= ZEND_GENERATOR_CURRENTLY_RUNNING; - execute_ex(generator->execute_data TSRMLS_CC); + zend_execute_ex(generator->execute_data TSRMLS_CC); generator->flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING; /* Restore executor globals */ @@ -545,27 +467,7 @@ void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */ EG(This) = original_This; EG(scope) = original_scope; EG(called_scope) = original_called_scope; - - /* The stack top before and after the execution differ, i.e. there are - * arguments pushed to the stack. */ - if (generator->original_stack_top != zend_vm_stack_top(TSRMLS_C)) { - generator->backed_up_stack_size = (zend_vm_stack_top(TSRMLS_C) - generator->original_stack_top) * sizeof(void *); - generator->backed_up_stack = emalloc(generator->backed_up_stack_size); - memcpy(generator->backed_up_stack, generator->original_stack_top, generator->backed_up_stack_size); - zend_vm_stack_free(generator->original_stack_top TSRMLS_CC); - } - - if (original_arg_types_stack_count != EG(arg_types_stack).top) { - generator->backed_up_arg_types_stack_count = - EG(arg_types_stack).top - original_arg_types_stack_count; - - generator->backed_up_arg_types_stack = emalloc(generator->backed_up_arg_types_stack_count * sizeof(void *)); - zend_ptr_stack_pop_into_memory( - &EG(arg_types_stack), - generator->backed_up_arg_types_stack_count, - generator->backed_up_arg_types_stack - ); - } + EG(argument_stack) = original_stack; /* If an exception was thrown in the generator we have to internally * rethrow it in the parent scope. */ @@ -741,21 +643,11 @@ ZEND_METHOD(Generator, __wakeup) /* get_iterator implementation */ -typedef struct _zend_generator_iterator { - zend_object_iterator intern; - - /* The generator object zval has to be stored, because the iterator is - * holding a ref to it, which has to be dtored. */ - zval *object; -} zend_generator_iterator; - static void zend_generator_iterator_dtor(zend_object_iterator *iterator TSRMLS_DC) /* {{{ */ { zval *object = ((zend_generator_iterator *) iterator)->object; zval_ptr_dtor(&object); - - efree(iterator); } /* }}} */ @@ -854,7 +746,7 @@ zend_object_iterator *zend_generator_get_iterator(zend_class_entry *ce, zval *ob return NULL; } - iterator = emalloc(sizeof(zend_generator_iterator)); + iterator = &generator->iterator; iterator->intern.funcs = &zend_generator_iterator_functions; iterator->intern.data = (void *) generator; diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h index 3dc3e6fecd..90f8160f71 100644 --- a/Zend/zend_generators.h +++ b/Zend/zend_generators.h @@ -25,25 +25,24 @@ BEGIN_EXTERN_C() extern ZEND_API zend_class_entry *zend_ce_generator; END_EXTERN_C() +typedef struct _zend_generator_iterator { + zend_object_iterator intern; + + /* The generator object zval has to be stored, because the iterator is + * holding a ref to it, which has to be dtored. */ + zval *object; +} zend_generator_iterator; + typedef struct _zend_generator { zend_object std; + zend_generator_iterator iterator; + /* The suspended execution context. */ zend_execute_data *execute_data; - /* If the execution is suspended during a function call there may be - * arguments pushed to the stack, so it has to be backed up. */ - void *backed_up_stack; - size_t backed_up_stack_size; - - /* For method calls PHP also pushes various type information on a second - * stack, which also needs to be backed up. */ - void **backed_up_arg_types_stack; - int backed_up_arg_types_stack_count; - - /* The original stack top before resuming the generator. This is required - * for proper cleanup during exception handling. */ - void **original_stack_top; + /* The separate stack used by generator */ + zend_vm_stack stack; /* Current value */ zval *value; diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index e5aba0df67..6ad9768086 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -167,8 +167,6 @@ struct _zend_executor_globals { zval error_zval; zval *error_zval_ptr; - zend_ptr_stack arg_types_stack; - /* symbol table cache */ HashTable *symtable_cache[SYMTABLE_CACHE_SIZE]; HashTable **symtable_cache_limit; diff --git a/Zend/zend_modules.h b/Zend/zend_modules.h index 442535bc68..bfea3e0d22 100644 --- a/Zend/zend_modules.h +++ b/Zend/zend_modules.h @@ -33,7 +33,7 @@ #define ZEND_MODULE_INFO_FUNC_ARGS zend_module_entry *zend_module TSRMLS_DC #define ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU zend_module TSRMLS_CC -#define ZEND_MODULE_API_NO 20121113 +#define ZEND_MODULE_API_NO 20121128 #ifdef ZTS #define USING_ZTS 1 #else diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 563c84301d..2fd8f529ef 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -70,6 +70,9 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->T = 0; + op_array->nested_calls = 0; + op_array->used_stack = 0; + op_array->function_name = NULL; op_array->filename = zend_get_compiled_filename(TSRMLS_C); op_array->doc_comment = NULL; @@ -541,6 +544,15 @@ static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num, /* generate a FAST_CALL to finaly block */ start_op = get_next_op_number(op_array); + + if (op_array->opcodes[op_num].opcode == ZEND_YIELD) { + /* Disable yield in finally block */ + opline = get_next_op(op_array TSRMLS_CC); + opline->opcode = ZEND_GENERATOR_FLAG; + opline->extended_value = 1; + SET_UNUSED(opline->op1); + SET_UNUSED(opline->op2); + } opline = get_next_op(op_array TSRMLS_CC); opline->opcode = ZEND_FAST_CALL; SET_UNUSED(opline->op1); @@ -567,6 +579,14 @@ static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num, opline->op1.opline_num = op_array->try_catch_array[i].finally_op; } } + if (op_array->opcodes[op_num].opcode == ZEND_YIELD) { + /* Re-enable yield */ + opline = get_next_op(op_array TSRMLS_CC); + opline->opcode = ZEND_GENERATOR_FLAG; + opline->extended_value = 0; + SET_UNUSED(opline->op1); + SET_UNUSED(opline->op2); + } /* Finish the sequence with original opcode */ opline = get_next_op(op_array TSRMLS_CC); @@ -622,6 +642,7 @@ static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC) switch (opline->opcode) { case ZEND_RETURN: case ZEND_RETURN_BY_REF: + case ZEND_YIELD: zend_resolve_finally_call(op_array, i, (zend_uint)-1 TSRMLS_CC); break; case ZEND_BRK: diff --git a/Zend/zend_ptr_stack.c b/Zend/zend_ptr_stack.c index d178cc0184..9d82bba475 100644 --- a/Zend/zend_ptr_stack.c +++ b/Zend/zend_ptr_stack.c @@ -110,23 +110,6 @@ ZEND_API int zend_ptr_stack_num_elements(zend_ptr_stack *stack) { return stack->top; } - -ZEND_API void zend_ptr_stack_push_from_memory(zend_ptr_stack *stack, int count, void **pointers) -{ - ZEND_PTR_STACK_RESIZE_IF_NEEDED(stack, count); - - memcpy(stack->top_element, pointers, count * sizeof(void *)); - stack->top_element += count; - stack->top += count; -} - -ZEND_API void zend_ptr_stack_pop_into_memory(zend_ptr_stack *stack, int count, void **pointers) -{ - memcpy(pointers, stack->top_element - count, count * sizeof(void *)); - stack->top_element -= count; - stack->top -= count; -} - /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_ptr_stack.h b/Zend/zend_ptr_stack.h index fe93e93b5a..9f6fc13161 100644 --- a/Zend/zend_ptr_stack.h +++ b/Zend/zend_ptr_stack.h @@ -41,8 +41,6 @@ ZEND_API void zend_ptr_stack_destroy(zend_ptr_stack *stack); ZEND_API void zend_ptr_stack_apply(zend_ptr_stack *stack, void (*func)(void *)); ZEND_API void zend_ptr_stack_clean(zend_ptr_stack *stack, void (*func)(void *), zend_bool free_elements); ZEND_API int zend_ptr_stack_num_elements(zend_ptr_stack *stack); -ZEND_API void zend_ptr_stack_push_from_memory(zend_ptr_stack *stack, int count, void **pointers); -ZEND_API void zend_ptr_stack_pop_into_memory(zend_ptr_stack *stack, int count, void **pointers); END_EXTERN_C() #define ZEND_PTR_STACK_RESIZE_IF_NEEDED(stack, count) \ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 4ae4ca1267..966827d5b4 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1161,7 +1161,7 @@ ZEND_VM_HANDLER(92, ZEND_FETCH_FUNC_ARG, CONST|TMP|VAR|CV, UNUSED|CONST|VAR) USE_OPLINE ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type, - ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R); + ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R); } ZEND_VM_HANDLER(95, ZEND_FETCH_UNSET, CONST|TMP|VAR|CV, UNUSED|CONST|VAR) @@ -1283,7 +1283,7 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, VAR|CV, CONST|TMP|VAR|UNUSED|CV) SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -1519,7 +1519,7 @@ ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, VAR|UNUSED|CV, CONST|TMP|VAR|CV) { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -1889,7 +1889,6 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) EX(function_state).function = (zend_function *) EX(op_array); EX(function_state).arguments = NULL; - EX(object) = EX(current_object); EG(opline_ptr) = &EX(opline); EG(active_op_array) = EX(op_array); @@ -1925,8 +1924,8 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) EX(function_state).arguments = NULL; if (EG(This)) { - if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) { - if (IS_CTOR_USED(EX(called_scope))) { + if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { + if (EX(call)->is_ctor_result_used) { Z_DELREF_P(EG(This)); } if (Z_REFCOUNT_P(EG(This)) == 1) { @@ -1939,8 +1938,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) EG(scope) = EX(current_scope); EG(called_scope) = EX(current_called_scope); - EX(object) = EX(current_object); - EX(called_scope) = DECODE_CTOR(EX(called_scope)); + EX(call)--; zend_vm_stack_clear_multiple(TSRMLS_C); @@ -1966,6 +1964,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) zend_function *fbc = EX(function_state).function; SAVE_OPLINE(); + EX(object) = EX(call)->object; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name, fbc->common.function_name); @@ -2000,11 +1999,11 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) EX(current_called_scope) = EG(called_scope); EG(This) = EX(object); EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ? fbc->common.scope : NULL; - EG(called_scope) = EX(called_scope); + EG(called_scope) = EX(call)->called_scope; } - zend_arg_types_stack_3_pop(&EG(arg_types_stack), &EX(called_scope), &EX(current_object), &EX(fbc)); - EX(function_state).arguments = zend_vm_stack_push_args(opline->extended_value TSRMLS_CC); + EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C); + zend_vm_stack_push((void*)(zend_uintptr_t)opline->extended_value TSRMLS_CC); LOAD_OPLINE(); if (fbc->type == ZEND_INTERNAL_FUNCTION) { @@ -2054,7 +2053,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) if (RETURN_VALUE_USED(opline)) { EX_T(opline->result.var).var.ptr = zend_generator_create_zval(EG(active_op_array) TSRMLS_CC); } - } else if (EXPECTED(zend_execute == execute)) { + } else if (EXPECTED(zend_execute_ex == execute_ex)) { if (EXPECTED(EG(exception) == NULL)) { ZEND_VM_ENTER(); } @@ -2100,8 +2099,8 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) if (should_change_scope) { if (EG(This)) { - if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) { - if (IS_CTOR_USED(EX(called_scope))) { + if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { + if (EX(call)->is_ctor_result_used) { Z_DELREF_P(EG(This)); } if (Z_REFCOUNT_P(EG(This)) == 1) { @@ -2115,8 +2114,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) EG(called_scope) = EX(current_called_scope); } - EX(object) = EX(current_object); - EX(called_scope) = DECODE_CTOR(EX(called_scope)); + EX(call)--; zend_vm_stack_clear_multiple(TSRMLS_C); @@ -2463,9 +2461,9 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) char *function_name_strval; int function_name_strlen; zend_free_op free_op1, free_op2; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); @@ -2477,49 +2475,51 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R); + call->object = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (OP2_TYPE != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - 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); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + 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); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (OP2_TYPE == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; FREE_OP2(); FREE_OP1_IF_VAR(); @@ -2533,9 +2533,9 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS USE_OPLINE zval *function_name; zend_class_entry *ce; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (OP1_TYPE == IS_CONST) { /* no function found. try a static method in class */ @@ -2549,24 +2549,24 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS } CACHE_PTR(opline->op1.literal->cache_slot, ce); } - EX(called_scope) = ce; + call->called_scope = ce; } else { ce = EX_T(opline->op1.var).class_entry; if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - EX(called_scope) = EG(called_scope); + call->called_scope = EG(called_scope); } else { - EX(called_scope) = ce; + call->called_scope = ce; } } if (OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST && CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); } else if (OP1_TYPE != IS_CONST && OP2_TYPE == IS_CONST && - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { /* do nothing */ } else if (OP2_TYPE != IS_UNUSED) { char *function_name_strval = NULL; @@ -2589,20 +2589,20 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS if (function_name_strval) { if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + call->fbc = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); } else { - 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); + 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); } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval); } if (OP2_TYPE == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (OP1_TYPE == IS_CONST) { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } else { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, call->fbc); } } } @@ -2616,29 +2616,31 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name); } - EX(fbc) = ce->constructor; + call->fbc = ce->constructor; } - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; + if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { + call->object = NULL; } else { if (EG(This) && Z_OBJ_HT_P(EG(This))->get_class_entry && !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { /* We are calling method of the other (incompatible) class, but passing $this. This is done for compatibility with php-4. */ - if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - 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); + if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + 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); } else { /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - 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); + 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); } } - if ((EX(object) = EG(This))) { - Z_ADDREF_P(EX(object)); - EX(called_scope) = Z_OBJCE_P(EX(object)); + if ((call->object = EG(This))) { + Z_ADDREF_P(call->object); + call->called_scope = Z_OBJCE_P(call->object); } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2648,19 +2650,21 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) { USE_OPLINE zval *function_name; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); + call_slot *call = EX(call_slots) + opline->result.num; if (OP2_TYPE == IS_CONST) { function_name = (zval*)(opline->op2.literal+1); if (CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); - } 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)) { + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); + } 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)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } - EX(object) = NULL; + call->object = NULL; + call->is_ctor_call = 0; + EX(call) = call; /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { @@ -2680,28 +2684,32 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) } else { lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); } - if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &EX(fbc)) == FAILURE)) { + if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); FREE_OP2(); - EX(object) = NULL; + call->object = NULL; + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (OP2_TYPE != IS_CONST && OP2_TYPE != IS_TMP_VAR && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) { - if (EX(object)) { - Z_ADDREF_P(EX(object)); + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { + if (call->object) { + Z_ADDREF_P(call->object); } if (OP2_TYPE == IS_VAR && OP2_FREE && - EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) { + call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - EX(fbc)->common.prototype = (zend_function*)function_name; + call->fbc->common.prototype = (zend_function*)function_name; } else { FREE_OP2(); } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (OP2_TYPE != IS_CONST && @@ -2732,41 +2740,43 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - EX(called_scope) = ce; - EX(object) = NULL; + call->called_scope = ce; + call->object = NULL; if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC); + call->fbc = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); + call->fbc = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); } } else { - EX(object) = *obj; - ce = EX(called_scope) = Z_OBJCE_PP(obj); + call->object = *obj; + ce = call->called_scope = Z_OBJCE_PP(obj); - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method)); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_PP(method)); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); } + call->is_ctor_call = 0; + EX(call) = call; FREE_OP2(); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2781,31 +2791,32 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST) { USE_OPLINE zend_literal *func_name; - - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); + call_slot *call = EX(call_slots) + opline->result.num; func_name = opline->op2.literal + 1; if (CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); - } 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) { + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); + } 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) { func_name++; - 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)) { + 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)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } } else { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } - EX(object) = NULL; + call->object = NULL; + call->is_ctor_call = 0; + EX(call) = call; ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(61, ZEND_DO_FCALL_BY_NAME, ANY, ANY) { - EX(function_state).function = EX(fbc); + EX(function_state).function = EX(call)->fbc; ZEND_VM_DISPATCH_TO_HELPER(zend_do_fcall_common_helper); } @@ -2814,8 +2825,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY) USE_OPLINE zend_free_op free_op1; zval *fname = GET_OP1_ZVAL_PTR(BP_VAR_R); - - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); + call_slot *call = EX(call_slots) + opline->op2.num; if (CACHED_PTR(opline->op1.literal->cache_slot)) { EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot); @@ -2825,7 +2835,10 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY) } else { CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function); } - EX(object) = NULL; + call->fbc = EX(function_state).function; + call->object = NULL; + call->is_ctor_call = 0; + EX(call) = call; FREE_OP1(); @@ -3052,7 +3065,7 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, ANY) SAVE_OPLINE(); if (opline->extended_value==ZEND_DO_FCALL_BY_NAME - && ARG_MUST_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + && ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.opline_num); } { @@ -3113,7 +3126,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY) if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) { ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); } - } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); } @@ -3139,7 +3152,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY) if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : - !ARG_MAY_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } ALLOC_ZVAL(valptr); @@ -3175,7 +3188,7 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY) ZEND_VM_NEXT_OPCODE(); } - if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && !ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && !ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); } @@ -3194,7 +3207,7 @@ ZEND_VM_HANDLER(66, ZEND_SEND_VAR, VAR|CV, ANY) USE_OPLINE if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME) - && ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + && ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF); } SAVE_OPLINE(); @@ -3400,17 +3413,20 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY) } ZEND_VM_JMP(EX(op_array)->opcodes + opline->op2.opline_num); } else { + call_slot *call = EX(call_slots) + opline->extended_value; + if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(object_zval); AI_SET_PTR(&EX_T(opline->result.var), object_zval); } - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), ENCODE_CTOR(EX(called_scope), RETURN_VALUE_USED(opline))); - /* We are not handling overloaded classes right now */ - EX(object) = object_zval; - EX(fbc) = constructor; - EX(called_scope) = EX_T(opline->op1.var).class_entry; + call->fbc = constructor; + call->object = object_zval; + call->called_scope = EX_T(opline->op1.var).class_entry; + call->is_ctor_call = 1; + call->is_ctor_result_used = RETURN_VALUE_USED(opline); + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -3829,8 +3845,6 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY) EG(return_value_ptr_ptr) = NULL; } - EX(current_object) = EX(object); - EX(function_state).function = (zend_function *) new_op_array; EX(object) = NULL; @@ -3838,14 +3852,13 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY) zend_rebuild_symbol_table(TSRMLS_C); } - if (EXPECTED(zend_execute == execute)) { + if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { zend_execute(new_op_array TSRMLS_CC); } EX(function_state).function = (zend_function *) EX(op_array); - EX(object) = EX(current_object); EG(opline_ptr) = &EX(opline); EG(active_op_array) = EX(op_array); @@ -5022,19 +5035,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) /* Figure out where the next stack frame (which maybe contains pushed * arguments that have to be dtor'ed) starts */ - if (EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) { - /* The generator object is stored in return_value_ptr_ptr */ - zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr); - - /* For generators the next stack frame is conveniently stored in the - * generator object. */ - stack_frame = generator->original_stack_top; - } else { - /* In all other cases the next stack frame starts after the temporary - * variables section of the current execution context */ - stack_frame = (void **) ((char *) EX_Ts() + - ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * EX(op_array)->T); - } + stack_frame = zend_vm_stack_frame_base(EXECUTE_DATA); /* If the exception was thrown during a function call there might be * arguments pushed to the stack that have to be dtor'ed. */ @@ -5056,21 +5057,23 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } } - while (EX(fbc)) { - EX(called_scope) = (zend_class_entry*)zend_ptr_stack_pop(&EG(arg_types_stack)); - if (EX(object)) { - if (IS_CTOR_CALL(EX(called_scope))) { - if (IS_CTOR_USED(EX(called_scope))) { - Z_DELREF_P(EX(object)); - } - if (Z_REFCOUNT_P(EX(object)) == 1) { - zend_object_store_ctor_failed(EX(object) TSRMLS_CC); + if (EX(call) >= EX(call_slots)) { + call_slot *call = EX(call); + do { + if (call->object) { + if (call->is_ctor_call) { + if (call->is_ctor_result_used) { + Z_DELREF_P(call->object); + } + if (Z_REFCOUNT_P(call->object) == 1) { + zend_object_store_ctor_failed(call->object TSRMLS_CC); + } } + zval_ptr_dtor(&call->object); } - zval_ptr_dtor(&EX(object)); - } - EX(called_scope) = DECODE_CTOR(EX(called_scope)); - zend_arg_types_stack_2_pop(&EG(arg_types_stack), &EX(object), &EX(fbc)); + call--; + } while (call >= EX(call_slots)); + EX(call) = NULL; } for (i=0; i<EX(op_array)->last_brk_cont; i++) { @@ -5240,6 +5243,19 @@ ZEND_VM_HANDLER(156, ZEND_SEPARATE, VAR, UNUSED) ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HANDLER(159, ZEND_GENERATOR_FLAG, ANY, ANY) +{ + USE_OPLINE + zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr); + + if (opline->extended_value) { + generator->flags |= ZEND_GENERATOR_FORCED_CLOSE; + } else { + generator->flags &= ~ZEND_GENERATOR_FORCED_CLOSE; + } + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSED) { USE_OPLINE diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 582962cfcf..921ece228b 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -339,7 +339,50 @@ static opcode_handler_t zend_vm_get_opcode_handler(zend_uchar opcode, zend_op* o #define EX_Ts() EX(Ts) -zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC) { +/* + * Stack Frame Layout (the whole stack frame is allocated at once) + * ================== + * + * +========================================+ + * | zend_execute_data |<---+ + * | EX(function_state).arguments |--+ | + * | ... | | | + * | ARGUMENT [1] | | | + * | ... | | | + * | ARGUMENT [ARGS_NUMBER] | | | + * | ARGS_NUMBER |<-+ | + * +========================================+ | + * | + * +========================================+ | + * EG(current_execute_data) -> | zend_execute_data | | + * | EX(prev_execute_data) |----+ + * +----------------------------------------+ + * EX(Ts) ---------> | EX(Ts)[0] | + * | ... | + * | EX(Tx)[op_arrat->T] | + * +----------------------------------------+ + * EX(CVs) --------> | EX(CVs)[0] |--+ + * | ... | | + * | EX(CVs)[op_array->last_var] | | + * +----------------------------------------+ | + * | Optional slot for CV[0] zval* |<-+ + * | ... | + * | ... for CV [op_array->last_var] zval* | + * +----------------------------------------+ + * EX(call_slots) -> | EX(call_slots)[0] | + * | ... | + * | EX(call_slots)[op_array->nested_calls] | + * +----------------------------------------+ + * zend_vm_stack_frame_base -> | ARGUMENTS STACK [0] | + * | ... | + * zend_vm_stack_top --------> | ... | + * | ... | + * | ARGUMENTS STACK [op_array->used_stack] | + * +----------------------------------------+ + */ + +zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC) +{ zend_execute_data *execute_data; /* @@ -354,7 +397,9 @@ zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_arra size_t execute_data_size = ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)); size_t CVs_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval **) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)); size_t Ts_size = ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T; - size_t total_size = execute_data_size + CVs_size + Ts_size; + size_t call_slots_size = ZEND_MM_ALIGNED_SIZE(sizeof(call_slot)) * op_array->nested_calls; + size_t stack_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * op_array->used_stack; + size_t total_size = execute_data_size + Ts_size + CVs_size + call_slots_size + stack_size; /* * Normally the execute_data is allocated on the VM stack (because it does @@ -366,23 +411,58 @@ zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_arra * by replacing a pointer. */ if (op_array->fn_flags & ZEND_ACC_GENERATOR) { - execute_data = emalloc(total_size); + /* Prepend the regular stack frame with copy on prev_execute_data + * and passed arguments + */ + int args_count = zend_vm_stack_get_args_count_ex(EG(current_execute_data)); + size_t args_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * (args_count + 1); + + total_size += args_size + execute_data_size; + + EG(argument_stack) = zend_vm_stack_new_page((total_size + (sizeof(void*) - 1)) / sizeof(void*)); + EG(argument_stack)->prev = NULL; + execute_data = (zend_execute_data*)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + args_size + execute_data_size); + + /* copy prev_execute_data */ + EX(prev_execute_data) = (zend_execute_data*)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + args_size); + memset(EX(prev_execute_data), 0, sizeof(zend_execute_data)); + EX(prev_execute_data)->function_state.function = (zend_function*)op_array; + EX(prev_execute_data)->function_state.arguments = (void**)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * args_count); + + /* copy arguemnts */ + *EX(prev_execute_data)->function_state.arguments = (void*)(zend_uintptr_t)args_count; + if (args_count > 0) { + zval **arg_src = (zval**)zend_vm_stack_get_arg_ex(EG(current_execute_data), 1); + zval **arg_dst = (zval**)zend_vm_stack_get_arg_ex(EX(prev_execute_data), 1); + int i; + + for (i = 0; i < args_count; i++) { + arg_dst[i] = arg_src[i]; + Z_ADDREF_P(arg_dst[i]); + } + } } else { execute_data = zend_vm_stack_alloc(total_size TSRMLS_CC); + EX(prev_execute_data) = EG(current_execute_data); } - EX(CVs) = (zval ***) ((char *) execute_data + execute_data_size); + EX(Ts) = (temp_variable *) ((char *) execute_data + execute_data_size); + + EX(CVs) = (zval ***) ((char *) EX(Ts) + Ts_size); memset(EX(CVs), 0, sizeof(zval **) * op_array->last_var); - EX(Ts) = (temp_variable *) ((char *) EX(CVs) + CVs_size); + EX(call_slots) = (call_slot*)((char *) EX(CVs) + CVs_size); + + + EX(op_array) = op_array; + + EG(argument_stack)->top = zend_vm_stack_frame_base(execute_data); - EX(fbc) = NULL; - EX(called_scope) = NULL; EX(object) = NULL; + EX(current_this) = NULL; EX(old_error_reporting) = NULL; - EX(op_array) = op_array; EX(symbol_table) = EG(active_symbol_table); - EX(prev_execute_data) = EG(current_execute_data); + EX(call) = NULL; EG(current_execute_data) = execute_data; EX(nested) = nested; @@ -452,12 +532,12 @@ ZEND_API void execute_ex(zend_execute_data *execute_data TSRMLS_DC) zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen"); } -ZEND_API void execute(zend_op_array *op_array TSRMLS_DC) +ZEND_API void zend_execute(zend_op_array *op_array TSRMLS_DC) { if (EG(exception)) { return; } - execute_ex(zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC) TSRMLS_CC); + zend_execute_ex(zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC) TSRMLS_CC); } static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) @@ -509,7 +589,6 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) EX(function_state).function = (zend_function *) EX(op_array); EX(function_state).arguments = NULL; - EX(object) = EX(current_object); EG(opline_ptr) = &EX(opline); EG(active_op_array) = EX(op_array); @@ -545,8 +624,8 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) EX(function_state).arguments = NULL; if (EG(This)) { - if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) { - if (IS_CTOR_USED(EX(called_scope))) { + if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { + if (EX(call)->is_ctor_result_used) { Z_DELREF_P(EG(This)); } if (Z_REFCOUNT_P(EG(This)) == 1) { @@ -559,8 +638,7 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) EG(scope) = EX(current_scope); EG(called_scope) = EX(current_called_scope); - EX(object) = EX(current_object); - EX(called_scope) = DECODE_CTOR(EX(called_scope)); + EX(call)--; zend_vm_stack_clear_multiple(TSRMLS_C); @@ -586,6 +664,7 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR zend_function *fbc = EX(function_state).function; SAVE_OPLINE(); + EX(object) = EX(call)->object; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name, fbc->common.function_name); @@ -620,11 +699,11 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR EX(current_called_scope) = EG(called_scope); EG(This) = EX(object); EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ? fbc->common.scope : NULL; - EG(called_scope) = EX(called_scope); + EG(called_scope) = EX(call)->called_scope; } - zend_arg_types_stack_3_pop(&EG(arg_types_stack), &EX(called_scope), &EX(current_object), &EX(fbc)); - EX(function_state).arguments = zend_vm_stack_push_args(opline->extended_value TSRMLS_CC); + EX(function_state).arguments = zend_vm_stack_top(TSRMLS_C); + zend_vm_stack_push((void*)(zend_uintptr_t)opline->extended_value TSRMLS_CC); LOAD_OPLINE(); if (fbc->type == ZEND_INTERNAL_FUNCTION) { @@ -674,7 +753,7 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR if (RETURN_VALUE_USED(opline)) { EX_T(opline->result.var).var.ptr = zend_generator_create_zval(EG(active_op_array) TSRMLS_CC); } - } else if (EXPECTED(zend_execute == execute)) { + } else if (EXPECTED(zend_execute_ex == execute_ex)) { if (EXPECTED(EG(exception) == NULL)) { ZEND_VM_ENTER(); } @@ -720,8 +799,8 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR if (should_change_scope) { if (EG(This)) { - if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) { - if (IS_CTOR_USED(EX(called_scope))) { + if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) { + if (EX(call)->is_ctor_result_used) { Z_DELREF_P(EG(This)); } if (Z_REFCOUNT_P(EG(This)) == 1) { @@ -735,8 +814,7 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR EG(called_scope) = EX(current_called_scope); } - EX(object) = EX(current_object); - EX(called_scope) = DECODE_CTOR(EX(called_scope)); + EX(call)--; zend_vm_stack_clear_multiple(TSRMLS_C); @@ -780,7 +858,7 @@ static int ZEND_FASTCALL ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS static int ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - EX(function_state).function = EX(fbc); + EX(function_state).function = EX(call)->fbc; return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } @@ -860,17 +938,20 @@ static int ZEND_FASTCALL ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } ZEND_VM_JMP(EX(op_array)->opcodes + opline->op2.opline_num); } else { + call_slot *call = EX(call_slots) + opline->extended_value; + if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(object_zval); AI_SET_PTR(&EX_T(opline->result.var), object_zval); } - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), ENCODE_CTOR(EX(called_scope), RETURN_VALUE_USED(opline))); - /* We are not handling overloaded classes right now */ - EX(object) = object_zval; - EX(fbc) = constructor; - EX(called_scope) = EX_T(opline->op1.var).class_entry; + call->fbc = constructor; + call->object = object_zval; + call->called_scope = EX_T(opline->op1.var).class_entry; + call->is_ctor_call = 1; + call->is_ctor_result_used = RETURN_VALUE_USED(opline); + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1075,19 +1156,7 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER /* Figure out where the next stack frame (which maybe contains pushed * arguments that have to be dtor'ed) starts */ - if (EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) { - /* The generator object is stored in return_value_ptr_ptr */ - zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr); - - /* For generators the next stack frame is conveniently stored in the - * generator object. */ - stack_frame = generator->original_stack_top; - } else { - /* In all other cases the next stack frame starts after the temporary - * variables section of the current execution context */ - stack_frame = (void **) ((char *) EX_Ts() + - ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * EX(op_array)->T); - } + stack_frame = zend_vm_stack_frame_base(execute_data); /* If the exception was thrown during a function call there might be * arguments pushed to the stack that have to be dtor'ed. */ @@ -1109,21 +1178,23 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER } } - while (EX(fbc)) { - EX(called_scope) = (zend_class_entry*)zend_ptr_stack_pop(&EG(arg_types_stack)); - if (EX(object)) { - if (IS_CTOR_CALL(EX(called_scope))) { - if (IS_CTOR_USED(EX(called_scope))) { - Z_DELREF_P(EX(object)); - } - if (Z_REFCOUNT_P(EX(object)) == 1) { - zend_object_store_ctor_failed(EX(object) TSRMLS_CC); + if (EX(call) >= EX(call_slots)) { + call_slot *call = EX(call); + do { + if (call->object) { + if (call->is_ctor_call) { + if (call->is_ctor_result_used) { + Z_DELREF_P(call->object); + } + if (Z_REFCOUNT_P(call->object) == 1) { + zend_object_store_ctor_failed(call->object TSRMLS_CC); + } } + zval_ptr_dtor(&call->object); } - zval_ptr_dtor(&EX(object)); - } - EX(called_scope) = DECODE_CTOR(EX(called_scope)); - zend_arg_types_stack_2_pop(&EG(arg_types_stack), &EX(object), &EX(fbc)); + call--; + } while (call >= EX(call_slots)); + EX(call) = NULL; } for (i=0; i<EX(op_array)->last_brk_cont; i++) { @@ -1213,6 +1284,19 @@ static int ZEND_FASTCALL ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS } } +static int ZEND_FASTCALL ZEND_GENERATOR_FLAG_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr); + + if (opline->extended_value) { + generator->flags |= ZEND_GENERATOR_FORCED_CLOSE; + } else { + generator->flags &= ~ZEND_GENERATOR_FORCED_CLOSE; + } + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -1291,19 +1375,21 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE { USE_OPLINE zval *function_name; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); + call_slot *call = EX(call_slots) + opline->result.num; if (IS_CONST == IS_CONST) { function_name = (zval*)(opline->op2.literal+1); if (CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); - } 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)) { + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); + } 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)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } - EX(object) = NULL; + call->object = NULL; + call->is_ctor_call = 0; + EX(call) = call; /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { @@ -1323,28 +1409,32 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE } else { lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); } - if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &EX(fbc)) == FAILURE)) { + if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); - EX(object) = NULL; + call->object = NULL; + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_CONST != IS_CONST && IS_CONST != IS_TMP_VAR && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) { - if (EX(object)) { - Z_ADDREF_P(EX(object)); + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { + if (call->object) { + Z_ADDREF_P(call->object); } if (IS_CONST == IS_VAR && 0 && - EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) { + call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - EX(fbc)->common.prototype = (zend_function*)function_name; + call->fbc->common.prototype = (zend_function*)function_name; } else { } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_CONST != IS_CONST && @@ -1375,41 +1465,43 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - EX(called_scope) = ce; - EX(object) = NULL; + call->called_scope = ce; + call->object = NULL; if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC); + call->fbc = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); + call->fbc = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); } } else { - EX(object) = *obj; - ce = EX(called_scope) = Z_OBJCE_PP(obj); + call->object = *obj; + ce = call->called_scope = Z_OBJCE_PP(obj); - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method)); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_PP(method)); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1424,25 +1516,26 @@ static int ZEND_FASTCALL ZEND_INIT_NS_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPC { USE_OPLINE zend_literal *func_name; - - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); + call_slot *call = EX(call_slots) + opline->result.num; func_name = opline->op2.literal + 1; if (CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); - } 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) { + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); + } 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) { func_name++; - 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)) { + 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)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } } else { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } - EX(object) = NULL; + call->object = NULL; + call->is_ctor_call = 0; + EX(call) = call; ZEND_VM_NEXT_OPCODE(); } @@ -1599,19 +1692,21 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H { USE_OPLINE zval *function_name; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); + call_slot *call = EX(call_slots) + opline->result.num; if (IS_TMP_VAR == IS_CONST) { function_name = (zval*)(opline->op2.literal+1); if (CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); - } 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)) { + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); + } 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)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } - EX(object) = NULL; + call->object = NULL; + call->is_ctor_call = 0; + EX(call) = call; /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { @@ -1631,28 +1726,32 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H } else { lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); } - if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &EX(fbc)) == FAILURE)) { + if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); zval_dtor(free_op2.var); - EX(object) = NULL; + call->object = NULL; + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_TMP_VAR != IS_CONST && IS_TMP_VAR != IS_TMP_VAR && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) { - if (EX(object)) { - Z_ADDREF_P(EX(object)); + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { + if (call->object) { + Z_ADDREF_P(call->object); } if (IS_TMP_VAR == IS_VAR && 1 && - EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) { + call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - EX(fbc)->common.prototype = (zend_function*)function_name; + call->fbc->common.prototype = (zend_function*)function_name; } else { zval_dtor(free_op2.var); } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_TMP_VAR != IS_CONST && @@ -1683,41 +1782,43 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - EX(called_scope) = ce; - EX(object) = NULL; + call->called_scope = ce; + call->object = NULL; if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC); + call->fbc = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); + call->fbc = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); } } else { - EX(object) = *obj; - ce = EX(called_scope) = Z_OBJCE_PP(obj); + call->object = *obj; + ce = call->called_scope = Z_OBJCE_PP(obj); - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method)); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_PP(method)); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); } + call->is_ctor_call = 0; + EX(call) = call; zval_dtor(free_op2.var); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1769,19 +1870,21 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H { USE_OPLINE zval *function_name; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); + call_slot *call = EX(call_slots) + opline->result.num; if (IS_VAR == IS_CONST) { function_name = (zval*)(opline->op2.literal+1); if (CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); - } 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)) { + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); + } 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)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } - EX(object) = NULL; + call->object = NULL; + call->is_ctor_call = 0; + EX(call) = call; /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { @@ -1801,28 +1904,32 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H } else { lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); } - if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &EX(fbc)) == FAILURE)) { + if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; - EX(object) = NULL; + call->object = NULL; + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_VAR != IS_CONST && IS_VAR != IS_TMP_VAR && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) { - if (EX(object)) { - Z_ADDREF_P(EX(object)); + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { + if (call->object) { + Z_ADDREF_P(call->object); } if (IS_VAR == IS_VAR && (free_op2.var != NULL) && - EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) { + call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - EX(fbc)->common.prototype = (zend_function*)function_name; + call->fbc->common.prototype = (zend_function*)function_name; } else { if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_VAR != IS_CONST && @@ -1853,41 +1960,43 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - EX(called_scope) = ce; - EX(object) = NULL; + call->called_scope = ce; + call->object = NULL; if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC); + call->fbc = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); + call->fbc = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); } } else { - EX(object) = *obj; - ce = EX(called_scope) = Z_OBJCE_PP(obj); + call->object = *obj; + ce = call->called_scope = Z_OBJCE_PP(obj); - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method)); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_PP(method)); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); } + call->is_ctor_call = 0; + EX(call) = call; if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -1974,19 +2083,21 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA { USE_OPLINE zval *function_name; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); + call_slot *call = EX(call_slots) + opline->result.num; if (IS_CV == IS_CONST) { function_name = (zval*)(opline->op2.literal+1); if (CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); - } 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)) { + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); + } 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)) { SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } else { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } - EX(object) = NULL; + call->object = NULL; + call->is_ctor_call = 0; + EX(call) = call; /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } else { @@ -2006,28 +2117,32 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA } else { lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); } - if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &EX(fbc)) == FAILURE)) { + if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &call->fbc) == FAILURE)) { zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); } efree(lcname); - EX(object) = NULL; + call->object = NULL; + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_CV != IS_CONST && IS_CV != IS_TMP_VAR && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && - Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) { - if (EX(object)) { - Z_ADDREF_P(EX(object)); + Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { + if (call->object) { + Z_ADDREF_P(call->object); } if (IS_CV == IS_VAR && 0 && - EX(fbc)->common.fn_flags & ZEND_ACC_CLOSURE) { + call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ - EX(fbc)->common.prototype = (zend_function*)function_name; + call->fbc->common.prototype = (zend_function*)function_name; } else { } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else if (IS_CV != IS_CONST && @@ -2058,41 +2173,43 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - EX(called_scope) = ce; - EX(object) = NULL; + call->called_scope = ce; + call->object = NULL; if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC); + call->fbc = ce->get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method) TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); + call->fbc = zend_std_get_static_method(ce, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); } } else { - EX(object) = *obj; - ce = EX(called_scope) = Z_OBJCE_PP(obj); + call->object = *obj; + ce = call->called_scope = Z_OBJCE_PP(obj); - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method)); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, Z_STRVAL_PP(method), Z_STRLEN_PP(method), NULL TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), Z_STRVAL_PP(method)); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, Z_STRVAL_PP(method)); } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -2328,8 +2445,7 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A USE_OPLINE zval *fname = opline->op1.zv; - - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); + call_slot *call = EX(call_slots) + opline->op2.num; if (CACHED_PTR(opline->op1.literal->cache_slot)) { EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot); @@ -2339,7 +2455,10 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A } else { CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function); } - EX(object) = NULL; + call->fbc = EX(function_state).function; + call->object = NULL; + call->is_ctor_call = 0; + EX(call) = call; return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } @@ -2498,7 +2617,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A SAVE_OPLINE(); if (opline->extended_value==ZEND_DO_FCALL_BY_NAME - && ARG_MUST_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + && ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.opline_num); } { @@ -2754,8 +2873,6 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HA EG(return_value_ptr_ptr) = NULL; } - EX(current_object) = EX(object); - EX(function_state).function = (zend_function *) new_op_array; EX(object) = NULL; @@ -2763,14 +2880,13 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HA zend_rebuild_symbol_table(TSRMLS_C); } - if (EXPECTED(zend_execute == execute)) { + if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { zend_execute(new_op_array TSRMLS_CC); } EX(function_state).function = (zend_function *) EX(op_array); - EX(object) = EX(current_object); EG(opline_ptr) = &EX(opline); EG(active_op_array) = EX(op_array); @@ -3497,7 +3613,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CONST_CONST_HANDLER(ZEND_OPCO { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CONST_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CONST_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -3569,9 +3685,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( USE_OPLINE zval *function_name; zend_class_entry *ce; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CONST == IS_CONST) { /* no function found. try a static method in class */ @@ -3585,24 +3701,24 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( } CACHE_PTR(opline->op1.literal->cache_slot, ce); } - EX(called_scope) = ce; + call->called_scope = ce; } else { ce = EX_T(opline->op1.var).class_entry; if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - EX(called_scope) = EG(called_scope); + call->called_scope = EG(called_scope); } else { - EX(called_scope) = ce; + call->called_scope = ce; } } if (IS_CONST == IS_CONST && IS_CONST == IS_CONST && CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); } else if (IS_CONST != IS_CONST && IS_CONST == IS_CONST && - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { /* do nothing */ } else if (IS_CONST != IS_UNUSED) { char *function_name_strval = NULL; @@ -3625,20 +3741,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( if (function_name_strval) { if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + call->fbc = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + call->fbc = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval); } if (IS_CONST == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_CONST == IS_CONST) { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } else { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, call->fbc); } } } @@ -3652,29 +3768,31 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER( if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name); } - EX(fbc) = ce->constructor; + call->fbc = ce->constructor; } - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; + if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { + call->object = NULL; } else { if (EG(This) && Z_OBJ_HT_P(EG(This))->get_class_entry && !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { /* We are calling method of the other (incompatible) class, but passing $this. This is done for compatibility with php-4. */ - if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - 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); + if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + 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); } else { /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - 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); + 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); } } - if ((EX(object) = EG(This))) { - Z_ADDREF_P(EX(object)); - EX(called_scope) = Z_OBJCE_P(EX(object)); + if ((call->object = EG(This))) { + Z_ADDREF_P(call->object); + call->called_scope = Z_OBJCE_P(call->object); } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -4555,9 +4673,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE USE_OPLINE zval *function_name; zend_class_entry *ce; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CONST == IS_CONST) { /* no function found. try a static method in class */ @@ -4571,24 +4689,24 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE } CACHE_PTR(opline->op1.literal->cache_slot, ce); } - EX(called_scope) = ce; + call->called_scope = ce; } else { ce = EX_T(opline->op1.var).class_entry; if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - EX(called_scope) = EG(called_scope); + call->called_scope = EG(called_scope); } else { - EX(called_scope) = ce; + call->called_scope = ce; } } if (IS_CONST == IS_CONST && IS_TMP_VAR == IS_CONST && CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); } else if (IS_CONST != IS_CONST && IS_TMP_VAR == IS_CONST && - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { /* do nothing */ } else if (IS_TMP_VAR != IS_UNUSED) { char *function_name_strval = NULL; @@ -4611,20 +4729,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE if (function_name_strval) { if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + call->fbc = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + call->fbc = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval); } if (IS_TMP_VAR == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_CONST == IS_CONST) { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } else { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, call->fbc); } } } @@ -4638,29 +4756,31 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZE if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name); } - EX(fbc) = ce->constructor; + call->fbc = ce->constructor; } - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; + if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { + call->object = NULL; } else { if (EG(This) && Z_OBJ_HT_P(EG(This))->get_class_entry && !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { /* We are calling method of the other (incompatible) class, but passing $this. This is done for compatibility with php-4. */ - if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - 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); + if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + 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); } else { /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - 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); + 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); } } - if ((EX(object) = EG(This))) { - Z_ADDREF_P(EX(object)); - EX(called_scope) = Z_OBJCE_P(EX(object)); + if ((call->object = EG(This))) { + Z_ADDREF_P(call->object); + call->called_scope = Z_OBJCE_P(call->object); } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -5365,7 +5485,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CONST_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CONST_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -5413,9 +5533,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE USE_OPLINE zval *function_name; zend_class_entry *ce; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CONST == IS_CONST) { /* no function found. try a static method in class */ @@ -5429,24 +5549,24 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE } CACHE_PTR(opline->op1.literal->cache_slot, ce); } - EX(called_scope) = ce; + call->called_scope = ce; } else { ce = EX_T(opline->op1.var).class_entry; if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - EX(called_scope) = EG(called_scope); + call->called_scope = EG(called_scope); } else { - EX(called_scope) = ce; + call->called_scope = ce; } } if (IS_CONST == IS_CONST && IS_VAR == IS_CONST && CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); } else if (IS_CONST != IS_CONST && IS_VAR == IS_CONST && - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { /* do nothing */ } else if (IS_VAR != IS_UNUSED) { char *function_name_strval = NULL; @@ -5469,20 +5589,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE if (function_name_strval) { if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + call->fbc = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + call->fbc = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval); } if (IS_VAR == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_CONST == IS_CONST) { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } else { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, call->fbc); } } } @@ -5496,29 +5616,31 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZE if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name); } - EX(fbc) = ce->constructor; + call->fbc = ce->constructor; } - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; + if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { + call->object = NULL; } else { if (EG(This) && Z_OBJ_HT_P(EG(This))->get_class_entry && !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { /* We are calling method of the other (incompatible) class, but passing $this. This is done for compatibility with php-4. */ - if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - 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); + if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + 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); } else { /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - 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); + 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); } } - if ((EX(object) = EG(This))) { - Z_ADDREF_P(EX(object)); - EX(called_scope) = Z_OBJCE_P(EX(object)); + if ((call->object = EG(This))) { + Z_ADDREF_P(call->object); + call->called_scope = Z_OBJCE_P(call->object); } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -6109,7 +6231,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CONST_UNUSED_HANDLER(ZEND_OPC { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CONST_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CONST_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -6127,9 +6249,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER USE_OPLINE zval *function_name; zend_class_entry *ce; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CONST == IS_CONST) { /* no function found. try a static method in class */ @@ -6143,24 +6265,24 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER } CACHE_PTR(opline->op1.literal->cache_slot, ce); } - EX(called_scope) = ce; + call->called_scope = ce; } else { ce = EX_T(opline->op1.var).class_entry; if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - EX(called_scope) = EG(called_scope); + call->called_scope = EG(called_scope); } else { - EX(called_scope) = ce; + call->called_scope = ce; } } if (IS_CONST == IS_CONST && IS_UNUSED == IS_CONST && CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); } else if (IS_CONST != IS_CONST && IS_UNUSED == IS_CONST && - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { /* do nothing */ } else if (IS_UNUSED != IS_UNUSED) { char *function_name_strval = NULL; @@ -6183,20 +6305,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER if (function_name_strval) { if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + call->fbc = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_UNUSED == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + call->fbc = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_UNUSED == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval); } if (IS_UNUSED == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_CONST == IS_CONST) { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } else { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, call->fbc); } } } @@ -6210,29 +6332,31 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name); } - EX(fbc) = ce->constructor; + call->fbc = ce->constructor; } - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; + if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { + call->object = NULL; } else { if (EG(This) && Z_OBJ_HT_P(EG(This))->get_class_entry && !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { /* We are calling method of the other (incompatible) class, but passing $this. This is done for compatibility with php-4. */ - if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - 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); + if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + 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); } else { /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - 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); + 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); } } - if ((EX(object) = EG(This))) { - Z_ADDREF_P(EX(object)); - EX(called_scope) = Z_OBJCE_P(EX(object)); + if ((call->object = EG(This))) { + Z_ADDREF_P(call->object); + call->called_scope = Z_OBJCE_P(call->object); } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -6982,9 +7106,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN USE_OPLINE zval *function_name; zend_class_entry *ce; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CONST == IS_CONST) { /* no function found. try a static method in class */ @@ -6998,24 +7122,24 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN } CACHE_PTR(opline->op1.literal->cache_slot, ce); } - EX(called_scope) = ce; + call->called_scope = ce; } else { ce = EX_T(opline->op1.var).class_entry; if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - EX(called_scope) = EG(called_scope); + call->called_scope = EG(called_scope); } else { - EX(called_scope) = ce; + call->called_scope = ce; } } if (IS_CONST == IS_CONST && IS_CV == IS_CONST && CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); } else if (IS_CONST != IS_CONST && IS_CV == IS_CONST && - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { /* do nothing */ } else if (IS_CV != IS_UNUSED) { char *function_name_strval = NULL; @@ -7038,20 +7162,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN if (function_name_strval) { if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + call->fbc = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + call->fbc = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval); } if (IS_CV == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_CONST == IS_CONST) { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } else { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, call->fbc); } } } @@ -7065,29 +7189,31 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEN if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name); } - EX(fbc) = ce->constructor; + call->fbc = ce->constructor; } - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; + if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { + call->object = NULL; } else { if (EG(This) && Z_OBJ_HT_P(EG(This))->get_class_entry && !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { /* We are calling method of the other (incompatible) class, but passing $this. This is done for compatibility with php-4. */ - if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - 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); + if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + 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); } else { /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - 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); + 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); } } - if ((EX(object) = EG(This))) { - Z_ADDREF_P(EX(object)); - EX(called_scope) = Z_OBJCE_P(EX(object)); + if ((call->object = EG(This))) { + Z_ADDREF_P(call->object); + call->called_scope = Z_OBJCE_P(call->object); } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -7813,7 +7939,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG SAVE_OPLINE(); if (opline->extended_value==ZEND_DO_FCALL_BY_NAME - && ARG_MUST_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + && ARG_MUST_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.opline_num); } { @@ -8070,8 +8196,6 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HAND EG(return_value_ptr_ptr) = NULL; } - EX(current_object) = EX(object); - EX(function_state).function = (zend_function *) new_op_array; EX(object) = NULL; @@ -8079,14 +8203,13 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HAND zend_rebuild_symbol_table(TSRMLS_C); } - if (EXPECTED(zend_execute == execute)) { + if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { zend_execute(new_op_array TSRMLS_CC); } EX(function_state).function = (zend_function *) EX(op_array); - EX(object) = EX(current_object); EG(opline_ptr) = &EX(opline); EG(active_op_array) = EX(op_array); @@ -8865,7 +8988,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_TMP_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_TMP_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -8985,9 +9108,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCO char *function_name_strval; int function_name_strlen; zend_free_op free_op1; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = opline->op2.zv; @@ -8999,49 +9122,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCO function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); + call->object = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_CONST != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_CONST == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); @@ -9838,9 +9963,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE char *function_name_strval; int function_name_strlen; zend_free_op free_op1, free_op2; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_tmp(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC); @@ -9852,49 +9977,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); + call->object = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_TMP_VAR != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_TMP_VAR == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; zval_dtor(free_op2.var); @@ -10601,7 +10728,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_H { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_TMP_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_TMP_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -10696,9 +10823,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE char *function_name_strval; int function_name_strlen; zend_free_op free_op1, free_op2; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_var(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC); @@ -10710,49 +10837,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); + call->object = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_VAR != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_VAR == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; @@ -11345,7 +11474,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCOD { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_TMP_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_TMP_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -12130,9 +12259,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_ char *function_name_strval; int function_name_strlen; zend_free_op free_op1; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op2.var TSRMLS_CC); @@ -12144,49 +12273,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_ function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); + call->object = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_CV != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_CV == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); @@ -13067,7 +13198,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) { return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } - } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } @@ -13093,7 +13224,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : - !ARG_MAY_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } ALLOC_ZVAL(valptr); @@ -13129,7 +13260,7 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG ZEND_VM_NEXT_OPCODE(); } - if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && !ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && !ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } @@ -13148,7 +13279,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG USE_OPLINE if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME) - && ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + && ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { return ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } SAVE_OPLINE(); @@ -13400,8 +13531,6 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND EG(return_value_ptr_ptr) = NULL; } - EX(current_object) = EX(object); - EX(function_state).function = (zend_function *) new_op_array; EX(object) = NULL; @@ -13409,14 +13538,13 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND zend_rebuild_symbol_table(TSRMLS_C); } - if (EXPECTED(zend_execute == execute)) { + if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { zend_execute(new_op_array TSRMLS_CC); } EX(function_state).function = (zend_function *) EX(op_array); - EX(object) = EX(current_object); EG(opline_ptr) = &EX(opline); EG(active_op_array) = EX(op_array); @@ -14772,7 +14900,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_VAR_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_VAR_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -14894,7 +15022,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_CONST_HANDLER(ZEND_OP SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { container = _get_zval_ptr_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -15130,7 +15258,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_CONST_HANDLER(ZEND_OP { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -15378,9 +15506,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCO char *function_name_strval; int function_name_strlen; zend_free_op free_op1; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = opline->op2.zv; @@ -15392,49 +15520,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCO function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); + call->object = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_CONST != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_CONST == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; @@ -15447,9 +15577,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE USE_OPLINE zval *function_name; zend_class_entry *ce; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_VAR == IS_CONST) { /* no function found. try a static method in class */ @@ -15463,24 +15593,24 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE } CACHE_PTR(opline->op1.literal->cache_slot, ce); } - EX(called_scope) = ce; + call->called_scope = ce; } else { ce = EX_T(opline->op1.var).class_entry; if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - EX(called_scope) = EG(called_scope); + call->called_scope = EG(called_scope); } else { - EX(called_scope) = ce; + call->called_scope = ce; } } if (IS_VAR == IS_CONST && IS_CONST == IS_CONST && CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); } else if (IS_VAR != IS_CONST && IS_CONST == IS_CONST && - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { /* do nothing */ } else if (IS_CONST != IS_UNUSED) { char *function_name_strval = NULL; @@ -15503,20 +15633,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE if (function_name_strval) { if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + call->fbc = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + call->fbc = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval); } if (IS_CONST == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_VAR == IS_CONST) { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } else { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, call->fbc); } } } @@ -15530,29 +15660,31 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZE if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name); } - EX(fbc) = ce->constructor; + call->fbc = ce->constructor; } - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; + if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { + call->object = NULL; } else { if (EG(This) && Z_OBJ_HT_P(EG(This))->get_class_entry && !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { /* We are calling method of the other (incompatible) class, but passing $this. This is done for compatibility with php-4. */ - if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - 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); + if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + 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); } else { /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - 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); + 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); } } - if ((EX(object) = EG(This))) { - Z_ADDREF_P(EX(object)); - EX(called_scope) = Z_OBJCE_P(EX(object)); + if ((call->object = EG(This))) { + Z_ADDREF_P(call->object); + call->called_scope = Z_OBJCE_P(call->object); } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -17227,7 +17359,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_TMP_HANDLER(ZEND_OPCO SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { container = _get_zval_ptr_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -17463,7 +17595,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_TMP_HANDLER(ZEND_OPCO { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -17712,9 +17844,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE char *function_name_strval; int function_name_strlen; zend_free_op free_op1, free_op2; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_tmp(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC); @@ -17726,49 +17858,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); + call->object = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_TMP_VAR != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_TMP_VAR == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; zval_dtor(free_op2.var); if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; @@ -17782,9 +17916,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND USE_OPLINE zval *function_name; zend_class_entry *ce; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_VAR == IS_CONST) { /* no function found. try a static method in class */ @@ -17798,24 +17932,24 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND } CACHE_PTR(opline->op1.literal->cache_slot, ce); } - EX(called_scope) = ce; + call->called_scope = ce; } else { ce = EX_T(opline->op1.var).class_entry; if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - EX(called_scope) = EG(called_scope); + call->called_scope = EG(called_scope); } else { - EX(called_scope) = ce; + call->called_scope = ce; } } if (IS_VAR == IS_CONST && IS_TMP_VAR == IS_CONST && CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); } else if (IS_VAR != IS_CONST && IS_TMP_VAR == IS_CONST && - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { /* do nothing */ } else if (IS_TMP_VAR != IS_UNUSED) { char *function_name_strval = NULL; @@ -17838,20 +17972,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND if (function_name_strval) { if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + call->fbc = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + call->fbc = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval); } if (IS_TMP_VAR == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_VAR == IS_CONST) { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } else { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, call->fbc); } } } @@ -17865,29 +17999,31 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name); } - EX(fbc) = ce->constructor; + call->fbc = ce->constructor; } - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; + if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { + call->object = NULL; } else { if (EG(This) && Z_OBJ_HT_P(EG(This))->get_class_entry && !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { /* We are calling method of the other (incompatible) class, but passing $this. This is done for compatibility with php-4. */ - if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - 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); + if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + 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); } else { /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - 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); + 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); } } - if ((EX(object) = EG(This))) { - Z_ADDREF_P(EX(object)); - EX(called_scope) = Z_OBJCE_P(EX(object)); + if ((call->object = EG(This))) { + Z_ADDREF_P(call->object); + call->called_scope = Z_OBJCE_P(call->object); } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -19352,7 +19488,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_H { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_VAR_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_VAR_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -19474,7 +19610,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_VAR_HANDLER(ZEND_OPCO SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { container = _get_zval_ptr_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -19710,7 +19846,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_VAR_HANDLER(ZEND_OPCO { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -20014,9 +20150,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE char *function_name_strval; int function_name_strlen; zend_free_op free_op1, free_op2; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_var(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC); @@ -20028,49 +20164,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); + call->object = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_VAR != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_VAR == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; @@ -20084,9 +20222,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND USE_OPLINE zval *function_name; zend_class_entry *ce; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_VAR == IS_CONST) { /* no function found. try a static method in class */ @@ -20100,24 +20238,24 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND } CACHE_PTR(opline->op1.literal->cache_slot, ce); } - EX(called_scope) = ce; + call->called_scope = ce; } else { ce = EX_T(opline->op1.var).class_entry; if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - EX(called_scope) = EG(called_scope); + call->called_scope = EG(called_scope); } else { - EX(called_scope) = ce; + call->called_scope = ce; } } if (IS_VAR == IS_CONST && IS_VAR == IS_CONST && CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); } else if (IS_VAR != IS_CONST && IS_VAR == IS_CONST && - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { /* do nothing */ } else if (IS_VAR != IS_UNUSED) { char *function_name_strval = NULL; @@ -20140,20 +20278,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND if (function_name_strval) { if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + call->fbc = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + call->fbc = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval); } if (IS_VAR == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_VAR == IS_CONST) { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } else { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, call->fbc); } } } @@ -20167,29 +20305,31 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name); } - EX(fbc) = ce->constructor; + call->fbc = ce->constructor; } - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; + if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { + call->object = NULL; } else { if (EG(This) && Z_OBJ_HT_P(EG(This))->get_class_entry && !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { /* We are calling method of the other (incompatible) class, but passing $this. This is done for compatibility with php-4. */ - if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - 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); + if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + 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); } else { /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - 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); + 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); } } - if ((EX(object) = EG(This))) { - Z_ADDREF_P(EX(object)); - EX(called_scope) = Z_OBJCE_P(EX(object)); + if ((call->object = EG(This))) { + Z_ADDREF_P(call->object); + call->called_scope = Z_OBJCE_P(call->object); } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -21333,7 +21473,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCOD { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_VAR_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_VAR_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -21410,7 +21550,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_UNUSED_HANDLER(ZEND_O SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { container = _get_zval_ptr_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -21517,9 +21657,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z USE_OPLINE zval *function_name; zend_class_entry *ce; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_VAR == IS_CONST) { /* no function found. try a static method in class */ @@ -21533,24 +21673,24 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z } CACHE_PTR(opline->op1.literal->cache_slot, ce); } - EX(called_scope) = ce; + call->called_scope = ce; } else { ce = EX_T(opline->op1.var).class_entry; if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - EX(called_scope) = EG(called_scope); + call->called_scope = EG(called_scope); } else { - EX(called_scope) = ce; + call->called_scope = ce; } } if (IS_VAR == IS_CONST && IS_UNUSED == IS_CONST && CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); } else if (IS_VAR != IS_CONST && IS_UNUSED == IS_CONST && - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { /* do nothing */ } else if (IS_UNUSED != IS_UNUSED) { char *function_name_strval = NULL; @@ -21573,20 +21713,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z if (function_name_strval) { if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + call->fbc = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_UNUSED == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + call->fbc = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_UNUSED == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval); } if (IS_UNUSED == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_VAR == IS_CONST) { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } else { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, call->fbc); } } } @@ -21600,29 +21740,31 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(Z if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name); } - EX(fbc) = ce->constructor; + call->fbc = ce->constructor; } - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; + if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { + call->object = NULL; } else { if (EG(This) && Z_OBJ_HT_P(EG(This))->get_class_entry && !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { /* We are calling method of the other (incompatible) class, but passing $this. This is done for compatibility with php-4. */ - if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - 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); + if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + 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); } else { /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - 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); + 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); } } - if ((EX(object) = EG(This))) { - Z_ADDREF_P(EX(object)); - EX(called_scope) = Z_OBJCE_P(EX(object)); + if ((call->object = EG(This))) { + Z_ADDREF_P(call->object); + call->called_scope = Z_OBJCE_P(call->object); } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -22913,7 +23055,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_VAR_CV_HANDLER(ZEND_OPCOD SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { container = _get_zval_ptr_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -23149,7 +23291,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_VAR_CV_HANDLER(ZEND_OPCOD { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -23450,9 +23592,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_ char *function_name_strval; int function_name_strlen; zend_free_op free_op1; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op2.var TSRMLS_CC); @@ -23464,49 +23606,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_ function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); + call->object = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_CV != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_CV == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; @@ -23519,9 +23663,9 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ USE_OPLINE zval *function_name; zend_class_entry *ce; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_VAR == IS_CONST) { /* no function found. try a static method in class */ @@ -23535,24 +23679,24 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ } CACHE_PTR(opline->op1.literal->cache_slot, ce); } - EX(called_scope) = ce; + call->called_scope = ce; } else { ce = EX_T(opline->op1.var).class_entry; if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { - EX(called_scope) = EG(called_scope); + call->called_scope = EG(called_scope); } else { - EX(called_scope) = ce; + call->called_scope = ce; } } if (IS_VAR == IS_CONST && IS_CV == IS_CONST && CACHED_PTR(opline->op2.literal->cache_slot)) { - EX(fbc) = CACHED_PTR(opline->op2.literal->cache_slot); + call->fbc = CACHED_PTR(opline->op2.literal->cache_slot); } else if (IS_VAR != IS_CONST && IS_CV == IS_CONST && - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce))) { /* do nothing */ } else if (IS_CV != IS_UNUSED) { char *function_name_strval = NULL; @@ -23575,20 +23719,20 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ if (function_name_strval) { if (ce->get_static_method) { - EX(fbc) = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + call->fbc = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + call->fbc = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); } - if (UNEXPECTED(EX(fbc) == NULL)) { + if (UNEXPECTED(call->fbc == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval); } if (IS_CV == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) { if (IS_VAR == IS_CONST) { - CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc)); + CACHE_PTR(opline->op2.literal->cache_slot, call->fbc); } else { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, EX(fbc)); + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, ce, call->fbc); } } } @@ -23602,29 +23746,31 @@ static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_ if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name); } - EX(fbc) = ce->constructor; + call->fbc = ce->constructor; } - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; + if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) { + call->object = NULL; } else { if (EG(This) && Z_OBJ_HT_P(EG(This))->get_class_entry && !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { /* We are calling method of the other (incompatible) class, but passing $this. This is done for compatibility with php-4. */ - if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - 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); + if (call->fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + 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); } else { /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - 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); + 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); } } - if ((EX(object) = EG(This))) { - Z_ADDREF_P(EX(object)); - EX(called_scope) = Z_OBJCE_P(EX(object)); + if ((call->object = EG(This))) { + Z_ADDREF_P(call->object); + call->called_scope = Z_OBJCE_P(call->object); } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -24915,7 +25061,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_CONST_HANDLER(ZEND { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -25073,9 +25219,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_O char *function_name_strval; int function_name_strlen; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = opline->op2.zv; @@ -25087,49 +25233,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_O function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_obj_zval_ptr_unused(TSRMLS_C); + call->object = _get_obj_zval_ptr_unused(TSRMLS_C); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_CONST != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_CONST == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); @@ -26320,7 +26468,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_TMP_HANDLER(ZEND_O { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -26477,9 +26625,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPC char *function_name_strval; int function_name_strlen; zend_free_op free_op2; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_tmp(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC); @@ -26491,49 +26639,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPC function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_obj_zval_ptr_unused(TSRMLS_C); + call->object = _get_obj_zval_ptr_unused(TSRMLS_C); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_TMP_VAR != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_TMP_VAR == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; zval_dtor(free_op2.var); @@ -27633,7 +27783,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_VAR_HANDLER(ZEND_O { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -27790,9 +27940,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPC char *function_name_strval; int function_name_strlen; zend_free_op free_op2; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_var(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC); @@ -27804,49 +27954,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPC function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_obj_zval_ptr_unused(TSRMLS_C); + call->object = _get_obj_zval_ptr_unused(TSRMLS_C); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_VAR != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_VAR == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; @@ -29369,7 +29521,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_UNUSED_CV_HANDLER(ZEND_OP { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -29525,9 +29677,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCO char *function_name_strval; int function_name_strlen; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op2.var TSRMLS_CC); @@ -29539,49 +29691,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCO function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_obj_zval_ptr_unused(TSRMLS_C); + call->object = _get_obj_zval_ptr_unused(TSRMLS_C); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_CV != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_CV == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); @@ -30630,7 +30784,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) { return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } - } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } @@ -30656,7 +30810,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : - !ARG_MAY_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + !ARG_MAY_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } ALLOC_ZVAL(valptr); @@ -30692,7 +30846,7 @@ static int ZEND_FASTCALL ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS ZEND_VM_NEXT_OPCODE(); } - if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && !ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && !ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } @@ -30710,7 +30864,7 @@ static int ZEND_FASTCALL ZEND_SEND_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS USE_OPLINE if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME) - && ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + && ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, opline->op2.opline_num)) { return ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } SAVE_OPLINE(); @@ -30951,8 +31105,6 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL EG(return_value_ptr_ptr) = NULL; } - EX(current_object) = EX(object); - EX(function_state).function = (zend_function *) new_op_array; EX(object) = NULL; @@ -30960,14 +31112,13 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL zend_rebuild_symbol_table(TSRMLS_C); } - if (EXPECTED(zend_execute == execute)) { + if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { zend_execute(new_op_array TSRMLS_CC); } EX(function_state).function = (zend_function *) EX(op_array); - EX(object) = EX(current_object); EG(opline_ptr) = &EX(opline); EG(active_op_array) = EX(op_array); @@ -32176,7 +32327,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_ { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CV_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CV_CONST(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -32297,7 +32448,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_CONST_HANDLER(ZEND_OPC SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { container = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -32530,7 +32681,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_CONST_HANDLER(ZEND_OPC { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -32775,9 +32926,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCOD char *function_name_strval; int function_name_strlen; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = opline->op2.zv; @@ -32789,49 +32940,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCOD function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC); + call->object = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_CONST != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_CONST == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); @@ -34407,7 +34560,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_TMP_HANDLER(ZEND_OPCOD SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { container = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -34640,7 +34793,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_TMP_HANDLER(ZEND_OPCOD { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -34886,9 +35039,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_ char *function_name_strval; int function_name_strlen; zend_free_op free_op2; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_tmp(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC); @@ -34900,49 +35053,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_ function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC); + call->object = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_TMP_VAR != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_TMP_VAR == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; zval_dtor(free_op2.var); @@ -36402,7 +36557,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HA { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CV_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CV_VAR(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -36523,7 +36678,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_VAR_HANDLER(ZEND_OPCOD SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { container = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -36756,7 +36911,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_VAR_HANDLER(ZEND_OPCOD { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; zval *property; @@ -37056,9 +37211,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_ char *function_name_strval; int function_name_strlen; zend_free_op free_op2; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_var(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC); @@ -37070,49 +37225,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_ function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC); + call->object = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_VAR != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_VAR == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; @@ -38251,7 +38408,7 @@ static int ZEND_FASTCALL ZEND_FETCH_FUNC_ARG_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE { USE_OPLINE - return zend_fetch_var_address_helper_SPEC_CV_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + return zend_fetch_var_address_helper_SPEC_CV_UNUSED(ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL ZEND_FETCH_UNSET_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -38327,7 +38484,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_UNUSED_HANDLER(ZEND_OP SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { container = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -39689,7 +39846,7 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_FUNC_ARG_SPEC_CV_CV_HANDLER(ZEND_OPCODE SAVE_OPLINE(); - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { container = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->op1.var TSRMLS_CC); if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); @@ -39922,7 +40079,7 @@ static int ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CV_CV_HANDLER(ZEND_OPCODE { USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->fbc, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1; zval *property; @@ -40219,9 +40376,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_H char *function_name_strval; int function_name_strlen; + call_slot *call = EX(call_slots) + opline->result.num; SAVE_OPLINE(); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op2.var TSRMLS_CC); @@ -40233,49 +40390,51 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_H function_name_strval = Z_STRVAL_P(function_name); function_name_strlen = Z_STRLEN_P(function_name); - EX(object) = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC); + call->object = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC); - if (EXPECTED(EX(object) != NULL) && - EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { - EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); if (IS_CV != IS_CONST || - (EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) { - zval *object = EX(object); + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; - if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); - if (UNEXPECTED(EX(fbc) == NULL)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); } if (IS_CV == IS_CONST && - EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) && - EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && - EXPECTED(EX(object) == object)) { - CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc)); + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); } } } else { zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); } - if ((EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) != 0) { - EX(object) = NULL; + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; } else { - if (!PZVAL_IS_REF(EX(object))) { - Z_ADDREF_P(EX(object)); /* For $this pointer */ + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; ALLOC_ZVAL(this_ptr); - INIT_PZVAL_COPY(this_ptr, EX(object)); + INIT_PZVAL_COPY(this_ptr, call->object); zval_copy_ctor(this_ptr); - EX(object) = this_ptr; + call->object = this_ptr; } } + call->is_ctor_call = 0; + EX(call) = call; CHECK_EXCEPTION(); @@ -44828,31 +44987,31 @@ void zend_init_opcodes_handlers(void) ZEND_JMP_SET_VAR_SPEC_CV_HANDLER, ZEND_JMP_SET_VAR_SPEC_CV_HANDLER, ZEND_JMP_SET_VAR_SPEC_CV_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, + ZEND_GENERATOR_FLAG_SPEC_HANDLER, ZEND_YIELD_SPEC_CONST_CONST_HANDLER, ZEND_YIELD_SPEC_CONST_TMP_HANDLER, ZEND_YIELD_SPEC_CONST_VAR_HANDLER, diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index e2d5dd12b0..85d3dfb04f 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -1,6 +1,49 @@ {%DEFINES%} -zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC) { +/* + * Stack Frame Layout (the whole stack frame is allocated at once) + * ================== + * + * +========================================+ + * | zend_execute_data |<---+ + * | EX(function_state).arguments |--+ | + * | ... | | | + * | ARGUMENT [1] | | | + * | ... | | | + * | ARGUMENT [ARGS_NUMBER] | | | + * | ARGS_NUMBER |<-+ | + * +========================================+ | + * | + * +========================================+ | + * EG(current_execute_data) -> | zend_execute_data | | + * | EX(prev_execute_data) |----+ + * +----------------------------------------+ + * EX(Ts) ---------> | EX(Ts)[0] | + * | ... | + * | EX(Tx)[op_arrat->T] | + * +----------------------------------------+ + * EX(CVs) --------> | EX(CVs)[0] |--+ + * | ... | | + * | EX(CVs)[op_array->last_var] | | + * +----------------------------------------+ | + * | Optional slot for CV[0] zval* |<-+ + * | ... | + * | ... for CV [op_array->last_var] zval* | + * +----------------------------------------+ + * EX(call_slots) -> | EX(call_slots)[0] | + * | ... | + * | EX(call_slots)[op_array->nested_calls] | + * +----------------------------------------+ + * zend_vm_stack_frame_base -> | ARGUMENTS STACK [0] | + * | ... | + * zend_vm_stack_top --------> | ... | + * | ... | + * | ARGUMENTS STACK [op_array->used_stack] | + * +----------------------------------------+ + */ + +zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC) +{ zend_execute_data *execute_data; /* @@ -15,7 +58,9 @@ zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_arra size_t execute_data_size = ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)); size_t CVs_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval **) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2)); size_t Ts_size = ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T; - size_t total_size = execute_data_size + CVs_size + Ts_size; + size_t call_slots_size = ZEND_MM_ALIGNED_SIZE(sizeof(call_slot)) * op_array->nested_calls; + size_t stack_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * op_array->used_stack; + size_t total_size = execute_data_size + Ts_size + CVs_size + call_slots_size + stack_size; /* * Normally the execute_data is allocated on the VM stack (because it does @@ -27,23 +72,58 @@ zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_arra * by replacing a pointer. */ if (op_array->fn_flags & ZEND_ACC_GENERATOR) { - execute_data = emalloc(total_size); + /* Prepend the regular stack frame with copy on prev_execute_data + * and passed arguments + */ + int args_count = zend_vm_stack_get_args_count_ex(EG(current_execute_data)); + size_t args_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * (args_count + 1); + + total_size += args_size + execute_data_size; + + EG(argument_stack) = zend_vm_stack_new_page((total_size + (sizeof(void*) - 1)) / sizeof(void*)); + EG(argument_stack)->prev = NULL; + execute_data = (zend_execute_data*)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + args_size + execute_data_size); + + /* copy prev_execute_data */ + EX(prev_execute_data) = (zend_execute_data*)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + args_size); + memset(EX(prev_execute_data), 0, sizeof(zend_execute_data)); + EX(prev_execute_data)->function_state.function = (zend_function*)op_array; + EX(prev_execute_data)->function_state.arguments = (void**)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * args_count); + + /* copy arguemnts */ + *EX(prev_execute_data)->function_state.arguments = (void*)(zend_uintptr_t)args_count; + if (args_count > 0) { + zval **arg_src = (zval**)zend_vm_stack_get_arg_ex(EG(current_execute_data), 1); + zval **arg_dst = (zval**)zend_vm_stack_get_arg_ex(EX(prev_execute_data), 1); + int i; + + for (i = 0; i < args_count; i++) { + arg_dst[i] = arg_src[i]; + Z_ADDREF_P(arg_dst[i]); + } + } } else { execute_data = zend_vm_stack_alloc(total_size TSRMLS_CC); + EX(prev_execute_data) = EG(current_execute_data); } - EX(CVs) = (zval ***) ((char *) execute_data + execute_data_size); + EX(Ts) = (temp_variable *) ((char *) execute_data + execute_data_size); + + EX(CVs) = (zval ***) ((char *) EX(Ts) + Ts_size); memset(EX(CVs), 0, sizeof(zval **) * op_array->last_var); - EX(Ts) = (temp_variable *) ((char *) EX(CVs) + CVs_size); + EX(call_slots) = (call_slot*)((char *) EX(CVs) + CVs_size); + + + EX(op_array) = op_array; + + EG(argument_stack)->top = zend_vm_stack_frame_base(execute_data); - EX(fbc) = NULL; - EX(called_scope) = NULL; EX(object) = NULL; + EX(current_this) = NULL; EX(old_error_reporting) = NULL; - EX(op_array) = op_array; EX(symbol_table) = EG(active_symbol_table); - EX(prev_execute_data) = EG(current_execute_data); + EX(call) = NULL; EG(current_execute_data) = execute_data; EX(nested) = nested; @@ -103,12 +183,12 @@ ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *execute_data TSRMLS_DC) zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen"); } -ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC) +ZEND_API void zend_{%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC) { if (EG(exception)) { return; } - {%EXECUTOR_NAME%}_ex(zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC) TSRMLS_CC); + zend_{%EXECUTOR_NAME%}_ex(zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC) TSRMLS_CC); } {%EXTERNAL_EXECUTOR%} diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 52f6cde59e..fcf7960b8e 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -159,6 +159,7 @@ #define ZEND_SEPARATE 156 #define ZEND_QM_ASSIGN_VAR 157 #define ZEND_JMP_SET_VAR 158 +#define ZEND_GENERATOR_FLAG 159 #define ZEND_YIELD 160 #define ZEND_GENERATOR_RETURN 161 #define ZEND_FAST_CALL 162 |