mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
. 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.
This commit is contained in:
parent
9f7e53fde8
commit
70f83f35d0
20 changed files with 1477 additions and 1307 deletions
5
NEWS
5
NEWS
|
@ -3,6 +3,11 @@ PHP NEWS
|
||||||
?? ??? 201?, PHP 5.5.0
|
?? ??? 201?, PHP 5.5.0
|
||||||
|
|
||||||
- General improvements:
|
- General improvements:
|
||||||
|
. 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. (Dmitry)
|
||||||
. Added support for generators. (Nikita Popov)
|
. Added support for generators. (Nikita Popov)
|
||||||
. Add simplified password hashing API
|
. Add simplified password hashing API
|
||||||
(https://wiki.php.net/rfc/password_hash). (Anthony Ferrara)
|
(https://wiki.php.net/rfc/password_hash). (Anthony Ferrara)
|
||||||
|
|
21
UPGRADING
21
UPGRADING
|
@ -28,6 +28,27 @@ PHP 5.5 UPGRADE NOTES
|
||||||
zend_logo_guid() have been removed
|
zend_logo_guid() have been removed
|
||||||
- Removal of Logo GUIDs
|
- Removal of Logo GUIDs
|
||||||
|
|
||||||
|
- extensions can't override zend_execute() any more, they should override
|
||||||
|
zend_execute_ex() instead. The EG(current_execute_data) is already
|
||||||
|
initialized in zend_execute_ex(), so for compatibility extensions
|
||||||
|
may need to use EG(current_execute_data)->prev_execute_data instead.
|
||||||
|
- removed EG(arg_types_stack), EX(fbc), EX(called_scope), EX(current_object)
|
||||||
|
- added op_array->nested_calls. It's calculated at compile time.
|
||||||
|
- added EX(call_slots). It is an array to store information about syntaticaly
|
||||||
|
nested calls (e.g. foo(bar())). It's preallocated together with execute_data.
|
||||||
|
- added EX(call) - pointer to a current calling function. Actually an
|
||||||
|
element of EX(call_slots)
|
||||||
|
- opcodes INIT_METHOD_CALL, ZEND_INIT_STATIC_METHOD_CALL,
|
||||||
|
ZEND_INIT_FCALL_BY_NAME, ZEND_INIT_NS_FCALL_BY_NAME use result.num as
|
||||||
|
an index in EX(call_slots)
|
||||||
|
- opcode ZEND_NEW uses extended_vallue as an index in EX(call_slots)
|
||||||
|
- opcoes ZEND_DO_FCALL and ZEND_DO_FCALL_BY_NAME use op2.num as
|
||||||
|
an index in EX(call_slots)
|
||||||
|
- added op_array->used_stack. It's calculated at compile time and the
|
||||||
|
corresponding stack space is preallocated together with execute_data.
|
||||||
|
ZEND_SEND* and ZEND_DO_FCALL* don't need to check for stack overflow
|
||||||
|
anymore.
|
||||||
|
|
||||||
========================================
|
========================================
|
||||||
2. New Features
|
2. New Features
|
||||||
========================================
|
========================================
|
||||||
|
|
|
@ -683,11 +683,11 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions TS
|
||||||
#if HAVE_DTRACE
|
#if HAVE_DTRACE
|
||||||
/* build with dtrace support */
|
/* build with dtrace support */
|
||||||
zend_compile_file = dtrace_compile_file;
|
zend_compile_file = dtrace_compile_file;
|
||||||
zend_execute = dtrace_execute;
|
zend_execute_ex = dtrace_execute_ex;
|
||||||
zend_execute_internal = dtrace_execute_internal;
|
zend_execute_internal = dtrace_execute_internal;
|
||||||
#else
|
#else
|
||||||
zend_compile_file = compile_file;
|
zend_compile_file = compile_file;
|
||||||
zend_execute = execute;
|
zend_execute_ex = execute_ex;
|
||||||
zend_execute_internal = NULL;
|
zend_execute_internal = NULL;
|
||||||
#endif /* HAVE_SYS_SDT_H */
|
#endif /* HAVE_SYS_SDT_H */
|
||||||
zend_compile_string = compile_string;
|
zend_compile_string = compile_string;
|
||||||
|
|
|
@ -179,6 +179,8 @@ void zend_init_compiler_context(TSRMLS_D) /* {{{ */
|
||||||
CG(context).literals_size = 0;
|
CG(context).literals_size = 0;
|
||||||
CG(context).current_brk_cont = -1;
|
CG(context).current_brk_cont = -1;
|
||||||
CG(context).backpatch_count = 0;
|
CG(context).backpatch_count = 0;
|
||||||
|
CG(context).nested_calls = 0;
|
||||||
|
CG(context).used_stack = 0;
|
||||||
CG(context).labels = NULL;
|
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;
|
function_name->u.constant.value.str.val = lcname;
|
||||||
|
|
||||||
zend_stack_push(&CG(function_call_stack), (void *) &function, sizeof(zend_function *));
|
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);
|
zend_do_extended_fcall_begin(TSRMLS_C);
|
||||||
return 0;
|
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);
|
GET_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant);
|
||||||
}
|
}
|
||||||
last_op->opcode = ZEND_INIT_METHOD_CALL;
|
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;
|
Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME;
|
||||||
} else {
|
} else {
|
||||||
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||||
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
|
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
|
||||||
|
opline->result.num = CG(context).nested_calls;
|
||||||
SET_UNUSED(opline->op1);
|
SET_UNUSED(opline->op1);
|
||||||
if (left_bracket->op_type == IS_CONST) {
|
if (left_bracket->op_type == IS_CONST) {
|
||||||
opline->op2_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 *));
|
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);
|
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
|
/* In run-time PHP will check for function with full name and
|
||||||
internal function with short name */
|
internal function with short name */
|
||||||
opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
|
opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
|
||||||
|
opline->result.num = CG(context).nested_calls;
|
||||||
SET_UNUSED(opline->op1);
|
SET_UNUSED(opline->op1);
|
||||||
opline->op2_type = IS_CONST;
|
opline->op2_type = IS_CONST;
|
||||||
opline->op2.constant = zend_add_ns_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC);
|
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);
|
GET_CACHE_SLOT(opline->op2.constant);
|
||||||
} else {
|
} else {
|
||||||
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
|
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
|
||||||
|
opline->result.num = CG(context).nested_calls;
|
||||||
SET_UNUSED(opline->op1);
|
SET_UNUSED(opline->op1);
|
||||||
if (function_name->op_type == IS_CONST) {
|
if (function_name->op_type == IS_CONST) {
|
||||||
opline->op2_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 *));
|
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);
|
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->extended_value = class_node.EA ;
|
||||||
}
|
}
|
||||||
opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
|
opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
|
||||||
|
opline->result.num = CG(context).nested_calls;
|
||||||
if (class_node.op_type == IS_CONST) {
|
if (class_node.op_type == IS_CONST) {
|
||||||
opline->op1_type = IS_CONST;
|
opline->op1_type = IS_CONST;
|
||||||
opline->op1.constant =
|
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 *));
|
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);
|
zend_do_extended_fcall_begin(TSRMLS_C);
|
||||||
return 1; /* Dynamic */
|
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) {
|
if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) {
|
||||||
opline->opcode = ZEND_DO_FCALL;
|
opline->opcode = ZEND_DO_FCALL;
|
||||||
SET_NODE(opline->op1, function_name);
|
SET_NODE(opline->op1, function_name);
|
||||||
|
SET_UNUSED(opline->op2);
|
||||||
|
opline->op2.num = CG(context).nested_calls;
|
||||||
CALCULATE_LITERAL_HASH(opline->op1.constant);
|
CALCULATE_LITERAL_HASH(opline->op1.constant);
|
||||||
GET_CACHE_SLOT(opline->op1.constant);
|
GET_CACHE_SLOT(opline->op1.constant);
|
||||||
} else {
|
} else {
|
||||||
opline->opcode = ZEND_DO_FCALL_BY_NAME;
|
opline->opcode = ZEND_DO_FCALL_BY_NAME;
|
||||||
SET_UNUSED(opline->op1);
|
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.var = get_temporary_variable(CG(active_op_array));
|
||||||
opline->result_type = IS_VAR;
|
opline->result_type = IS_VAR;
|
||||||
GET_NODE(result, opline->result) ;
|
GET_NODE(result, opline->result);
|
||||||
SET_UNUSED(opline->op2);
|
|
||||||
|
|
||||||
zend_stack_del_top(&CG(function_call_stack));
|
zend_stack_del_top(&CG(function_call_stack));
|
||||||
opline->extended_value = Z_LVAL(argument_list->u.constant);
|
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);
|
SET_NODE(opline->op1, param);
|
||||||
opline->op2.opline_num = offset;
|
opline->op2.opline_num = offset;
|
||||||
SET_UNUSED(opline->op2);
|
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));
|
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 = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||||
opline->opcode = ZEND_NEW;
|
opline->opcode = ZEND_NEW;
|
||||||
|
opline->extended_value = CG(context).nested_calls;
|
||||||
opline->result_type = IS_VAR;
|
opline->result_type = IS_VAR;
|
||||||
opline->result.var = get_temporary_variable(CG(active_op_array));
|
opline->result.var = get_temporary_variable(CG(active_op_array));
|
||||||
SET_NODE(opline->op1, class_type);
|
SET_NODE(opline->op1, class_type);
|
||||||
SET_UNUSED(opline->op2);
|
SET_UNUSED(opline->op2);
|
||||||
|
|
||||||
zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(unsigned char *));
|
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;
|
opline->extended_value = 1;
|
||||||
SET_UNUSED(opline->op2);
|
SET_UNUSED(opline->op2);
|
||||||
GET_NODE(result, opline->result);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,8 @@ typedef struct _zend_compiler_context {
|
||||||
int literals_size;
|
int literals_size;
|
||||||
int current_brk_cont;
|
int current_brk_cont;
|
||||||
int backpatch_count;
|
int backpatch_count;
|
||||||
|
int nested_calls;
|
||||||
|
int used_stack;
|
||||||
HashTable *labels;
|
HashTable *labels;
|
||||||
} zend_compiler_context;
|
} zend_compiler_context;
|
||||||
|
|
||||||
|
@ -279,6 +281,9 @@ struct _zend_op_array {
|
||||||
|
|
||||||
zend_uint T;
|
zend_uint T;
|
||||||
|
|
||||||
|
zend_uint nested_calls;
|
||||||
|
zend_uint used_stack;
|
||||||
|
|
||||||
zend_brk_cont_element *brk_cont_array;
|
zend_brk_cont_element *brk_cont_array;
|
||||||
int last_brk_cont;
|
int last_brk_cont;
|
||||||
|
|
||||||
|
@ -369,11 +374,17 @@ typedef struct _list_llist_element {
|
||||||
|
|
||||||
union _temp_variable;
|
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_execute_data {
|
||||||
struct _zend_op *opline;
|
struct _zend_op *opline;
|
||||||
zend_function_state function_state;
|
zend_function_state function_state;
|
||||||
zend_function *fbc; /* Function Being Called */
|
|
||||||
zend_class_entry *called_scope;
|
|
||||||
zend_op_array *op_array;
|
zend_op_array *op_array;
|
||||||
zval *object;
|
zval *object;
|
||||||
union _temp_variable *Ts;
|
union _temp_variable *Ts;
|
||||||
|
@ -386,8 +397,9 @@ struct _zend_execute_data {
|
||||||
zend_class_entry *current_scope;
|
zend_class_entry *current_scope;
|
||||||
zend_class_entry *current_called_scope;
|
zend_class_entry *current_called_scope;
|
||||||
zval *current_this;
|
zval *current_this;
|
||||||
zval *current_object;
|
|
||||||
struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */
|
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
|
#define EX(element) execute_data.element
|
||||||
|
|
|
@ -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:
|
* Local variables:
|
||||||
* tab-width: 4
|
* tab-width: 4
|
||||||
|
|
|
@ -50,14 +50,14 @@ typedef union _temp_variable {
|
||||||
|
|
||||||
BEGIN_EXTERN_C()
|
BEGIN_EXTERN_C()
|
||||||
struct _zend_fcall_info;
|
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);
|
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 init_executor(TSRMLS_D);
|
||||||
void shutdown_executor(TSRMLS_D);
|
void shutdown_executor(TSRMLS_D);
|
||||||
void shutdown_destructors(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_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_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 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);
|
ZEND_API int zend_is_true(zval *op);
|
||||||
|
@ -221,12 +221,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)
|
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;
|
*(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);
|
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;
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,6 +261,12 @@ static zend_always_inline void *zend_vm_stack_alloc(size_t size TSRMLS_DC)
|
||||||
return ret;
|
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)
|
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)) {
|
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)
|
static zend_always_inline void zend_vm_stack_clear_multiple(TSRMLS_D)
|
||||||
{
|
{
|
||||||
void **p = EG(argument_stack)->top - 1;
|
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);
|
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)
|
||||||
{
|
{
|
||||||
void **p = EG(current_execute_data)->prev_execute_data->function_state.arguments;
|
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 = ex->function_state.arguments;
|
||||||
int arg_count = (int)(zend_uintptr_t) *p;
|
int arg_count = (int)(zend_uintptr_t) *p;
|
||||||
|
|
||||||
if (UNEXPECTED(requested_arg > arg_count)) {
|
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;
|
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;
|
return zend_vm_stack_get_args_count_ex(EG(current_execute_data)->prev_execute_data);
|
||||||
|
|
||||||
zend_ptr_stack_2_pop(stack, &a, &b);
|
|
||||||
|
|
||||||
*object = (zval *) a;
|
|
||||||
*fbc = (zend_function *) b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
return zend_vm_stack_get_arg_ex(EG(current_execute_data)->prev_execute_data, requested_arg);
|
||||||
|
|
||||||
zend_ptr_stack_3_pop(stack, &a, &b, &c);
|
|
||||||
|
|
||||||
*called_scope = (zend_class_entry *) a;
|
|
||||||
*object = (zval *) b;
|
|
||||||
*fbc = (zend_function *) c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute_new_code(TSRMLS_D);
|
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_clean_and_cache_symbol_table(HashTable *symbol_table TSRMLS_DC);
|
||||||
void zend_free_compiled_variables(zval ***CVs, int num);
|
void zend_free_compiled_variables(zval ***CVs, int num);
|
||||||
void **zend_copy_arguments(void **arguments_end);
|
|
||||||
|
|
||||||
#define CACHED_PTR(num) \
|
#define CACHED_PTR(num) \
|
||||||
EG(active_op_array)->run_time_cache[(num)]
|
EG(active_op_array)->run_time_cache[(num)]
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#endif
|
#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);
|
ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data_ptr, zend_fcall_info *fci, int return_value_used TSRMLS_DC);
|
||||||
|
|
||||||
/* true globals */
|
/* true globals */
|
||||||
|
@ -137,7 +137,6 @@ void init_executor(TSRMLS_D) /* {{{ */
|
||||||
INIT_ZVAL(EG(error_zval));
|
INIT_ZVAL(EG(error_zval));
|
||||||
EG(uninitialized_zval_ptr)=&EG(uninitialized_zval);
|
EG(uninitialized_zval_ptr)=&EG(uninitialized_zval);
|
||||||
EG(error_zval_ptr)=&EG(error_zval);
|
EG(error_zval_ptr)=&EG(error_zval);
|
||||||
zend_ptr_stack_init(&EG(arg_types_stack));
|
|
||||||
/* destroys stack frame, therefore makes core dumps worthless */
|
/* destroys stack frame, therefore makes core dumps worthless */
|
||||||
#if 0&&ZEND_DEBUG
|
#if 0&&ZEND_DEBUG
|
||||||
original_sigsegv_handler = signal(SIGSEGV, zend_handle_sigsegv);
|
original_sigsegv_handler = signal(SIGSEGV, zend_handle_sigsegv);
|
||||||
|
@ -293,10 +292,10 @@ void shutdown_executor(TSRMLS_D) /* {{{ */
|
||||||
} zend_end_try();
|
} zend_end_try();
|
||||||
|
|
||||||
zend_try {
|
zend_try {
|
||||||
zend_vm_stack_destroy(TSRMLS_C);
|
|
||||||
|
|
||||||
zend_objects_store_free_object_storage(&EG(objects_store) TSRMLS_CC);
|
zend_objects_store_free_object_storage(&EG(objects_store) TSRMLS_CC);
|
||||||
|
|
||||||
|
zend_vm_stack_destroy(TSRMLS_C);
|
||||||
|
|
||||||
/* Destroy all op arrays */
|
/* Destroy all op arrays */
|
||||||
if (EG(full_tables_cleanup)) {
|
if (EG(full_tables_cleanup)) {
|
||||||
zend_hash_reverse_apply(EG(function_table), (apply_func_t) clean_non_persistent_function_full TSRMLS_CC);
|
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_hash_destroy(&EG(included_files));
|
||||||
|
|
||||||
zend_ptr_stack_destroy(&EG(arg_types_stack));
|
|
||||||
zend_stack_destroy(&EG(user_error_handlers_error_reporting));
|
zend_stack_destroy(&EG(user_error_handlers_error_reporting));
|
||||||
zend_ptr_stack_destroy(&EG(user_error_handlers));
|
zend_ptr_stack_destroy(&EG(user_error_handlers));
|
||||||
zend_ptr_stack_destroy(&EG(user_exception_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)) {
|
!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))) {
|
if (i || UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (EG(argument_stack)->top))) {
|
||||||
/* hack to clean up the stack */
|
/* 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);
|
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]);
|
*param = **(fci->params[i]);
|
||||||
INIT_PZVAL(param);
|
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);
|
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);
|
current_scope = EG(scope);
|
||||||
EG(scope) = calling_scope;
|
EG(scope) = calling_scope;
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
/* The first number is the engine version and the rest is the date.
|
/* 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..
|
* 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 {
|
typedef struct _zend_extension_version_info {
|
||||||
int zend_extension_api_no;
|
int zend_extension_api_no;
|
||||||
|
|
|
@ -32,41 +32,7 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio
|
||||||
if (generator->execute_data) {
|
if (generator->execute_data) {
|
||||||
zend_execute_data *execute_data = generator->execute_data;
|
zend_execute_data *execute_data = generator->execute_data;
|
||||||
zend_op_array *op_array = execute_data->op_array;
|
zend_op_array *op_array = execute_data->op_array;
|
||||||
|
void **stack_frame;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!execute_data->symbol_table) {
|
if (!execute_data->symbol_table) {
|
||||||
zend_free_compiled_variables(execute_data->CVs, op_array->last_var);
|
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);
|
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
|
/* If the generator is closed before it can finish execution (reach
|
||||||
* a return statement) we have to free loop variables manually, as
|
* a return statement) we have to free loop variables manually, as
|
||||||
* we don't know whether the SWITCH_FREE / FREE opcodes have run */
|
* 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 */
|
/* Clear any backed up stack arguments */
|
||||||
if (generator->backed_up_stack) {
|
if (generator->stack != EG(argument_stack)) {
|
||||||
zval **zvals = (zval **) generator->backed_up_stack;
|
stack_frame = zend_vm_stack_frame_base(execute_data);
|
||||||
size_t zval_num = generator->backed_up_stack_size / sizeof(zval *);
|
while (generator->stack->top != stack_frame) {
|
||||||
int i;
|
zval_ptr_dtor((zval**)stack_frame);
|
||||||
|
stack_frame++;
|
||||||
for (i = 0; i < zval_num; i++) {
|
|
||||||
zval_ptr_dtor(&zvals[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
efree(generator->backed_up_stack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (generator->backed_up_arg_types_stack) {
|
while (execute_data->call >= execute_data->call_slots) {
|
||||||
/* The arg types stack contains three elements per call: fbc, object
|
if (execute_data->call->object) {
|
||||||
* and called_scope. Here we traverse the stack from top to bottom
|
zval_ptr_dtor(&execute_data->call->object);
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
execute_data->call--;
|
||||||
efree(generator->backed_up_arg_types_stack);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* We have added an additional stack frame in prev_execute_data, so we
|
/* 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
|
* 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) {
|
for (i = 0; i < arguments_count; ++i) {
|
||||||
zval_ptr_dtor(arguments_start + i);
|
zval_ptr_dtor(arguments_start + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
efree(arguments_start);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
efree(prev_execute_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free a clone of closure */
|
/* Free a clone of closure */
|
||||||
|
@ -175,7 +121,11 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio
|
||||||
efree(op_array);
|
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;
|
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_execute_data *execute_data = orig->execute_data;
|
||||||
zend_op_array *op_array = execute_data->op_array;
|
zend_op_array *op_array = execute_data->op_array;
|
||||||
HashTable *symbol_table = execute_data->symbol_table;
|
HashTable *symbol_table = execute_data->symbol_table;
|
||||||
|
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;
|
||||||
|
|
||||||
/* Alloc separate execution context, as well as separate sections for
|
/* Create new execution context. We have to back up and restore
|
||||||
* compiled variables and temporary variables */
|
* EG(current_execute_data), EG(opline_ptr), EG(active_symbol_table)
|
||||||
size_t execute_data_size = ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data));
|
* and EG(This) here because the function modifies or uses them */
|
||||||
size_t CVs_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval **) * op_array->last_var * (symbol_table ? 1 : 2));
|
current_execute_data = EG(current_execute_data);
|
||||||
size_t Ts_size = ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T;
|
EG(current_execute_data) = execute_data->prev_execute_data;
|
||||||
size_t total_size = execute_data_size + CVs_size + Ts_size;
|
opline_ptr = EG(opline_ptr);
|
||||||
|
current_symbol_table = EG(active_symbol_table);
|
||||||
clone->execute_data = emalloc(total_size);
|
EG(active_symbol_table) = execute_data->symbol_table;
|
||||||
|
current_this = EG(This);
|
||||||
/* Copy the zend_execute_data struct */
|
EG(This) = NULL;
|
||||||
memcpy(clone->execute_data, execute_data, execute_data_size);
|
current_stack = EG(argument_stack);
|
||||||
|
clone->execute_data = zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC);
|
||||||
/* Set the pointers to the memory segments for the compiled and
|
clone->stack = EG(argument_stack);
|
||||||
* temporary variables (which are located after the execute_data) */
|
EG(argument_stack) = current_stack;
|
||||||
clone->execute_data->CVs = (zval ***) ((char *) clone->execute_data + execute_data_size);
|
EG(This) = current_this;
|
||||||
clone->execute_data->Ts = (temp_variable *) ((char *) clone->execute_data->CVs + CVs_size);
|
EG(active_symbol_table) = current_symbol_table;
|
||||||
|
EG(current_execute_data) = current_execute_data;
|
||||||
/* Zero out the compiled variables section */
|
EG(opline_ptr) = opline_ptr;
|
||||||
memset(clone->execute_data->CVs, 0, sizeof(zval **) * op_array->last_var);
|
|
||||||
|
|
||||||
|
/* 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) {
|
if (!symbol_table) {
|
||||||
int i;
|
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++) {
|
for (i = 0; i < op_array->last_var; i++) {
|
||||||
if (execute_data->CVs[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 **) 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]);
|
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 */
|
/* 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 */
|
/* 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
|
/* Update the send_target to use the temporary variable with the same
|
||||||
* offset as the original generator, but in our temporary variable
|
* offset as the original generator, but in our temporary variable
|
||||||
* memory segment. */
|
* memory segment. */
|
||||||
|
@ -334,24 +291,14 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator **
|
||||||
}
|
}
|
||||||
|
|
||||||
if (execute_data->current_this) {
|
if (execute_data->current_this) {
|
||||||
|
clone->execute_data->current_this = execute_data->current_this;
|
||||||
Z_ADDREF_P(execute_data->current_this);
|
Z_ADDREF_P(execute_data->current_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (execute_data->object) {
|
if (execute_data->object) {
|
||||||
|
clone->execute_data->object = execute_data->object;
|
||||||
Z_ADDREF_P(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 */
|
/* 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_generator *generator;
|
||||||
zend_execute_data *current_execute_data;
|
zend_execute_data *current_execute_data;
|
||||||
zend_op **opline_ptr;
|
zend_op **opline_ptr;
|
||||||
|
HashTable *current_symbol_table;
|
||||||
zend_execute_data *execute_data;
|
zend_execute_data *execute_data;
|
||||||
|
zend_vm_stack current_stack = EG(argument_stack);
|
||||||
|
|
||||||
/* Create a clone of closure, because it may be destroyed */
|
/* Create a clone of closure, because it may be destroyed */
|
||||||
if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
|
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
|
/* Create new execution context. We have to back up and restore
|
||||||
* EG(current_execute_data) and EG(opline_ptr) here because the function
|
* EG(current_execute_data), EG(opline_ptr) and EG(active_symbol_table)
|
||||||
* modifies it. */
|
* here because the function modifies or uses them */
|
||||||
current_execute_data = EG(current_execute_data);
|
current_execute_data = EG(current_execute_data);
|
||||||
opline_ptr = EG(opline_ptr);
|
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);
|
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(current_execute_data) = current_execute_data;
|
||||||
EG(opline_ptr) = opline_ptr;
|
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. */
|
/* Save execution context in generator object. */
|
||||||
generator = (zend_generator *) zend_object_store_get_object(return_value TSRMLS_CC);
|
generator = (zend_generator *) zend_object_store_get_object(return_value TSRMLS_CC);
|
||||||
generator->execute_data = execute_data;
|
generator->execute_data = execute_data;
|
||||||
|
generator->stack = EG(argument_stack);
|
||||||
/* We have to add another stack frame so the generator function shows
|
EG(argument_stack) = current_stack;
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
@ -487,28 +429,7 @@ void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */
|
||||||
zval *original_This = EG(This);
|
zval *original_This = EG(This);
|
||||||
zend_class_entry *original_scope = EG(scope);
|
zend_class_entry *original_scope = EG(scope);
|
||||||
zend_class_entry *original_called_scope = EG(called_scope);
|
zend_class_entry *original_called_scope = EG(called_scope);
|
||||||
int original_arg_types_stack_count = EG(arg_types_stack).top;
|
zend_vm_stack original_stack = EG(argument_stack);
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We (mis)use the return_value_ptr_ptr to provide the generator object
|
/* 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 */
|
* 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(This) = generator->execute_data->current_this;
|
||||||
EG(scope) = generator->execute_data->current_scope;
|
EG(scope) = generator->execute_data->current_scope;
|
||||||
EG(called_scope) = generator->execute_data->current_called_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
|
/* We want the backtrace to look as if the generator function was
|
||||||
* called from whatever method we are current running (e.g. next()).
|
* 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 */
|
/* Resume execution */
|
||||||
generator->flags |= ZEND_GENERATOR_CURRENTLY_RUNNING;
|
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;
|
generator->flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING;
|
||||||
|
|
||||||
/* Restore executor globals */
|
/* Restore executor globals */
|
||||||
|
@ -545,27 +467,7 @@ void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */
|
||||||
EG(This) = original_This;
|
EG(This) = original_This;
|
||||||
EG(scope) = original_scope;
|
EG(scope) = original_scope;
|
||||||
EG(called_scope) = original_called_scope;
|
EG(called_scope) = original_called_scope;
|
||||||
|
EG(argument_stack) = original_stack;
|
||||||
/* 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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If an exception was thrown in the generator we have to internally
|
/* If an exception was thrown in the generator we have to internally
|
||||||
* rethrow it in the parent scope. */
|
* rethrow it in the parent scope. */
|
||||||
|
@ -741,21 +643,11 @@ ZEND_METHOD(Generator, __wakeup)
|
||||||
|
|
||||||
/* get_iterator implementation */
|
/* 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) /* {{{ */
|
static void zend_generator_iterator_dtor(zend_object_iterator *iterator TSRMLS_DC) /* {{{ */
|
||||||
{
|
{
|
||||||
zval *object = ((zend_generator_iterator *) iterator)->object;
|
zval *object = ((zend_generator_iterator *) iterator)->object;
|
||||||
|
|
||||||
zval_ptr_dtor(&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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator = emalloc(sizeof(zend_generator_iterator));
|
iterator = &generator->iterator;
|
||||||
iterator->intern.funcs = &zend_generator_iterator_functions;
|
iterator->intern.funcs = &zend_generator_iterator_functions;
|
||||||
iterator->intern.data = (void *) generator;
|
iterator->intern.data = (void *) generator;
|
||||||
|
|
||||||
|
|
|
@ -25,25 +25,24 @@ BEGIN_EXTERN_C()
|
||||||
extern ZEND_API zend_class_entry *zend_ce_generator;
|
extern ZEND_API zend_class_entry *zend_ce_generator;
|
||||||
END_EXTERN_C()
|
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 {
|
typedef struct _zend_generator {
|
||||||
zend_object std;
|
zend_object std;
|
||||||
|
|
||||||
|
zend_generator_iterator iterator;
|
||||||
|
|
||||||
/* The suspended execution context. */
|
/* The suspended execution context. */
|
||||||
zend_execute_data *execute_data;
|
zend_execute_data *execute_data;
|
||||||
|
|
||||||
/* If the execution is suspended during a function call there may be
|
/* The separate stack used by generator */
|
||||||
* arguments pushed to the stack, so it has to be backed up. */
|
zend_vm_stack stack;
|
||||||
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;
|
|
||||||
|
|
||||||
/* Current value */
|
/* Current value */
|
||||||
zval *value;
|
zval *value;
|
||||||
|
|
|
@ -167,8 +167,6 @@ struct _zend_executor_globals {
|
||||||
zval error_zval;
|
zval error_zval;
|
||||||
zval *error_zval_ptr;
|
zval *error_zval_ptr;
|
||||||
|
|
||||||
zend_ptr_stack arg_types_stack;
|
|
||||||
|
|
||||||
/* symbol table cache */
|
/* symbol table cache */
|
||||||
HashTable *symtable_cache[SYMTABLE_CACHE_SIZE];
|
HashTable *symtable_cache[SYMTABLE_CACHE_SIZE];
|
||||||
HashTable **symtable_cache_limit;
|
HashTable **symtable_cache_limit;
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
#define ZEND_MODULE_INFO_FUNC_ARGS zend_module_entry *zend_module TSRMLS_DC
|
#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_INFO_FUNC_ARGS_PASSTHRU zend_module TSRMLS_CC
|
||||||
|
|
||||||
#define ZEND_MODULE_API_NO 20121113
|
#define ZEND_MODULE_API_NO 20121128
|
||||||
#ifdef ZTS
|
#ifdef ZTS
|
||||||
#define USING_ZTS 1
|
#define USING_ZTS 1
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -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->T = 0;
|
||||||
|
|
||||||
|
op_array->nested_calls = 0;
|
||||||
|
op_array->used_stack = 0;
|
||||||
|
|
||||||
op_array->function_name = NULL;
|
op_array->function_name = NULL;
|
||||||
op_array->filename = zend_get_compiled_filename(TSRMLS_C);
|
op_array->filename = zend_get_compiled_filename(TSRMLS_C);
|
||||||
op_array->doc_comment = NULL;
|
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 */
|
/* generate a FAST_CALL to finaly block */
|
||||||
start_op = get_next_op_number(op_array);
|
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 = get_next_op(op_array TSRMLS_CC);
|
||||||
opline->opcode = ZEND_FAST_CALL;
|
opline->opcode = ZEND_FAST_CALL;
|
||||||
SET_UNUSED(opline->op1);
|
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;
|
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 */
|
/* Finish the sequence with original opcode */
|
||||||
opline = get_next_op(op_array TSRMLS_CC);
|
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) {
|
switch (opline->opcode) {
|
||||||
case ZEND_RETURN:
|
case ZEND_RETURN:
|
||||||
case ZEND_RETURN_BY_REF:
|
case ZEND_RETURN_BY_REF:
|
||||||
|
case ZEND_YIELD:
|
||||||
zend_resolve_finally_call(op_array, i, (zend_uint)-1 TSRMLS_CC);
|
zend_resolve_finally_call(op_array, i, (zend_uint)-1 TSRMLS_CC);
|
||||||
break;
|
break;
|
||||||
case ZEND_BRK:
|
case ZEND_BRK:
|
||||||
|
|
|
@ -110,23 +110,6 @@ ZEND_API int zend_ptr_stack_num_elements(zend_ptr_stack *stack)
|
||||||
{
|
{
|
||||||
return stack->top;
|
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:
|
* Local variables:
|
||||||
* tab-width: 4
|
* tab-width: 4
|
||||||
|
|
|
@ -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_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 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 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()
|
END_EXTERN_C()
|
||||||
|
|
||||||
#define ZEND_PTR_STACK_RESIZE_IF_NEEDED(stack, count) \
|
#define ZEND_PTR_STACK_RESIZE_IF_NEEDED(stack, count) \
|
||||||
|
|
|
@ -1161,7 +1161,7 @@ ZEND_VM_HANDLER(92, ZEND_FETCH_FUNC_ARG, CONST|TMP|VAR|CV, UNUSED|CONST|VAR)
|
||||||
USE_OPLINE
|
USE_OPLINE
|
||||||
|
|
||||||
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type,
|
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)
|
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();
|
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);
|
container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
|
||||||
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
|
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) {
|
||||||
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
|
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
|
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 */
|
/* Behave like FETCH_OBJ_W */
|
||||||
zend_free_op free_op1, free_op2;
|
zend_free_op free_op1, free_op2;
|
||||||
zval *property;
|
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).function = (zend_function *) EX(op_array);
|
||||||
EX(function_state).arguments = NULL;
|
EX(function_state).arguments = NULL;
|
||||||
EX(object) = EX(current_object);
|
|
||||||
|
|
||||||
EG(opline_ptr) = &EX(opline);
|
EG(opline_ptr) = &EX(opline);
|
||||||
EG(active_op_array) = EX(op_array);
|
EG(active_op_array) = EX(op_array);
|
||||||
|
@ -1925,8 +1924,8 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
|
||||||
EX(function_state).arguments = NULL;
|
EX(function_state).arguments = NULL;
|
||||||
|
|
||||||
if (EG(This)) {
|
if (EG(This)) {
|
||||||
if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) {
|
if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) {
|
||||||
if (IS_CTOR_USED(EX(called_scope))) {
|
if (EX(call)->is_ctor_result_used) {
|
||||||
Z_DELREF_P(EG(This));
|
Z_DELREF_P(EG(This));
|
||||||
}
|
}
|
||||||
if (Z_REFCOUNT_P(EG(This)) == 1) {
|
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(scope) = EX(current_scope);
|
||||||
EG(called_scope) = EX(current_called_scope);
|
EG(called_scope) = EX(current_called_scope);
|
||||||
|
|
||||||
EX(object) = EX(current_object);
|
EX(call)--;
|
||||||
EX(called_scope) = DECODE_CTOR(EX(called_scope));
|
|
||||||
|
|
||||||
zend_vm_stack_clear_multiple(TSRMLS_C);
|
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;
|
zend_function *fbc = EX(function_state).function;
|
||||||
|
|
||||||
SAVE_OPLINE();
|
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|ZEND_ACC_DEPRECATED)) != 0)) {
|
||||||
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 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);
|
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);
|
EX(current_called_scope) = EG(called_scope);
|
||||||
EG(This) = EX(object);
|
EG(This) = EX(object);
|
||||||
EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ? fbc->common.scope : NULL;
|
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_top(TSRMLS_C);
|
||||||
EX(function_state).arguments = zend_vm_stack_push_args(opline->extended_value TSRMLS_CC);
|
zend_vm_stack_push((void*)(zend_uintptr_t)opline->extended_value TSRMLS_CC);
|
||||||
LOAD_OPLINE();
|
LOAD_OPLINE();
|
||||||
|
|
||||||
if (fbc->type == ZEND_INTERNAL_FUNCTION) {
|
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)) {
|
if (RETURN_VALUE_USED(opline)) {
|
||||||
EX_T(opline->result.var).var.ptr = zend_generator_create_zval(EG(active_op_array) TSRMLS_CC);
|
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)) {
|
if (EXPECTED(EG(exception) == NULL)) {
|
||||||
ZEND_VM_ENTER();
|
ZEND_VM_ENTER();
|
||||||
}
|
}
|
||||||
|
@ -2100,8 +2099,8 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
|
||||||
|
|
||||||
if (should_change_scope) {
|
if (should_change_scope) {
|
||||||
if (EG(This)) {
|
if (EG(This)) {
|
||||||
if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) {
|
if (UNEXPECTED(EG(exception) != NULL) && EX(call)->is_ctor_call) {
|
||||||
if (IS_CTOR_USED(EX(called_scope))) {
|
if (EX(call)->is_ctor_result_used) {
|
||||||
Z_DELREF_P(EG(This));
|
Z_DELREF_P(EG(This));
|
||||||
}
|
}
|
||||||
if (Z_REFCOUNT_P(EG(This)) == 1) {
|
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);
|
EG(called_scope) = EX(current_called_scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
EX(object) = EX(current_object);
|
EX(call)--;
|
||||||
EX(called_scope) = DECODE_CTOR(EX(called_scope));
|
|
||||||
|
|
||||||
zend_vm_stack_clear_multiple(TSRMLS_C);
|
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;
|
char *function_name_strval;
|
||||||
int function_name_strlen;
|
int function_name_strlen;
|
||||||
zend_free_op free_op1, free_op2;
|
zend_free_op free_op1, free_op2;
|
||||||
|
call_slot *call = EX(call_slots) + opline->result.num;
|
||||||
|
|
||||||
SAVE_OPLINE();
|
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);
|
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_strval = Z_STRVAL_P(function_name);
|
||||||
function_name_strlen = Z_STRLEN_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) &&
|
if (EXPECTED(call->object != NULL) &&
|
||||||
EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) {
|
EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) {
|
||||||
EX(called_scope) = Z_OBJCE_P(EX(object));
|
call->called_scope = Z_OBJCE_P(call->object);
|
||||||
|
|
||||||
if (OP2_TYPE != IS_CONST ||
|
if (OP2_TYPE != IS_CONST ||
|
||||||
(EX(fbc) = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope))) == NULL) {
|
(call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) {
|
||||||
zval *object = EX(object);
|
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");
|
zend_error_noreturn(E_ERROR, "Object does not support method calls");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* First, locate the function. */
|
/* 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);
|
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(EX(fbc) == NULL)) {
|
if (UNEXPECTED(call->fbc == NULL)) {
|
||||||
zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval);
|
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 &&
|
if (OP2_TYPE == IS_CONST &&
|
||||||
EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) &&
|
EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) &&
|
||||||
EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
|
EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) &&
|
||||||
EXPECTED(EX(object) == object)) {
|
EXPECTED(call->object == object)) {
|
||||||
CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, EX(called_scope), EX(fbc));
|
CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
|
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) {
|
if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
|
||||||
EX(object) = NULL;
|
call->object = NULL;
|
||||||
} else {
|
} else {
|
||||||
if (!PZVAL_IS_REF(EX(object))) {
|
if (!PZVAL_IS_REF(call->object)) {
|
||||||
Z_ADDREF_P(EX(object)); /* For $this pointer */
|
Z_ADDREF_P(call->object); /* For $this pointer */
|
||||||
} else {
|
} else {
|
||||||
zval *this_ptr;
|
zval *this_ptr;
|
||||||
ALLOC_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);
|
zval_copy_ctor(this_ptr);
|
||||||
EX(object) = this_ptr;
|
call->object = this_ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
call->is_ctor_call = 0;
|
||||||
|
EX(call) = call;
|
||||||
|
|
||||||
FREE_OP2();
|
FREE_OP2();
|
||||||
FREE_OP1_IF_VAR();
|
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
|
USE_OPLINE
|
||||||
zval *function_name;
|
zval *function_name;
|
||||||
zend_class_entry *ce;
|
zend_class_entry *ce;
|
||||||
|
call_slot *call = EX(call_slots) + opline->result.num;
|
||||||
|
|
||||||
SAVE_OPLINE();
|
SAVE_OPLINE();
|
||||||
zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
|
|
||||||
|
|
||||||
if (OP1_TYPE == IS_CONST) {
|
if (OP1_TYPE == IS_CONST) {
|
||||||
/* no function found. try a static method in class */
|
/* 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);
|
CACHE_PTR(opline->op1.literal->cache_slot, ce);
|
||||||
}
|
}
|
||||||
EX(called_scope) = ce;
|
call->called_scope = ce;
|
||||||
} else {
|
} else {
|
||||||
ce = EX_T(opline->op1.var).class_entry;
|
ce = EX_T(opline->op1.var).class_entry;
|
||||||
|
|
||||||
if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) {
|
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 {
|
} else {
|
||||||
EX(called_scope) = ce;
|
call->called_scope = ce;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OP1_TYPE == IS_CONST &&
|
if (OP1_TYPE == IS_CONST &&
|
||||||
OP2_TYPE == IS_CONST &&
|
OP2_TYPE == IS_CONST &&
|
||||||
CACHED_PTR(opline->op2.literal->cache_slot)) {
|
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 &&
|
} else if (OP1_TYPE != IS_CONST &&
|
||||||
OP2_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 */
|
/* do nothing */
|
||||||
} else if (OP2_TYPE != IS_UNUSED) {
|
} else if (OP2_TYPE != IS_UNUSED) {
|
||||||
char *function_name_strval = NULL;
|
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 (function_name_strval) {
|
||||||
if (ce->get_static_method) {
|
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 {
|
} 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);
|
zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);
|
||||||
}
|
}
|
||||||
if (OP2_TYPE == IS_CONST &&
|
if (OP2_TYPE == IS_CONST &&
|
||||||
EXPECTED(EX(fbc)->type <= ZEND_USER_FUNCTION) &&
|
EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) &&
|
||||||
EXPECTED((EX(fbc)->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
|
EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0)) {
|
||||||
if (OP1_TYPE == IS_CONST) {
|
if (OP1_TYPE == IS_CONST) {
|
||||||
CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
|
CACHE_PTR(opline->op2.literal->cache_slot, call->fbc);
|
||||||
} else {
|
} 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)) {
|
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);
|
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) {
|
if (call->fbc->common.fn_flags & ZEND_ACC_STATIC) {
|
||||||
EX(object) = NULL;
|
call->object = NULL;
|
||||||
} else {
|
} else {
|
||||||
if (EG(This) &&
|
if (EG(This) &&
|
||||||
Z_OBJ_HT_P(EG(This))->get_class_entry &&
|
Z_OBJ_HT_P(EG(This))->get_class_entry &&
|
||||||
!instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) {
|
!instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) {
|
||||||
/* We are calling method of the other (incompatible) class,
|
/* We are calling method of the other (incompatible) class,
|
||||||
but passing $this. This is done for compatibility with php-4. */
|
but passing $this. This is done for compatibility with php-4. */
|
||||||
if (EX(fbc)->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
|
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", EX(fbc)->common.scope->name, EX(fbc)->common.function_name);
|
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 {
|
} else {
|
||||||
/* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */
|
/* 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))) {
|
if ((call->object = EG(This))) {
|
||||||
Z_ADDREF_P(EX(object));
|
Z_ADDREF_P(call->object);
|
||||||
EX(called_scope) = Z_OBJCE_P(EX(object));
|
call->called_scope = Z_OBJCE_P(call->object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
call->is_ctor_call = 0;
|
||||||
|
EX(call) = call;
|
||||||
|
|
||||||
CHECK_EXCEPTION();
|
CHECK_EXCEPTION();
|
||||||
ZEND_VM_NEXT_OPCODE();
|
ZEND_VM_NEXT_OPCODE();
|
||||||
|
@ -2648,19 +2650,21 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
|
||||||
{
|
{
|
||||||
USE_OPLINE
|
USE_OPLINE
|
||||||
zval *function_name;
|
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) {
|
if (OP2_TYPE == IS_CONST) {
|
||||||
function_name = (zval*)(opline->op2.literal+1);
|
function_name = (zval*)(opline->op2.literal+1);
|
||||||
if (CACHED_PTR(opline->op2.literal->cache_slot)) {
|
if (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 (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)) {
|
} 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();
|
SAVE_OPLINE();
|
||||||
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
|
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
|
||||||
} else {
|
} 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();*/
|
/*CHECK_EXCEPTION();*/
|
||||||
ZEND_VM_NEXT_OPCODE();
|
ZEND_VM_NEXT_OPCODE();
|
||||||
} else {
|
} else {
|
||||||
|
@ -2680,28 +2684,32 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
|
||||||
} else {
|
} else {
|
||||||
lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen);
|
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);
|
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval);
|
||||||
}
|
}
|
||||||
efree(lcname);
|
efree(lcname);
|
||||||
FREE_OP2();
|
FREE_OP2();
|
||||||
EX(object) = NULL;
|
call->object = NULL;
|
||||||
|
call->is_ctor_call = 0;
|
||||||
|
EX(call) = call;
|
||||||
CHECK_EXCEPTION();
|
CHECK_EXCEPTION();
|
||||||
ZEND_VM_NEXT_OPCODE();
|
ZEND_VM_NEXT_OPCODE();
|
||||||
} else if (OP2_TYPE != IS_CONST && OP2_TYPE != IS_TMP_VAR &&
|
} else if (OP2_TYPE != IS_CONST && OP2_TYPE != IS_TMP_VAR &&
|
||||||
EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
|
EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) &&
|
||||||
Z_OBJ_HANDLER_P(function_name, get_closure) &&
|
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) {
|
Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) {
|
||||||
if (EX(object)) {
|
if (call->object) {
|
||||||
Z_ADDREF_P(EX(object));
|
Z_ADDREF_P(call->object);
|
||||||
}
|
}
|
||||||
if (OP2_TYPE == IS_VAR && OP2_FREE &&
|
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 */
|
/* Delay closure destruction until its invocation */
|
||||||
EX(fbc)->common.prototype = (zend_function*)function_name;
|
call->fbc->common.prototype = (zend_function*)function_name;
|
||||||
} else {
|
} else {
|
||||||
FREE_OP2();
|
FREE_OP2();
|
||||||
}
|
}
|
||||||
|
call->is_ctor_call = 0;
|
||||||
|
EX(call) = call;
|
||||||
CHECK_EXCEPTION();
|
CHECK_EXCEPTION();
|
||||||
ZEND_VM_NEXT_OPCODE();
|
ZEND_VM_NEXT_OPCODE();
|
||||||
} else if (OP2_TYPE != IS_CONST &&
|
} 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();
|
CHECK_EXCEPTION();
|
||||||
ZEND_VM_NEXT_OPCODE();
|
ZEND_VM_NEXT_OPCODE();
|
||||||
}
|
}
|
||||||
EX(called_scope) = ce;
|
call->called_scope = ce;
|
||||||
EX(object) = NULL;
|
call->object = NULL;
|
||||||
|
|
||||||
if (ce->get_static_method) {
|
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 {
|
} 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 {
|
} else {
|
||||||
EX(object) = *obj;
|
call->object = *obj;
|
||||||
ce = EX(called_scope) = Z_OBJCE_PP(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);
|
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(EX(fbc) == NULL)) {
|
if (UNEXPECTED(call->fbc == NULL)) {
|
||||||
zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), Z_STRVAL_PP(method));
|
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) {
|
if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
|
||||||
EX(object) = NULL;
|
call->object = NULL;
|
||||||
} else {
|
} else {
|
||||||
if (!PZVAL_IS_REF(EX(object))) {
|
if (!PZVAL_IS_REF(call->object)) {
|
||||||
Z_ADDREF_P(EX(object)); /* For $this pointer */
|
Z_ADDREF_P(call->object); /* For $this pointer */
|
||||||
} else {
|
} else {
|
||||||
zval *this_ptr;
|
zval *this_ptr;
|
||||||
ALLOC_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);
|
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));
|
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();
|
FREE_OP2();
|
||||||
CHECK_EXCEPTION();
|
CHECK_EXCEPTION();
|
||||||
ZEND_VM_NEXT_OPCODE();
|
ZEND_VM_NEXT_OPCODE();
|
||||||
|
@ -2781,31 +2791,32 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST)
|
||||||
{
|
{
|
||||||
USE_OPLINE
|
USE_OPLINE
|
||||||
zend_literal *func_name;
|
zend_literal *func_name;
|
||||||
|
call_slot *call = EX(call_slots) + opline->result.num;
|
||||||
zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
|
|
||||||
|
|
||||||
func_name = opline->op2.literal + 1;
|
func_name = opline->op2.literal + 1;
|
||||||
if (CACHED_PTR(opline->op2.literal->cache_slot)) {
|
if (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 (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) {
|
} 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++;
|
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();
|
SAVE_OPLINE();
|
||||||
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
|
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv));
|
||||||
} else {
|
} else {
|
||||||
CACHE_PTR(opline->op2.literal->cache_slot, EX(fbc));
|
CACHE_PTR(opline->op2.literal->cache_slot, call->fbc);
|
||||||
}
|
}
|
||||||
} else {
|
} 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_NEXT_OPCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
ZEND_VM_HANDLER(61, ZEND_DO_FCALL_BY_NAME, ANY, ANY)
|
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);
|
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
|
USE_OPLINE
|
||||||
zend_free_op free_op1;
|
zend_free_op free_op1;
|
||||||
zval *fname = GET_OP1_ZVAL_PTR(BP_VAR_R);
|
zval *fname = GET_OP1_ZVAL_PTR(BP_VAR_R);
|
||||||
|
call_slot *call = EX(call_slots) + opline->op2.num;
|
||||||
zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
|
|
||||||
|
|
||||||
if (CACHED_PTR(opline->op1.literal->cache_slot)) {
|
if (CACHED_PTR(opline->op1.literal->cache_slot)) {
|
||||||
EX(function_state).function = 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 {
|
} else {
|
||||||
CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function);
|
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();
|
FREE_OP1();
|
||||||
|
|
||||||
|
@ -3052,7 +3065,7 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, ANY)
|
||||||
|
|
||||||
SAVE_OPLINE();
|
SAVE_OPLINE();
|
||||||
if (opline->extended_value==ZEND_DO_FCALL_BY_NAME
|
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);
|
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)) {
|
if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) {
|
||||||
ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper);
|
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);
|
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) ?
|
if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ?
|
||||||
!(opline->extended_value & ZEND_ARG_SEND_SILENT) :
|
!(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");
|
zend_error(E_STRICT, "Only variables should be passed by reference");
|
||||||
}
|
}
|
||||||
ALLOC_ZVAL(valptr);
|
ALLOC_ZVAL(valptr);
|
||||||
|
@ -3175,7 +3188,7 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY)
|
||||||
ZEND_VM_NEXT_OPCODE();
|
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);
|
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
|
USE_OPLINE
|
||||||
|
|
||||||
if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME)
|
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);
|
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF);
|
||||||
}
|
}
|
||||||
SAVE_OPLINE();
|
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);
|
ZEND_VM_JMP(EX(op_array)->opcodes + opline->op2.opline_num);
|
||||||
} else {
|
} else {
|
||||||
|
call_slot *call = EX(call_slots) + opline->extended_value;
|
||||||
|
|
||||||
if (RETURN_VALUE_USED(opline)) {
|
if (RETURN_VALUE_USED(opline)) {
|
||||||
PZVAL_LOCK(object_zval);
|
PZVAL_LOCK(object_zval);
|
||||||
AI_SET_PTR(&EX_T(opline->result.var), 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 */
|
/* We are not handling overloaded classes right now */
|
||||||
EX(object) = object_zval;
|
call->fbc = constructor;
|
||||||
EX(fbc) = constructor;
|
call->object = object_zval;
|
||||||
EX(called_scope) = EX_T(opline->op1.var).class_entry;
|
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();
|
CHECK_EXCEPTION();
|
||||||
ZEND_VM_NEXT_OPCODE();
|
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;
|
EG(return_value_ptr_ptr) = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
EX(current_object) = EX(object);
|
|
||||||
|
|
||||||
EX(function_state).function = (zend_function *) new_op_array;
|
EX(function_state).function = (zend_function *) new_op_array;
|
||||||
EX(object) = NULL;
|
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);
|
zend_rebuild_symbol_table(TSRMLS_C);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EXPECTED(zend_execute == execute)) {
|
if (EXPECTED(zend_execute_ex == execute_ex)) {
|
||||||
ZEND_VM_ENTER();
|
ZEND_VM_ENTER();
|
||||||
} else {
|
} else {
|
||||||
zend_execute(new_op_array TSRMLS_CC);
|
zend_execute(new_op_array TSRMLS_CC);
|
||||||
}
|
}
|
||||||
|
|
||||||
EX(function_state).function = (zend_function *) EX(op_array);
|
EX(function_state).function = (zend_function *) EX(op_array);
|
||||||
EX(object) = EX(current_object);
|
|
||||||
|
|
||||||
EG(opline_ptr) = &EX(opline);
|
EG(opline_ptr) = &EX(opline);
|
||||||
EG(active_op_array) = EX(op_array);
|
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
|
/* Figure out where the next stack frame (which maybe contains pushed
|
||||||
* arguments that have to be dtor'ed) starts */
|
* arguments that have to be dtor'ed) starts */
|
||||||
if (EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) {
|
stack_frame = zend_vm_stack_frame_base(EXECUTE_DATA);
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the exception was thrown during a function call there might be
|
/* If the exception was thrown during a function call there might be
|
||||||
* arguments pushed to the stack that have to be dtor'ed. */
|
* 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)) {
|
if (EX(call) >= EX(call_slots)) {
|
||||||
EX(called_scope) = (zend_class_entry*)zend_ptr_stack_pop(&EG(arg_types_stack));
|
call_slot *call = EX(call);
|
||||||
if (EX(object)) {
|
do {
|
||||||
if (IS_CTOR_CALL(EX(called_scope))) {
|
if (call->object) {
|
||||||
if (IS_CTOR_USED(EX(called_scope))) {
|
if (call->is_ctor_call) {
|
||||||
Z_DELREF_P(EX(object));
|
if (call->is_ctor_result_used) {
|
||||||
}
|
Z_DELREF_P(call->object);
|
||||||
if (Z_REFCOUNT_P(EX(object)) == 1) {
|
}
|
||||||
zend_object_store_ctor_failed(EX(object) TSRMLS_CC);
|
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));
|
call--;
|
||||||
}
|
} while (call >= EX(call_slots));
|
||||||
EX(called_scope) = DECODE_CTOR(EX(called_scope));
|
EX(call) = NULL;
|
||||||
zend_arg_types_stack_2_pop(&EG(arg_types_stack), &EX(object), &EX(fbc));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<EX(op_array)->last_brk_cont; i++) {
|
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_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)
|
ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSED)
|
||||||
{
|
{
|
||||||
USE_OPLINE
|
USE_OPLINE
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,49 @@
|
||||||
{%DEFINES%}
|
{%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;
|
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 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 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 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
|
* 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.
|
* by replacing a pointer.
|
||||||
*/
|
*/
|
||||||
if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
|
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 {
|
} else {
|
||||||
execute_data = zend_vm_stack_alloc(total_size TSRMLS_CC);
|
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);
|
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(fbc) = NULL;
|
|
||||||
EX(called_scope) = NULL;
|
|
||||||
EX(object) = NULL;
|
|
||||||
EX(old_error_reporting) = NULL;
|
|
||||||
EX(op_array) = op_array;
|
EX(op_array) = op_array;
|
||||||
|
|
||||||
|
EG(argument_stack)->top = zend_vm_stack_frame_base(execute_data);
|
||||||
|
|
||||||
|
EX(object) = NULL;
|
||||||
|
EX(current_this) = NULL;
|
||||||
|
EX(old_error_reporting) = NULL;
|
||||||
EX(symbol_table) = EG(active_symbol_table);
|
EX(symbol_table) = EG(active_symbol_table);
|
||||||
EX(prev_execute_data) = EG(current_execute_data);
|
EX(call) = NULL;
|
||||||
EG(current_execute_data) = execute_data;
|
EG(current_execute_data) = execute_data;
|
||||||
EX(nested) = nested;
|
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_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)) {
|
if (EG(exception)) {
|
||||||
return;
|
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%}
|
{%EXTERNAL_EXECUTOR%}
|
||||||
|
|
|
@ -159,6 +159,7 @@
|
||||||
#define ZEND_SEPARATE 156
|
#define ZEND_SEPARATE 156
|
||||||
#define ZEND_QM_ASSIGN_VAR 157
|
#define ZEND_QM_ASSIGN_VAR 157
|
||||||
#define ZEND_JMP_SET_VAR 158
|
#define ZEND_JMP_SET_VAR 158
|
||||||
|
#define ZEND_GENERATOR_FLAG 159
|
||||||
#define ZEND_YIELD 160
|
#define ZEND_YIELD 160
|
||||||
#define ZEND_GENERATOR_RETURN 161
|
#define ZEND_GENERATOR_RETURN 161
|
||||||
#define ZEND_FAST_CALL 162
|
#define ZEND_FAST_CALL 162
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue