mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Refactored parameter passing mechanism.
In PHP-5.6 and below each argument passed to user function was copies on VM stack twice. Now we always have ZEND_INIT_FCALL (or simular) opcode that pushes "call frame" on top of VM stack. "Call frame" is actually the same zend_execute_data structure. All the following ZEND_SEND instructions push arguments on top of the stack in a way that they directly comes into corresponding CV variables of the called frame. Extra arguments are copied at the end of stack frame (after all CV and TMP variables) on function enterance. There are two minor incompatibilities: 1) It's not allowed to decalre functions redefining arguments e.g. "function foo($a,$a) {}". 2) func_get_arg() and func_get args() return the current value of argument and not the original value that was sent.
This commit is contained in:
parent
9c96d966bb
commit
b7715c7e8a
26 changed files with 2870 additions and 2926 deletions
|
@ -44,14 +44,13 @@ static zend_class_entry **class_cleanup_handlers;
|
|||
/* this function doesn't check for too many parameters */
|
||||
ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */
|
||||
{
|
||||
zval *p;
|
||||
int arg_count;
|
||||
va_list ptr;
|
||||
zval **param, *param_ptr;
|
||||
TSRMLS_FETCH();
|
||||
|
||||
p = zend_vm_stack_top(TSRMLS_C) - 1;
|
||||
arg_count = Z_LVAL_P(p);
|
||||
param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1);
|
||||
arg_count = EG(current_execute_data)->call->num_args;
|
||||
|
||||
if (param_count>arg_count) {
|
||||
return FAILURE;
|
||||
|
@ -61,7 +60,6 @@ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */
|
|||
|
||||
while (param_count-->0) {
|
||||
param = va_arg(ptr, zval **);
|
||||
param_ptr = (p-arg_count);
|
||||
if (!Z_ISREF_P(param_ptr) && Z_REFCOUNT_P(param_ptr) > 1) {
|
||||
zval new_tmp;
|
||||
|
||||
|
@ -70,7 +68,7 @@ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */
|
|||
ZVAL_COPY_VALUE(param_ptr, &new_tmp);
|
||||
}
|
||||
*param = param_ptr;
|
||||
arg_count--;
|
||||
param_ptr++;
|
||||
}
|
||||
va_end(ptr);
|
||||
|
||||
|
@ -82,14 +80,13 @@ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */
|
|||
/* this function doesn't check for too many parameters */
|
||||
ZEND_API int zend_get_parameters_ex(int param_count, ...) /* {{{ */
|
||||
{
|
||||
zval *p;
|
||||
int arg_count;
|
||||
va_list ptr;
|
||||
zval **param;
|
||||
zval **param, *param_ptr;
|
||||
TSRMLS_FETCH();
|
||||
|
||||
p = zend_vm_stack_top(TSRMLS_C) - 1;
|
||||
arg_count = Z_LVAL_P(p);
|
||||
param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1);
|
||||
arg_count = EG(current_execute_data)->call->num_args;
|
||||
|
||||
if (param_count>arg_count) {
|
||||
return FAILURE;
|
||||
|
@ -98,7 +95,8 @@ ZEND_API int zend_get_parameters_ex(int param_count, ...) /* {{{ */
|
|||
va_start(ptr, param_count);
|
||||
while (param_count-->0) {
|
||||
param = va_arg(ptr, zval **);
|
||||
*param = p-(arg_count--);
|
||||
*param = param_ptr;
|
||||
param_ptr++;
|
||||
}
|
||||
va_end(ptr);
|
||||
|
||||
|
@ -108,22 +106,20 @@ ZEND_API int zend_get_parameters_ex(int param_count, ...) /* {{{ */
|
|||
|
||||
ZEND_API int _zend_get_parameters_array_ex(int param_count, zval *argument_array TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zval *p;
|
||||
zval *param_ptr;
|
||||
int arg_count;
|
||||
|
||||
p = zend_vm_stack_top(TSRMLS_C) - 1;
|
||||
arg_count = Z_LVAL_P(p);
|
||||
param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1);
|
||||
arg_count = EG(current_execute_data)->call->num_args;
|
||||
|
||||
if (param_count>arg_count) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
while (param_count-->0) {
|
||||
zval *value = (p-arg_count);
|
||||
|
||||
ZVAL_COPY_VALUE(argument_array, value);
|
||||
ZVAL_COPY_VALUE(argument_array, param_ptr);
|
||||
argument_array++;
|
||||
arg_count--;
|
||||
param_ptr++;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
@ -132,22 +128,22 @@ ZEND_API int _zend_get_parameters_array_ex(int param_count, zval *argument_array
|
|||
|
||||
ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zval *p;
|
||||
zval *param_ptr;
|
||||
int arg_count;
|
||||
|
||||
p = zend_vm_stack_top(TSRMLS_C) - 1;
|
||||
arg_count = Z_LVAL_P(p);
|
||||
param_ptr = ZEND_CALL_ARG(EG(current_execute_data)->call, 1);
|
||||
arg_count = EG(current_execute_data)->call->num_args;
|
||||
|
||||
if (param_count>arg_count) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
while (param_count-->0) {
|
||||
zval *param = p-(arg_count--);
|
||||
if (Z_REFCOUNTED_P(param)) {
|
||||
Z_ADDREF_P(param);
|
||||
if (Z_REFCOUNTED_P(param_ptr)) {
|
||||
Z_ADDREF_P(param_ptr);
|
||||
}
|
||||
add_next_index_zval(argument_array, param);
|
||||
zend_hash_next_index_insert_new(Z_ARRVAL_P(argument_array), param_ptr);
|
||||
param_ptr++;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
@ -807,7 +803,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va,
|
|||
case '+':
|
||||
if (have_varargs) {
|
||||
if (!quiet) {
|
||||
zend_function *active_function = EG(current_execute_data)->function_state.function;
|
||||
zend_function *active_function = EG(current_execute_data)->call->func;
|
||||
const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
|
||||
zend_error(E_WARNING, "%s%s%s(): only one varargs specifier (* or +) is permitted",
|
||||
class_name,
|
||||
|
@ -827,7 +823,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va,
|
|||
|
||||
default:
|
||||
if (!quiet) {
|
||||
zend_function *active_function = EG(current_execute_data)->function_state.function;
|
||||
zend_function *active_function = EG(current_execute_data)->call->func;
|
||||
const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
|
||||
zend_error(E_WARNING, "%s%s%s(): bad type specifier while parsing parameters",
|
||||
class_name,
|
||||
|
@ -850,7 +846,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va,
|
|||
|
||||
if (num_args < min_num_args || (num_args > max_num_args && max_num_args > 0)) {
|
||||
if (!quiet) {
|
||||
zend_function *active_function = EG(current_execute_data)->function_state.function;
|
||||
zend_function *active_function = EG(current_execute_data)->call->func;
|
||||
const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
|
||||
zend_error(E_WARNING, "%s%s%s() expects %s %d parameter%s, %d given",
|
||||
class_name,
|
||||
|
@ -864,7 +860,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va,
|
|||
return FAILURE;
|
||||
}
|
||||
|
||||
arg_count = Z_LVAL_P(zend_vm_stack_top(TSRMLS_C) - 1);
|
||||
arg_count = EG(current_execute_data)->call->num_args;
|
||||
|
||||
if (num_args > arg_count) {
|
||||
zend_error(E_WARNING, "%s(): could not obtain parameters for parsing",
|
||||
|
@ -888,7 +884,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va,
|
|||
|
||||
if (num_varargs > 0) {
|
||||
*n_varargs = num_varargs;
|
||||
*varargs = (zend_vm_stack_top(TSRMLS_C) - 1 - (arg_count - i));
|
||||
*varargs = ZEND_CALL_ARG(EG(current_execute_data)->call, i + 1);
|
||||
/* adjust how many args we have left and restart loop */
|
||||
num_args += 1 - num_varargs;
|
||||
i += num_varargs;
|
||||
|
@ -899,7 +895,7 @@ static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va,
|
|||
}
|
||||
}
|
||||
|
||||
arg = zend_vm_stack_top(TSRMLS_C) - 1 - (arg_count-i);
|
||||
arg = ZEND_CALL_ARG(EG(current_execute_data)->call, i + 1);
|
||||
|
||||
if (zend_parse_arg(i+1, arg, va, &type_spec, quiet TSRMLS_CC) == FAILURE) {
|
||||
/* clean up varargs array if it was used */
|
||||
|
@ -970,7 +966,7 @@ ZEND_API int zend_parse_method_parameters(int num_args TSRMLS_DC, zval *this_ptr
|
|||
* Z_OBJ(EG(This)) to NULL when calling an internal function with common.scope == NULL.
|
||||
* In that case EG(This) would still be the $this from the calling code and we'd take the
|
||||
* wrong branch here. */
|
||||
zend_bool is_method = EG(current_execute_data)->function_state.function->common.scope != NULL;
|
||||
zend_bool is_method = EG(current_execute_data)->call->func->common.scope != NULL;
|
||||
if (!is_method || !this_ptr || Z_TYPE_P(this_ptr) != IS_OBJECT) {
|
||||
RETURN_IF_ZERO_ARGS(num_args, p, 0);
|
||||
|
||||
|
|
|
@ -394,10 +394,10 @@ ZEND_FUNCTION(gc_disable)
|
|||
Get the number of arguments that were passed to the function */
|
||||
ZEND_FUNCTION(func_num_args)
|
||||
{
|
||||
zend_execute_data *ex = EG(current_execute_data)->prev_execute_data;
|
||||
zend_execute_data *ex = EG(current_execute_data);
|
||||
|
||||
if (ex && ex->function_state.arguments) {
|
||||
RETURN_LONG(Z_LVAL_P(ex->function_state.arguments));
|
||||
if (ex->frame_kind == VM_FRAME_NESTED_FUNCTION || ex->frame_kind == VM_FRAME_TOP_FUNCTION) {
|
||||
RETURN_LONG(ex->num_args);
|
||||
} else {
|
||||
zend_error(E_WARNING, "func_num_args(): Called from the global scope - no function context");
|
||||
RETURN_LONG(-1);
|
||||
|
@ -409,11 +409,10 @@ ZEND_FUNCTION(func_num_args)
|
|||
Get the $arg_num'th argument that was passed to the function */
|
||||
ZEND_FUNCTION(func_get_arg)
|
||||
{
|
||||
zval *p;
|
||||
int arg_count;
|
||||
int arg_count, first_extra_arg;
|
||||
zval *arg;
|
||||
long requested_offset;
|
||||
zend_execute_data *ex = EG(current_execute_data)->prev_execute_data;
|
||||
zend_execute_data *ex;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &requested_offset) == FAILURE) {
|
||||
return;
|
||||
|
@ -424,20 +423,28 @@ ZEND_FUNCTION(func_get_arg)
|
|||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (!ex || !ex->function_state.arguments) {
|
||||
ex = EG(current_execute_data);
|
||||
if (ex->frame_kind != VM_FRAME_NESTED_FUNCTION && ex->frame_kind != VM_FRAME_TOP_FUNCTION) {
|
||||
zend_error(E_WARNING, "func_get_arg(): Called from the global scope - no function context");
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
p = ex->function_state.arguments;
|
||||
arg_count = Z_LVAL_P(p); /* this is the amount of arguments passed to func_get_arg(); */
|
||||
arg_count = ex->num_args;
|
||||
|
||||
if (requested_offset >= arg_count) {
|
||||
zend_error(E_WARNING, "func_get_arg(): Argument %ld not passed to function", requested_offset);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
arg = p-(arg_count-requested_offset);
|
||||
first_extra_arg = ex->func->op_array.num_args;
|
||||
if (ex->func->op_array.fn_flags & ZEND_ACC_VARIADIC) {
|
||||
first_extra_arg--;
|
||||
}
|
||||
if (requested_offset >= first_extra_arg && (ex->num_args > first_extra_arg)) {
|
||||
arg = EX_VAR_NUM_2(ex, ex->func->op_array.last_var + ex->func->op_array.T) + (requested_offset - first_extra_arg);
|
||||
} else {
|
||||
arg = ZEND_CALL_ARG(ex, requested_offset + 1);
|
||||
}
|
||||
RETURN_ZVAL_FAST(arg);
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -447,26 +454,45 @@ ZEND_FUNCTION(func_get_arg)
|
|||
ZEND_FUNCTION(func_get_args)
|
||||
{
|
||||
zval *p;
|
||||
int arg_count;
|
||||
int arg_count, first_extra_arg;
|
||||
int i;
|
||||
zend_execute_data *ex = EG(current_execute_data)->prev_execute_data;
|
||||
zend_execute_data *ex = EG(current_execute_data);
|
||||
|
||||
if (!ex || !ex->function_state.arguments) {
|
||||
if (ex->frame_kind != VM_FRAME_NESTED_FUNCTION && ex->frame_kind != VM_FRAME_TOP_FUNCTION) {
|
||||
zend_error(E_WARNING, "func_get_args(): Called from the global scope - no function context");
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
p = ex->function_state.arguments;
|
||||
arg_count = Z_LVAL_P(p); /* this is the amount of arguments passed to func_get_args(); */
|
||||
arg_count = ex->num_args;
|
||||
|
||||
array_init_size(return_value, arg_count);
|
||||
if (arg_count) {
|
||||
Bucket *q;
|
||||
|
||||
p -= arg_count;
|
||||
first_extra_arg = ex->func->op_array.num_args;
|
||||
if (ex->func->op_array.fn_flags & ZEND_ACC_VARIADIC) {
|
||||
first_extra_arg--;
|
||||
}
|
||||
zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
|
||||
i = 0;
|
||||
q = Z_ARRVAL_P(return_value)->arData;
|
||||
for (i=0; i<arg_count; i++) {
|
||||
p = ZEND_CALL_ARG(ex, 1);
|
||||
if (ex->num_args > first_extra_arg) {
|
||||
while (i < first_extra_arg) {
|
||||
q->h = i;
|
||||
q->key = NULL;
|
||||
if (!Z_ISREF_P(p)) {
|
||||
ZVAL_COPY(&q->val, p);
|
||||
} else {
|
||||
ZVAL_DUP(&q->val, Z_REFVAL_P(p));
|
||||
}
|
||||
p++;
|
||||
q++;
|
||||
i++;
|
||||
}
|
||||
p = EX_VAR_NUM_2(ex, ex->func->op_array.last_var + ex->func->op_array.T);
|
||||
}
|
||||
while (i < arg_count) {
|
||||
q->h = i;
|
||||
q->key = NULL;
|
||||
if (!Z_ISREF_P(p)) {
|
||||
|
@ -476,6 +502,7 @@ ZEND_FUNCTION(func_get_args)
|
|||
}
|
||||
p++;
|
||||
q++;
|
||||
i++;
|
||||
}
|
||||
Z_ARRVAL_P(return_value)->nNumUsed = i;
|
||||
Z_ARRVAL_P(return_value)->nNumOfElements = i;
|
||||
|
@ -1957,22 +1984,37 @@ ZEND_FUNCTION(get_defined_constants)
|
|||
/* }}} */
|
||||
|
||||
|
||||
static void debug_backtrace_get_args(zval *curpos, zval *arg_array TSRMLS_DC)
|
||||
static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array TSRMLS_DC)
|
||||
{
|
||||
zval *p = curpos;
|
||||
zval *arg;
|
||||
int arg_count = Z_LVAL_P(p);
|
||||
int num_args = call->num_args;
|
||||
|
||||
array_init_size(arg_array, arg_count);
|
||||
p -= arg_count;
|
||||
array_init_size(arg_array, num_args);
|
||||
if (num_args) {
|
||||
int i = 0;
|
||||
zval *p = ZEND_CALL_ARG(call, 1);
|
||||
|
||||
while (--arg_count >= 0) {
|
||||
arg = p++;
|
||||
if (arg) {
|
||||
if (Z_REFCOUNTED_P(arg)) Z_ADDREF_P(arg);
|
||||
add_next_index_zval(arg_array, arg);
|
||||
} else {
|
||||
add_next_index_null(arg_array);
|
||||
if (call->func->type == ZEND_USER_FUNCTION) {
|
||||
int first_extra_arg = call->func->op_array.num_args;
|
||||
|
||||
if (call->func->op_array.fn_flags & ZEND_ACC_VARIADIC) {
|
||||
first_extra_arg--;
|
||||
}
|
||||
if (call->num_args > first_extra_arg) {
|
||||
while (i < first_extra_arg) {
|
||||
if (Z_REFCOUNTED_P(p)) Z_ADDREF_P(p);
|
||||
zend_hash_next_index_insert_new(Z_ARRVAL_P(arg_array), p);
|
||||
p++;
|
||||
i++;
|
||||
}
|
||||
p = EX_VAR_NUM_2(call, call->func->op_array.last_var + call->func->op_array.T);
|
||||
}
|
||||
}
|
||||
|
||||
while (i < num_args) {
|
||||
if (Z_REFCOUNTED_P(p)) Z_ADDREF_P(p);
|
||||
zend_hash_next_index_insert_new(Z_ARRVAL_P(arg_array), p);
|
||||
p++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1996,6 +2038,7 @@ ZEND_FUNCTION(debug_print_backtrace)
|
|||
zend_execute_data *ptr, *skip;
|
||||
zend_object *object;
|
||||
int lineno, frameno = 0;
|
||||
zend_function *func;
|
||||
const char *function_name;
|
||||
const char *filename;
|
||||
zend_string *class_name = NULL;
|
||||
|
@ -2025,17 +2068,16 @@ ZEND_FUNCTION(debug_print_backtrace)
|
|||
|
||||
skip = ptr;
|
||||
/* skip internal handler */
|
||||
if (!skip->op_array &&
|
||||
if ((!skip->func || !ZEND_USER_CODE(skip->func->common.type)) &&
|
||||
skip->prev_execute_data &&
|
||||
skip->prev_execute_data->opline &&
|
||||
skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL &&
|
||||
skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL_BY_NAME &&
|
||||
skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) {
|
||||
skip = skip->prev_execute_data;
|
||||
}
|
||||
|
||||
if (skip->op_array) {
|
||||
filename = skip->op_array->filename->val;
|
||||
if (skip->func && ZEND_USER_CODE(skip->func->common.type)) {
|
||||
filename = skip->func->op_array.filename->val;
|
||||
lineno = skip->opline->lineno;
|
||||
} else {
|
||||
filename = NULL;
|
||||
|
@ -2044,41 +2086,47 @@ ZEND_FUNCTION(debug_print_backtrace)
|
|||
|
||||
/* $this may be passed into regular internal functions */
|
||||
if (object &&
|
||||
ptr->function_state.function->type == ZEND_INTERNAL_FUNCTION &&
|
||||
!ptr->function_state.function->common.scope) {
|
||||
ptr->call &&
|
||||
ptr->call->func->type == ZEND_INTERNAL_FUNCTION &&
|
||||
!ptr->call->func->common.scope) {
|
||||
object = NULL;
|
||||
}
|
||||
|
||||
function_name = (ptr->function_state.function->common.scope &&
|
||||
ptr->function_state.function->common.scope->trait_aliases) ?
|
||||
if (ptr->call && ptr->call->func && (ptr->call->flags & ZEND_CALL_DONE)) {
|
||||
func = ptr->call->func;
|
||||
function_name = (func->common.scope &&
|
||||
func->common.scope->trait_aliases) ?
|
||||
zend_resolve_method_name(
|
||||
object ?
|
||||
(object ?
|
||||
zend_get_class_entry(object TSRMLS_CC) :
|
||||
ptr->function_state.function->common.scope,
|
||||
ptr->function_state.function)->val :
|
||||
(ptr->function_state.function->common.function_name ?
|
||||
ptr->function_state.function->common.function_name->val :
|
||||
NULL);
|
||||
func->common.scope), func)->val :
|
||||
(func->common.function_name ?
|
||||
func->common.function_name->val : NULL);
|
||||
} else {
|
||||
func = ptr->func;
|
||||
function_name = func && func->common.function_name ?
|
||||
func->common.function_name->val : NULL;
|
||||
}
|
||||
|
||||
if (function_name) {
|
||||
if (object) {
|
||||
if (ptr->function_state.function->common.scope) {
|
||||
class_name = ptr->function_state.function->common.scope->name;
|
||||
if (func->common.scope) {
|
||||
class_name = func->common.scope->name;
|
||||
} else {
|
||||
class_name = zend_get_object_classname(object TSRMLS_CC);
|
||||
}
|
||||
|
||||
call_type = "->";
|
||||
} else if (ptr->function_state.function->common.scope) {
|
||||
class_name = ptr->function_state.function->common.scope->name;
|
||||
} else if (func->common.scope) {
|
||||
class_name = func->common.scope->name;
|
||||
call_type = "::";
|
||||
} else {
|
||||
class_name = NULL;
|
||||
call_type = NULL;
|
||||
}
|
||||
if ((! ptr->opline) || ((ptr->opline->opcode == ZEND_DO_FCALL_BY_NAME) || (ptr->opline->opcode == ZEND_DO_FCALL))) {
|
||||
if (ptr->function_state.arguments && (options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0) {
|
||||
debug_backtrace_get_args(ptr->function_state.arguments, &arg_array TSRMLS_CC);
|
||||
if (func->type != ZEND_EVAL_CODE) {
|
||||
if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0) {
|
||||
debug_backtrace_get_args(ptr->call, &arg_array TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2137,13 +2185,14 @@ ZEND_FUNCTION(debug_print_backtrace)
|
|||
zend_execute_data *prev = skip->prev_execute_data;
|
||||
|
||||
while (prev) {
|
||||
if (prev->function_state.function &&
|
||||
prev->function_state.function->common.type != ZEND_USER_FUNCTION) {
|
||||
if (prev->call &&
|
||||
prev->call->func &&
|
||||
!ZEND_USER_CODE(prev->call->func->common.type)) {
|
||||
prev = NULL;
|
||||
break;
|
||||
}
|
||||
if (prev->op_array) {
|
||||
zend_printf(") called at [%s:%d]\n", prev->op_array->filename->val, prev->opline->lineno);
|
||||
if (prev->func && ZEND_USER_CODE(prev->func->common.type)) {
|
||||
zend_printf(") called at [%s:%d]\n", prev->func->op_array.filename->val, prev->opline->lineno);
|
||||
break;
|
||||
}
|
||||
prev = prev->prev_execute_data;
|
||||
|
@ -2166,6 +2215,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
|
|||
zend_execute_data *ptr, *skip;
|
||||
zend_object *object = Z_OBJ(EG(This));
|
||||
int lineno, frameno = 0;
|
||||
zend_function *func;
|
||||
const char *function_name;
|
||||
const char *filename;
|
||||
zend_string *class_name;
|
||||
|
@ -2194,17 +2244,16 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
|
|||
|
||||
skip = ptr;
|
||||
/* skip internal handler */
|
||||
if (!skip->op_array &&
|
||||
if ((!skip->func || !ZEND_USER_CODE(skip->func->common.type)) &&
|
||||
skip->prev_execute_data &&
|
||||
skip->prev_execute_data->opline &&
|
||||
skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL &&
|
||||
skip->prev_execute_data->opline->opcode != ZEND_DO_FCALL_BY_NAME &&
|
||||
skip->prev_execute_data->opline->opcode != ZEND_INCLUDE_OR_EVAL) {
|
||||
skip = skip->prev_execute_data;
|
||||
}
|
||||
|
||||
if (skip->op_array) {
|
||||
filename = skip->op_array->filename->val;
|
||||
if (skip->func && ZEND_USER_CODE(skip->func->common.type)) {
|
||||
filename = skip->func->op_array.filename->val;
|
||||
lineno = skip->opline->lineno;
|
||||
add_assoc_string_ex(&stack_frame, "file", sizeof("file")-1, (char*)filename);
|
||||
add_assoc_long_ex(&stack_frame, "line", sizeof("line")-1, lineno);
|
||||
|
@ -2216,15 +2265,16 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
|
|||
zend_execute_data *prev = skip->prev_execute_data;
|
||||
|
||||
while (prev) {
|
||||
if (prev->function_state.function &&
|
||||
prev->function_state.function->common.type != ZEND_USER_FUNCTION &&
|
||||
!(prev->function_state.function->common.type == ZEND_INTERNAL_FUNCTION &&
|
||||
(prev->function_state.function->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER))) {
|
||||
if (prev->call &&
|
||||
prev->call->func &&
|
||||
!ZEND_USER_CODE(prev->call->func->common.type) &&
|
||||
!(prev->call->func->common.type == ZEND_INTERNAL_FUNCTION &&
|
||||
(prev->call->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER))) {
|
||||
break;
|
||||
}
|
||||
if (prev->op_array) {
|
||||
if (prev->func && ZEND_USER_CODE(prev->func->common.type)) {
|
||||
// TODO: we have to duplicate it, becaise it may be stored in opcache SHM ???
|
||||
add_assoc_str_ex(&stack_frame, "file", sizeof("file")-1, STR_DUP(prev->op_array->filename, 0));
|
||||
add_assoc_str_ex(&stack_frame, "file", sizeof("file")-1, STR_DUP(prev->func->op_array.filename, 0));
|
||||
add_assoc_long_ex(&stack_frame, "line", sizeof("line")-1, prev->opline->lineno);
|
||||
break;
|
||||
}
|
||||
|
@ -2235,28 +2285,34 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
|
|||
|
||||
/* $this may be passed into regular internal functions */
|
||||
if (object &&
|
||||
ptr->function_state.function->type == ZEND_INTERNAL_FUNCTION &&
|
||||
!ptr->function_state.function->common.scope) {
|
||||
ptr->call &&
|
||||
ptr->call->func->type == ZEND_INTERNAL_FUNCTION &&
|
||||
!ptr->call->func->common.scope) {
|
||||
object = NULL;
|
||||
}
|
||||
|
||||
function_name = (ptr->function_state.function->common.scope &&
|
||||
ptr->function_state.function->common.scope->trait_aliases) ?
|
||||
if (ptr->call && ptr->call->func && (ptr->call->flags & ZEND_CALL_DONE)) {
|
||||
func = ptr->call->func;
|
||||
function_name = (func->common.scope &&
|
||||
func->common.scope->trait_aliases) ?
|
||||
zend_resolve_method_name(
|
||||
object ?
|
||||
(object ?
|
||||
zend_get_class_entry(object TSRMLS_CC) :
|
||||
ptr->function_state.function->common.scope,
|
||||
ptr->function_state.function)->val :
|
||||
(ptr->function_state.function->common.function_name ?
|
||||
ptr->function_state.function->common.function_name->val :
|
||||
NULL);
|
||||
func->common.scope), func)->val :
|
||||
(func->common.function_name ?
|
||||
func->common.function_name->val : NULL);
|
||||
} else {
|
||||
func = ptr->func;
|
||||
function_name = func && func->common.function_name ?
|
||||
func->common.function_name->val : NULL;
|
||||
}
|
||||
|
||||
if (function_name) {
|
||||
add_assoc_string_ex(&stack_frame, "function", sizeof("function")-1, (char*)function_name);
|
||||
|
||||
if (object) {
|
||||
if (ptr->function_state.function->common.scope) {
|
||||
add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(ptr->function_state.function->common.scope->name));
|
||||
if (func->common.scope) {
|
||||
add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(func->common.scope->name));
|
||||
} else {
|
||||
class_name = zend_get_object_classname(object TSRMLS_CC);
|
||||
add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(class_name));
|
||||
|
@ -2270,16 +2326,16 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
|
|||
}
|
||||
|
||||
add_assoc_string_ex(&stack_frame, "type", sizeof("type")-1, "->");
|
||||
} else if (ptr->function_state.function->common.scope) {
|
||||
add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(ptr->function_state.function->common.scope->name));
|
||||
} else if (func->common.scope) {
|
||||
add_assoc_str_ex(&stack_frame, "class", sizeof("class")-1, STR_COPY(func->common.scope->name));
|
||||
add_assoc_string_ex(&stack_frame, "type", sizeof("type")-1, "::");
|
||||
}
|
||||
|
||||
if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0 &&
|
||||
((! ptr->opline) || ((ptr->opline->opcode == ZEND_DO_FCALL_BY_NAME) || (ptr->opline->opcode == ZEND_DO_FCALL)))) {
|
||||
if (ptr->function_state.arguments) {
|
||||
func->type != ZEND_EVAL_CODE) {
|
||||
if (ptr->call) {
|
||||
zval args;
|
||||
debug_backtrace_get_args(ptr->function_state.arguments, &args TSRMLS_CC);
|
||||
debug_backtrace_get_args(ptr->call, &args TSRMLS_CC);
|
||||
add_assoc_zval_ex(&stack_frame, "args", sizeof("args")-1, &args);
|
||||
}
|
||||
}
|
||||
|
@ -2333,7 +2389,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
|
|||
add_assoc_string_ex(&stack_frame, "function", sizeof("function")-1, (char*)function_name);
|
||||
}
|
||||
|
||||
add_next_index_zval(return_value, &stack_frame);
|
||||
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &stack_frame);
|
||||
|
||||
include_filename = filename;
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ static zend_object_handlers closure_handlers;
|
|||
|
||||
ZEND_METHOD(Closure, __invoke) /* {{{ */
|
||||
{
|
||||
zend_function *func = EG(current_execute_data)->function_state.function;
|
||||
zend_function *func = EG(current_execute_data)->call->func;
|
||||
zval *arguments;
|
||||
|
||||
arguments = emalloc(sizeof(zval) * ZEND_NUM_ARGS());
|
||||
|
@ -213,7 +213,7 @@ static void zend_closure_free_storage(zend_object *object TSRMLS_DC) /* {{{ */
|
|||
if (closure->func.type == ZEND_USER_FUNCTION) {
|
||||
zend_execute_data *ex = EG(current_execute_data);
|
||||
while (ex) {
|
||||
if (ex->op_array == &closure->func.op_array) {
|
||||
if (ex->func == &closure->func) {
|
||||
zend_error(E_ERROR, "Cannot destroy active lambda function");
|
||||
}
|
||||
ex = ex->prev_execute_data;
|
||||
|
|
|
@ -97,9 +97,9 @@ ZEND_API zend_compiler_globals compiler_globals;
|
|||
ZEND_API zend_executor_globals executor_globals;
|
||||
#endif
|
||||
|
||||
static void zend_push_function_call_entry(zend_function *fbc TSRMLS_DC) /* {{{ */
|
||||
static void zend_push_function_call_entry(zend_function *fbc, zend_uint opline_num TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_function_call_entry fcall = { fbc };
|
||||
zend_function_call_entry fcall = { fbc, opline_num };
|
||||
zend_stack_push(&CG(function_call_stack), &fcall);
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -182,8 +182,6 @@ void zend_init_compiler_context(TSRMLS_D) /* {{{ */
|
|||
CG(context).literals_size = 0;
|
||||
CG(context).current_brk_cont = -1;
|
||||
CG(context).backpatch_count = 0;
|
||||
CG(context).nested_calls = 0;
|
||||
CG(context).used_stack = 0;
|
||||
CG(context).in_finally = 0;
|
||||
CG(context).labels = NULL;
|
||||
}
|
||||
|
@ -1463,6 +1461,11 @@ void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */
|
|||
&& opline->result.var == op1->u.op.var) {
|
||||
if (opline->opcode == ZEND_NEW) {
|
||||
opline->result_type |= EXT_TYPE_UNUSED;
|
||||
opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
|
||||
while (opline->opcode != ZEND_DO_FCALL || opline->op1.num != ZEND_CALL_CTOR) {
|
||||
opline--;
|
||||
}
|
||||
opline->op1.num |= ZEND_CALL_CTOR_RESULT_UNUSED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1841,7 +1844,9 @@ void zend_do_receive_param(zend_uchar op, znode *varname, znode *initialization,
|
|||
var.u.op.var = lookup_cv(CG(active_op_array), Z_STR(varname->u.constant) TSRMLS_CC);
|
||||
Z_STR(varname->u.constant) = CG(active_op_array)->vars[EX_VAR_TO_NUM(var.u.op.var)];
|
||||
var.EA = 0;
|
||||
if (Z_STRHASH(varname->u.constant) == THIS_HASHVAL &&
|
||||
if (EX_VAR_TO_NUM(var.u.op.var) != CG(active_op_array)->num_args) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Redefinition of parameter %s", Z_STRVAL(varname->u.constant));
|
||||
} else if (Z_STRHASH(varname->u.constant) == THIS_HASHVAL &&
|
||||
Z_STRLEN(varname->u.constant) == sizeof("this")-1 &&
|
||||
!memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this")-1)) {
|
||||
if (CG(active_op_array)->scope &&
|
||||
|
@ -1949,6 +1954,8 @@ void zend_do_receive_param(zend_uchar op, znode *varname, znode *initialization,
|
|||
|
||||
int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_op *opline;
|
||||
zend_uint op_number;
|
||||
zend_function *function;
|
||||
zend_string *lcname;
|
||||
char *is_compound = memchr(Z_STRVAL(function_name->u.constant), '\\', Z_STRLEN(function_name->u.constant));
|
||||
|
@ -1977,10 +1984,14 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace
|
|||
STR_RELEASE(Z_STR(function_name->u.constant));
|
||||
Z_STR(function_name->u.constant) = lcname;
|
||||
|
||||
zend_push_function_call_entry(function TSRMLS_CC);
|
||||
if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) {
|
||||
CG(active_op_array)->nested_calls = CG(context).nested_calls + 1;
|
||||
}
|
||||
op_number = get_next_op_number(CG(active_op_array));
|
||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
opline->opcode = ZEND_INIT_FCALL;
|
||||
SET_UNUSED(opline->op1);
|
||||
SET_NODE(opline->op2, function_name);
|
||||
GET_CACHE_SLOT(opline->op2.constant);
|
||||
|
||||
zend_push_function_call_entry(function, op_number TSRMLS_CC);
|
||||
zend_do_extended_fcall_begin(TSRMLS_C);
|
||||
return 0;
|
||||
}
|
||||
|
@ -2017,12 +2028,10 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
|
|||
}
|
||||
last_op->opcode = ZEND_INIT_METHOD_CALL;
|
||||
last_op->result_type = IS_UNUSED;
|
||||
last_op->result.num = CG(context).nested_calls;
|
||||
Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME;
|
||||
} else {
|
||||
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
|
||||
opline->result.num = CG(context).nested_calls;
|
||||
SET_UNUSED(opline->op1);
|
||||
if (left_bracket->op_type == IS_CONST) {
|
||||
opline->op2_type = IS_CONST;
|
||||
|
@ -2033,10 +2042,7 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
|
|||
}
|
||||
}
|
||||
|
||||
zend_push_function_call_entry(NULL TSRMLS_CC);
|
||||
if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
|
||||
CG(active_op_array)->nested_calls = CG(context).nested_calls;
|
||||
}
|
||||
zend_push_function_call_entry(NULL, last_op_number TSRMLS_CC);
|
||||
zend_do_extended_fcall_begin(TSRMLS_C);
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -2056,21 +2062,21 @@ void zend_do_clone(znode *result, znode *expr TSRMLS_DC) /* {{{ */
|
|||
|
||||
void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_uint op_number;
|
||||
zend_op *opline;
|
||||
|
||||
op_number = get_next_op_number(CG(active_op_array));
|
||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
if (ns_call) {
|
||||
/* In run-time PHP will check for function with full name and
|
||||
internal function with short name */
|
||||
opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
|
||||
opline->result.num = CG(context).nested_calls;
|
||||
SET_UNUSED(opline->op1);
|
||||
opline->op2_type = IS_CONST;
|
||||
opline->op2.constant = zend_add_ns_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC);
|
||||
GET_CACHE_SLOT(opline->op2.constant);
|
||||
} else {
|
||||
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
|
||||
opline->result.num = CG(context).nested_calls;
|
||||
SET_UNUSED(opline->op1);
|
||||
if (function_name->op_type == IS_CONST) {
|
||||
opline->op2_type = IS_CONST;
|
||||
|
@ -2081,10 +2087,7 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML
|
|||
}
|
||||
}
|
||||
|
||||
zend_push_function_call_entry(NULL TSRMLS_CC);
|
||||
if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
|
||||
CG(active_op_array)->nested_calls = CG(context).nested_calls;
|
||||
}
|
||||
zend_push_function_call_entry(NULL, op_number TSRMLS_CC);
|
||||
zend_do_extended_fcall_begin(TSRMLS_C);
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -2481,6 +2484,7 @@ void zend_do_build_full_name(znode *result, znode *prefix, znode *name, int is_c
|
|||
int zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
znode class_node;
|
||||
zend_uint op_number;
|
||||
zend_op *opline;
|
||||
|
||||
if (method_name->op_type == IS_CONST) {
|
||||
|
@ -2501,14 +2505,14 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na
|
|||
ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
|
||||
zend_resolve_class_name(class_name TSRMLS_CC);
|
||||
class_node = *class_name;
|
||||
op_number = get_next_op_number(CG(active_op_array) TSRMLS_CC);
|
||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
} else {
|
||||
zend_do_fetch_class(&class_node, class_name TSRMLS_CC);
|
||||
op_number = get_next_op_number(CG(active_op_array) TSRMLS_CC);
|
||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
opline->extended_value = class_node.EA ;
|
||||
}
|
||||
opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
|
||||
opline->result.num = CG(context).nested_calls;
|
||||
if (class_node.op_type == IS_CONST) {
|
||||
opline->op1_type = IS_CONST;
|
||||
opline->op1.constant =
|
||||
|
@ -2529,10 +2533,7 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na
|
|||
SET_NODE(opline->op2, method_name);
|
||||
}
|
||||
|
||||
zend_push_function_call_entry(NULL TSRMLS_CC);
|
||||
if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
|
||||
CG(active_op_array)->nested_calls = CG(context).nested_calls;
|
||||
}
|
||||
zend_push_function_call_entry(NULL, op_number TSRMLS_CC);
|
||||
zend_do_extended_fcall_begin(TSRMLS_C);
|
||||
return 1; /* Dynamic */
|
||||
}
|
||||
|
@ -2550,26 +2551,20 @@ void zend_do_end_function_call(znode *function_name, znode *result, int is_metho
|
|||
}
|
||||
opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)];
|
||||
} else {
|
||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
if (fcall->fbc) {
|
||||
opline->opcode = ZEND_DO_FCALL;
|
||||
SET_NODE(opline->op1, function_name);
|
||||
SET_UNUSED(opline->op2);
|
||||
opline->op2.num = CG(context).nested_calls;
|
||||
GET_CACHE_SLOT(opline->op1.constant);
|
||||
} else {
|
||||
opline->opcode = ZEND_DO_FCALL_BY_NAME;
|
||||
SET_UNUSED(opline->op1);
|
||||
SET_UNUSED(opline->op2);
|
||||
opline->op2.num = --CG(context).nested_calls;
|
||||
zend_uint call_flags = 0;
|
||||
|
||||
/* This would normally be a ZEND_DO_FCALL, but was forced to use
|
||||
* ZEND_DO_FCALL_BY_NAME due to a ... argument. In this case we need to
|
||||
* free the function_name */
|
||||
if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) {
|
||||
zval_dtor(&function_name->u.constant);
|
||||
}
|
||||
opline = &CG(active_op_array)->opcodes[fcall->op_number];
|
||||
opline->extended_value = fcall->arg_num;
|
||||
|
||||
if (opline->opcode == ZEND_NEW) {
|
||||
call_flags = ZEND_CALL_CTOR;
|
||||
}
|
||||
|
||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
opline->opcode = ZEND_DO_FCALL;
|
||||
SET_UNUSED(opline->op1);
|
||||
SET_UNUSED(opline->op2);
|
||||
opline->op1.num = call_flags;
|
||||
}
|
||||
|
||||
opline->result.var = get_temporary_variable(CG(active_op_array));
|
||||
|
@ -2577,10 +2572,6 @@ void zend_do_end_function_call(znode *function_name, znode *result, int is_metho
|
|||
GET_NODE(result, opline->result);
|
||||
opline->extended_value = fcall->arg_num;
|
||||
|
||||
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 -= fcall->arg_num;
|
||||
zend_stack_del_top(&CG(function_call_stack));
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -2682,19 +2673,13 @@ void zend_do_pass_param(znode *param, zend_uchar op TSRMLS_DC) /* {{{ */
|
|||
}
|
||||
} else {
|
||||
if (function_ptr) {
|
||||
opline->extended_value = ZEND_DO_FCALL;
|
||||
} else {
|
||||
opline->extended_value = ZEND_DO_FCALL_BY_NAME;
|
||||
opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND;
|
||||
}
|
||||
}
|
||||
opline->opcode = op;
|
||||
SET_NODE(opline->op1, param);
|
||||
opline->op2.opline_num = fcall->arg_num;
|
||||
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;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
@ -2705,25 +2690,6 @@ void zend_do_unpack_params(znode *params TSRMLS_DC) /* {{{ */
|
|||
|
||||
fcall->uses_argument_unpacking = 1;
|
||||
|
||||
if (fcall->fbc) {
|
||||
/* If argument unpacking is used argument numbers and sending modes can no longer be
|
||||
* computed at compile time, thus we need access to EX(call). In order to have it we
|
||||
* retroactively emit a ZEND_INIT_FCALL_BY_NAME opcode. */
|
||||
zval func_name;
|
||||
ZVAL_STR(&func_name, STR_COPY(fcall->fbc->common.function_name));
|
||||
|
||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
|
||||
opline->result.num = CG(context).nested_calls;
|
||||
SET_UNUSED(opline->op1);
|
||||
opline->op2_type = IS_CONST;
|
||||
opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &func_name TSRMLS_CC);
|
||||
GET_CACHE_SLOT(opline->op2.constant);
|
||||
|
||||
++CG(context).nested_calls;
|
||||
fcall->fbc = NULL;
|
||||
}
|
||||
|
||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
opline->opcode = ZEND_SEND_UNPACK;
|
||||
SET_NODE(opline->op1, params);
|
||||
|
@ -5619,16 +5585,12 @@ void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC) /*
|
|||
new_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
|
||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
opline->opcode = ZEND_NEW;
|
||||
opline->extended_value = CG(context).nested_calls;
|
||||
opline->result_type = IS_VAR;
|
||||
opline->result.var = get_temporary_variable(CG(active_op_array));
|
||||
SET_NODE(opline->op1, class_type);
|
||||
SET_UNUSED(opline->op2);
|
||||
|
||||
zend_push_function_call_entry(NULL TSRMLS_CC);
|
||||
if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
|
||||
CG(active_op_array)->nested_calls = CG(context).nested_calls;
|
||||
}
|
||||
zend_push_function_call_entry(NULL, new_token->u.op.opline_num TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
@ -5819,6 +5781,14 @@ void zend_do_shell_exec(znode *result, znode *cmd TSRMLS_DC) /* {{{ */
|
|||
{
|
||||
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
|
||||
opline->opcode = ZEND_INIT_FCALL;
|
||||
opline->extended_value = 1;
|
||||
SET_UNUSED(opline->op1);
|
||||
opline->op2_type = IS_CONST;
|
||||
LITERAL_STR(opline->op2, STR_INIT("shell_exec", sizeof("shell_exec")-1, 0));
|
||||
GET_CACHE_SLOT(opline->op2.constant);
|
||||
|
||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
switch (cmd->op_type) {
|
||||
case IS_CONST:
|
||||
case IS_TMP_VAR:
|
||||
|
@ -5830,28 +5800,18 @@ void zend_do_shell_exec(znode *result, znode *cmd TSRMLS_DC) /* {{{ */
|
|||
}
|
||||
SET_NODE(opline->op1, cmd);
|
||||
opline->op2.opline_num = 1;
|
||||
opline->extended_value = ZEND_DO_FCALL;
|
||||
opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND;
|
||||
SET_UNUSED(opline->op2);
|
||||
|
||||
/* FIXME: exception support not added to this op2 */
|
||||
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
|
||||
opline->opcode = ZEND_DO_FCALL;
|
||||
opline->extended_value = 1;
|
||||
opline->result.var = get_temporary_variable(CG(active_op_array));
|
||||
opline->result_type = IS_VAR;
|
||||
LITERAL_STR(opline->op1, STR_INIT("shell_exec", sizeof("shell_exec")-1, 0));
|
||||
opline->op1_type = IS_CONST;
|
||||
GET_CACHE_SLOT(opline->op1.constant);
|
||||
opline->extended_value = 1;
|
||||
SET_UNUSED(opline->op1);
|
||||
SET_UNUSED(opline->op2);
|
||||
opline->op2.num = CG(context).nested_calls;
|
||||
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,8 +59,6 @@ typedef struct _zend_compiler_context {
|
|||
int literals_size;
|
||||
int current_brk_cont;
|
||||
int backpatch_count;
|
||||
int nested_calls;
|
||||
int used_stack;
|
||||
int in_finally;
|
||||
HashTable *labels;
|
||||
} zend_compiler_context;
|
||||
|
@ -266,9 +264,6 @@ struct _zend_op_array {
|
|||
|
||||
zend_uint T;
|
||||
|
||||
zend_uint nested_calls;
|
||||
zend_uint used_stack;
|
||||
|
||||
zend_brk_cont_element *brk_cont_array;
|
||||
int last_brk_cont;
|
||||
|
||||
|
@ -336,14 +331,9 @@ union _zend_function {
|
|||
zend_internal_function internal_function;
|
||||
};
|
||||
|
||||
|
||||
typedef struct _zend_function_state {
|
||||
zend_function *function;
|
||||
zval *arguments;
|
||||
} zend_function_state;
|
||||
|
||||
typedef struct _zend_function_call_entry {
|
||||
zend_function *fbc;
|
||||
zend_uint op_number;
|
||||
zend_uint arg_num;
|
||||
zend_bool uses_argument_unpacking;
|
||||
} zend_function_call_entry;
|
||||
|
@ -361,15 +351,6 @@ typedef struct _list_llist_element {
|
|||
znode value;
|
||||
} list_llist_element;
|
||||
|
||||
typedef struct _call_slot {
|
||||
zend_function *fbc;
|
||||
zend_class_entry *called_scope;
|
||||
zend_object *object;
|
||||
zend_uint num_additional_args;
|
||||
zend_bool is_ctor_call;
|
||||
zend_bool is_ctor_result_used;
|
||||
} call_slot;
|
||||
|
||||
typedef enum _vm_frame_kind {
|
||||
VM_FRAME_NESTED_FUNCTION, /* stackless VM call to function */
|
||||
VM_FRAME_NESTED_CODE, /* stackless VM call to include/require/eval */
|
||||
|
@ -379,28 +360,38 @@ typedef enum _vm_frame_kind {
|
|||
|
||||
struct _zend_execute_data {
|
||||
struct _zend_op *opline; /* executed opline */
|
||||
zend_op_array *op_array; /* executed op_array */
|
||||
zend_function_state function_state; /* called function and arguments */
|
||||
zend_object *object; /* current $this */
|
||||
zend_class_entry *scope; /* function scope (self) */
|
||||
zend_class_entry *called_scope; /* function called scope (static) */
|
||||
zend_array *symbol_table;
|
||||
zend_execute_data *call; /* current call */
|
||||
void **run_time_cache;
|
||||
zend_function *func; /* executed op_array */
|
||||
zend_uint num_args;
|
||||
zend_uchar flags;
|
||||
zend_uchar frame_kind;
|
||||
zend_class_entry *called_scope;
|
||||
zend_object *object;
|
||||
zend_execute_data *prev_nested_call;
|
||||
zend_execute_data *prev_execute_data;
|
||||
zval *return_value;
|
||||
vm_frame_kind frame_kind;
|
||||
// TODO: simplify call sequence and remove call_* ???
|
||||
zval old_error_reporting;
|
||||
struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */
|
||||
zend_object *delayed_exception;
|
||||
call_slot *call_slots;
|
||||
call_slot *call;
|
||||
zend_class_entry *scope; /* function scope (self) */
|
||||
zend_array *symbol_table;
|
||||
struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */
|
||||
zend_object *delayed_exception;
|
||||
zval old_error_reporting;
|
||||
};
|
||||
|
||||
#define ZEND_CALL_CTOR (1 << 0)
|
||||
#define ZEND_CALL_CTOR_RESULT_UNUSED (1 << 1)
|
||||
#define ZEND_CALL_DONE (1 << 2)
|
||||
|
||||
#define ZEND_CALL_FRAME_SLOT \
|
||||
((ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval)) - 1) / ZEND_MM_ALIGNED_SIZE(sizeof(zval)))
|
||||
|
||||
#define ZEND_CALL_ARG(call, n) \
|
||||
(((zval*)(call)) + ((n) + (ZEND_CALL_FRAME_SLOT - 1)))
|
||||
|
||||
#define EX(element) execute_data.element
|
||||
|
||||
#define EX_VAR_2(ex, n) ((zval*)(((char*)(ex)) + ((int)(n))))
|
||||
#define EX_VAR_NUM_2(ex, n) (((zval*)(((char*)(ex))+ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data))))+(n))
|
||||
#define EX_VAR_NUM_2(ex, n) (((zval*)(ex)) + (ZEND_CALL_FRAME_SLOT + ((int)(n))))
|
||||
|
||||
#define EX_VAR(n) EX_VAR_2(execute_data, n)
|
||||
#define EX_VAR_NUM(n) EX_VAR_NUM_2(execute_data, n)
|
||||
|
@ -730,8 +721,8 @@ int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC);
|
|||
#define ZEND_FETCH_CLASS_DEFAULT 0
|
||||
#define ZEND_FETCH_CLASS_SELF 1
|
||||
#define ZEND_FETCH_CLASS_PARENT 2
|
||||
#define ZEND_FETCH_CLASS_MAIN 3 /* unused */
|
||||
#define ZEND_FETCH_CLASS_GLOBAL 4 /* unused */
|
||||
#define ZEND_FETCH_CLASS_MAIN 3 /* unused ??? */
|
||||
#define ZEND_FETCH_CLASS_GLOBAL 4 /* unused ??? */
|
||||
#define ZEND_FETCH_CLASS_AUTO 5
|
||||
#define ZEND_FETCH_CLASS_INTERFACE 6
|
||||
#define ZEND_FETCH_CLASS_STATIC 7
|
||||
|
@ -750,7 +741,6 @@ int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC);
|
|||
#define ZEND_PARSED_NEW (1<<6)
|
||||
#define ZEND_PARSED_LIST_EXPR (1<<7)
|
||||
|
||||
|
||||
/* unset types */
|
||||
#define ZEND_UNSET_REG 0
|
||||
|
||||
|
@ -770,6 +760,9 @@ int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC);
|
|||
#define ZEND_EVAL_CODE 4
|
||||
#define ZEND_OVERLOADED_FUNCTION_TEMPORARY 5
|
||||
|
||||
/* A quick check (type == ZEND_USER_FUNCTION || type == ZEND_EVAL_CODE) */
|
||||
#define ZEND_USER_CODE(type) ((type & 1) == 0)
|
||||
|
||||
#define ZEND_INTERNAL_CLASS 1
|
||||
#define ZEND_USER_CLASS 2
|
||||
|
||||
|
@ -877,7 +870,7 @@ END_EXTERN_C()
|
|||
/* call op_array handler of extendions */
|
||||
#define ZEND_COMPILE_HANDLE_OP_ARRAY (1<<1)
|
||||
|
||||
/* generate ZEND_DO_FCALL_BY_NAME for internal functions instead of ZEND_DO_FCALL */
|
||||
/* generate ZEND_INIT_FCALL_BY_NAME for internal functions instead of ZEND_INIT_FCALL */
|
||||
#define ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS (1<<2)
|
||||
|
||||
/* don't perform early binding for classes inherited form internal ones;
|
||||
|
|
|
@ -525,12 +525,13 @@ ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, ul
|
|||
}
|
||||
}
|
||||
|
||||
ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zend_uint arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind TSRMLS_DC)
|
||||
ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zend_uint arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg TSRMLS_DC)
|
||||
{
|
||||
zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data;
|
||||
const char *fname = zf->common.function_name->val;
|
||||
const char *fsep;
|
||||
const char *fclass;
|
||||
zval old_arg;
|
||||
|
||||
if (zf->common.scope) {
|
||||
fsep = "::";
|
||||
|
@ -540,11 +541,20 @@ ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zen
|
|||
fclass = "";
|
||||
}
|
||||
|
||||
if (ptr && ptr->op_array) {
|
||||
zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d and defined", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind, ptr->op_array->filename->val, ptr->opline->lineno);
|
||||
if (arg && zf->common.type == ZEND_USER_FUNCTION) {
|
||||
ZVAL_COPY_VALUE(&old_arg, arg);
|
||||
ZVAL_UNDEF(arg);
|
||||
}
|
||||
|
||||
if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) {
|
||||
zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d and defined", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind, ptr->func->op_array.filename->val, ptr->opline->lineno);
|
||||
} else {
|
||||
zend_error(error_type, "Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind);
|
||||
}
|
||||
|
||||
if (arg && zf->common.type == ZEND_USER_FUNCTION) {
|
||||
ZVAL_COPY_VALUE(arg, &old_arg);
|
||||
}
|
||||
}
|
||||
|
||||
static void zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type TSRMLS_DC)
|
||||
|
@ -572,21 +582,21 @@ static void zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg
|
|||
if (Z_TYPE_P(arg) == IS_OBJECT) {
|
||||
need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
|
||||
if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) {
|
||||
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val TSRMLS_CC);
|
||||
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name->val, arg TSRMLS_CC);
|
||||
}
|
||||
} else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) {
|
||||
need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
|
||||
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "" TSRMLS_CC);
|
||||
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg TSRMLS_CC);
|
||||
}
|
||||
} else if (cur_arg_info->type_hint) {
|
||||
if (cur_arg_info->type_hint == IS_ARRAY) {
|
||||
ZVAL_DEREF(arg);
|
||||
if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
|
||||
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "" TSRMLS_CC);
|
||||
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "", arg TSRMLS_CC);
|
||||
}
|
||||
} else if (cur_arg_info->type_hint == IS_CALLABLE) {
|
||||
if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
|
||||
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "" TSRMLS_CC);
|
||||
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg TSRMLS_CC);
|
||||
}
|
||||
#if ZEND_DEBUG
|
||||
} else {
|
||||
|
@ -618,12 +628,12 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, zend_uint arg_
|
|||
char *class_name;
|
||||
|
||||
need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
|
||||
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "" TSRMLS_CC);
|
||||
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "", NULL TSRMLS_CC);
|
||||
} else if (cur_arg_info->type_hint) {
|
||||
if (cur_arg_info->type_hint == IS_ARRAY) {
|
||||
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "" TSRMLS_CC);
|
||||
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "", NULL TSRMLS_CC);
|
||||
} else if (cur_arg_info->type_hint == IS_CALLABLE) {
|
||||
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "" TSRMLS_CC);
|
||||
zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "", NULL TSRMLS_CC);
|
||||
#if ZEND_DEBUG
|
||||
} else {
|
||||
zend_error(E_ERROR, "Unknown typehint");
|
||||
|
@ -635,15 +645,15 @@ static inline int zend_verify_missing_arg_type(zend_function *zf, zend_uint arg_
|
|||
|
||||
static void zend_verify_missing_arg(zend_execute_data *execute_data, zend_uint arg_num TSRMLS_DC)
|
||||
{
|
||||
if (EXPECTED(!(EX(op_array)->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) ||
|
||||
zend_verify_missing_arg_type((zend_function *) EX(op_array), arg_num, EX(opline)->extended_value TSRMLS_CC)) {
|
||||
const char *class_name = EX(op_array)->scope ? EX(op_array)->scope->name->val : "";
|
||||
const char *space = EX(op_array)->scope ? "::" : "";
|
||||
const char *func_name = EX(op_array)->function_name ? EX(op_array)->function_name->val : "main";
|
||||
if (EXPECTED(!(EX(func)->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) ||
|
||||
zend_verify_missing_arg_type(EX(func), arg_num, EX(opline)->extended_value TSRMLS_CC)) {
|
||||
const char *class_name = EX(func)->common.scope ? EX(func)->common.scope->name->val : "";
|
||||
const char *space = EX(func)->common.scope ? "::" : "";
|
||||
const char *func_name = EX(func)->common.function_name ? EX(func)->common.function_name->val : "main";
|
||||
zend_execute_data *ptr = EX(prev_execute_data);
|
||||
|
||||
if(ptr && ptr->op_array) {
|
||||
zend_error(E_WARNING, "Missing argument %u for %s%s%s(), called in %s on line %d and defined", arg_num, class_name, space, func_name, ptr->op_array->filename->val, ptr->opline->lineno);
|
||||
if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) {
|
||||
zend_error(E_WARNING, "Missing argument %u for %s%s%s(), called in %s on line %d and defined", arg_num, class_name, space, func_name, ptr->func->op_array.filename->val, ptr->opline->lineno);
|
||||
} else {
|
||||
zend_error(E_WARNING, "Missing argument %u for %s%s%s()", arg_num, class_name, space, func_name);
|
||||
}
|
||||
|
@ -1468,13 +1478,13 @@ ZEND_API opcode_handler_t *zend_opcode_handlers;
|
|||
ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, zend_fcall_info *fci TSRMLS_DC)
|
||||
{
|
||||
if (fci != NULL) {
|
||||
execute_data_ptr->function_state.function->internal_function.handler(
|
||||
execute_data_ptr->call->func->internal_function.handler(
|
||||
fci->param_count, fci->retval TSRMLS_CC
|
||||
);
|
||||
} else {
|
||||
zval *return_value = EX_VAR_2(execute_data_ptr, execute_data_ptr->opline->result.var);
|
||||
execute_data_ptr->function_state.function->internal_function.handler(
|
||||
execute_data_ptr->opline->extended_value + execute_data_ptr->call->num_additional_args, return_value TSRMLS_CC
|
||||
execute_data_ptr->call->func->internal_function.handler(
|
||||
execute_data_ptr->call->num_args, return_value TSRMLS_CC
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1495,9 +1505,9 @@ void zend_clean_and_cache_symbol_table(zend_array *symbol_table TSRMLS_DC) /* {{
|
|||
|
||||
static zend_always_inline void i_free_compiled_variables(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
if (EXPECTED(EX(op_array)->last_var > 0)) {
|
||||
if (EXPECTED(EX(func)->op_array.last_var > 0)) {
|
||||
zval *cv = EX_VAR_NUM(0);
|
||||
zval *end = cv + EX(op_array)->last_var;
|
||||
zval *end = cv + EX(func)->op_array.last_var;
|
||||
do {
|
||||
zval_ptr_dtor(cv);
|
||||
cv++;
|
||||
|
@ -1517,132 +1527,65 @@ void zend_free_compiled_variables(zend_execute_data *execute_data TSRMLS_DC) /*
|
|||
* ==================
|
||||
*
|
||||
* +========================================+
|
||||
* | 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) |----+
|
||||
* EG(current_execute_data) -> | zend_execute_data |
|
||||
* +----------------------------------------+
|
||||
* EX_CV_NUM(0) ---------> | VAR[0] |
|
||||
* EX_CV_NUM(0) ---------> | VAR[0] = ARG[1] |
|
||||
* | ... |
|
||||
* | VAR[op_array->num_args-1] = ARG[N] |
|
||||
* | ... |
|
||||
* | VAR[op_array->last_var-1] |
|
||||
* | VAR[op_array->last_var] |
|
||||
* | VAR[op_array->last_var] = TMP[0] |
|
||||
* | ... |
|
||||
* | VAR[op_array->last_var+op_array->T-1] |
|
||||
* +----------------------------------------+
|
||||
* EX(call_slots) -> | CALL_SLOT[0] |
|
||||
* | ARG[N+1] (extra_args) |
|
||||
* | ... |
|
||||
* | CALL_SLOT[op_array->nested_calls-1] |
|
||||
* +----------------------------------------+
|
||||
* zend_vm_stack_frame_base -> | ARGUMENTS STACK [0] |
|
||||
* | ... |
|
||||
* zend_vm_stack_top --------> | ... |
|
||||
* | ... |
|
||||
* | ARGUMENTS STACK [op_array->used_stack] |
|
||||
* +----------------------------------------+
|
||||
*/
|
||||
|
||||
static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array(zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */
|
||||
static zend_always_inline void i_init_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_execute_data *execute_data;
|
||||
|
||||
/*
|
||||
* When allocating the execute_data, memory for compiled variables and
|
||||
* temporary variables is also allocated before and after the actual
|
||||
* zend_execute_data struct. In addition we also allocate space to store
|
||||
* information about syntactically nested called functions and actual
|
||||
* parameters. op_array->last_var specifies the number of compiled
|
||||
* variables and op_array->T is the number of temporary variables. If there
|
||||
* is no symbol table, then twice as much memory is allocated for compiled
|
||||
* variables. In that case the first half contains zval**s and the second
|
||||
* half the actual zval*s (which would otherwise be in the symbol table).
|
||||
*/
|
||||
size_t execute_data_size = ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data));
|
||||
size_t vars_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval)) * (op_array->last_var + op_array->T);
|
||||
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 + vars_size + call_slots_size + stack_size;
|
||||
|
||||
/*
|
||||
* Normally the execute_data is allocated on the VM stack (because it does
|
||||
* not actually do any allocation and thus is faster). For generators
|
||||
* though this behavior would be suboptimal, because the (rather large)
|
||||
* structure would have to be copied back and forth every time execution is
|
||||
* suspended or resumed. That's why for generators the execution context
|
||||
* is allocated using a separate VM stack, thus allowing to save and
|
||||
* restore it simply by replacing a pointer. The same segment also keeps
|
||||
* a copy of previous execute_data and passed parameters.
|
||||
*/
|
||||
if (UNEXPECTED((op_array->fn_flags & ZEND_ACC_GENERATOR) != 0)) {
|
||||
/* Prepend the regular stack frame with a copy of prev_execute_data
|
||||
* and the 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(zval) - 1)) / sizeof(zval));
|
||||
EG(argument_stack)->prev = NULL;
|
||||
execute_data = (zend_execute_data*)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + execute_data_size + args_size);
|
||||
|
||||
/* copy prev_execute_data */
|
||||
EX(prev_execute_data) = (zend_execute_data*)ZEND_VM_STACK_ELEMETS(EG(argument_stack));
|
||||
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 = (zval*)(((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + execute_data_size + args_size - sizeof(zval)));
|
||||
|
||||
/* copy arguments */
|
||||
ZVAL_LONG(EX(prev_execute_data)->function_state.arguments, args_count);
|
||||
if (args_count > 0) {
|
||||
zval *arg_src = zend_vm_stack_get_arg_ex(EG(current_execute_data), 1);
|
||||
zval *arg_dst = zend_vm_stack_get_arg_ex(EX(prev_execute_data), 1);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < args_count; i++) {
|
||||
ZVAL_COPY(arg_dst + i, arg_src + i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
execute_data = zend_vm_stack_alloc(total_size TSRMLS_CC);
|
||||
EX(prev_execute_data) = EG(current_execute_data);
|
||||
}
|
||||
ZEND_ASSERT(EX(func) == (zend_function*)op_array);
|
||||
ZEND_ASSERT(EX(object) == Z_OBJ(EG(This)));
|
||||
ZEND_ASSERT(EX(called_scope) == EG(called_scope));
|
||||
|
||||
EX(return_value) = return_value;
|
||||
EX(frame_kind) = frame_kind;
|
||||
ZVAL_UNDEF(&EX(old_error_reporting));
|
||||
EX(delayed_exception) = NULL;
|
||||
EX(call_slots) = (call_slot*)((char *)execute_data + execute_data_size + vars_size);
|
||||
EX(call) = NULL;
|
||||
|
||||
EG(opline_ptr) = &EX(opline);
|
||||
EX(opline) = UNEXPECTED((op_array->fn_flags & ZEND_ACC_INTERACTIVE) != 0) && EG(start_op) ? EG(start_op) : op_array->opcodes;
|
||||
EX(function_state).function = (zend_function *) op_array;
|
||||
EX(function_state).arguments = NULL;
|
||||
EX(op_array) = op_array;
|
||||
EX(object) = Z_OBJ(EG(This));
|
||||
EX(scope) = EG(scope);
|
||||
EX(called_scope) = EG(called_scope);
|
||||
EX(symbol_table) = EG(active_symbol_table);
|
||||
|
||||
if (EX(symbol_table)) {
|
||||
if (UNEXPECTED(EX(symbol_table) != NULL)) {
|
||||
zend_attach_symbol_table(execute_data);
|
||||
} else {
|
||||
do {
|
||||
/* Initialize CV variables */
|
||||
zval *var = EX_VAR_NUM(0);
|
||||
zval *end = var + op_array->last_var;
|
||||
zend_uint first_extra_arg = op_array->num_args;
|
||||
|
||||
if (UNEXPECTED((op_array->fn_flags & ZEND_ACC_VARIADIC) != 0)) {
|
||||
first_extra_arg--;
|
||||
}
|
||||
if (UNEXPECTED(EX(num_args) > first_extra_arg)) {
|
||||
/* move extra args into separate array after all CV and TMP vars */
|
||||
zval *extra_args = EX_VAR_NUM(op_array->last_var + op_array->T);
|
||||
|
||||
while (var != end) {
|
||||
ZVAL_UNDEF(var);
|
||||
var++;
|
||||
memmove(extra_args, EX_VAR_NUM(first_extra_arg), sizeof(zval) * (EX(num_args) - first_extra_arg));
|
||||
}
|
||||
|
||||
do {
|
||||
/* Initialize CV variables (skip arguments) */
|
||||
int num_args = MIN(op_array->num_args, EX(num_args));
|
||||
|
||||
if (EXPECTED(num_args < op_array->last_var)) {
|
||||
zval *var = EX_VAR_NUM(num_args);
|
||||
zval *end = EX_VAR_NUM(op_array->last_var);
|
||||
|
||||
do {
|
||||
ZVAL_UNDEF(var);
|
||||
var++;
|
||||
} while (var != end);
|
||||
}
|
||||
} while (0);
|
||||
|
||||
|
@ -1661,62 +1604,120 @@ static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array
|
|||
}
|
||||
EX(run_time_cache) = op_array->run_time_cache;
|
||||
|
||||
EG(argument_stack)->top = (zval*)zend_vm_stack_frame_base(execute_data);
|
||||
EG(current_execute_data) = execute_data;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_op_array *op_array, zval *return_value TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
/*
|
||||
* Normally the execute_data is allocated on the VM stack (because it does
|
||||
* not actually do any allocation and thus is faster). For generators
|
||||
* though this behavior would be suboptimal, because the (rather large)
|
||||
* structure would have to be copied back and forth every time execution is
|
||||
* suspended or resumed. That's why for generators the execution context
|
||||
* is allocated using a separate VM stack, thus allowing to save and
|
||||
* restore it simply by replacing a pointer.
|
||||
*/
|
||||
zend_execute_data *execute_data;
|
||||
zend_uint num_args = EG(current_execute_data)->call->num_args;
|
||||
|
||||
EG(argument_stack) = zend_vm_stack_new_page(
|
||||
MAX(ZEND_VM_STACK_PAGE_SIZE,
|
||||
ZEND_CALL_FRAME_SLOT + MAX(op_array->last_var + op_array->T, num_args)));
|
||||
EG(argument_stack)->prev = NULL;
|
||||
|
||||
execute_data = zend_vm_stack_push_call_frame(
|
||||
(zend_function*)op_array,
|
||||
num_args,
|
||||
EG(current_execute_data)->call->flags,
|
||||
EG(current_execute_data)->call->called_scope,
|
||||
EG(current_execute_data)->call->object,
|
||||
NULL TSRMLS_CC);
|
||||
execute_data->num_args = num_args;
|
||||
|
||||
/* copy arguments */
|
||||
if (num_args > 0) {
|
||||
zval *arg_src = ZEND_CALL_ARG(EG(current_execute_data)->call, 1);
|
||||
zval *arg_dst = ZEND_CALL_ARG(execute_data, 1);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_args; i++) {
|
||||
ZVAL_COPY_VALUE(arg_dst + i, arg_src + i);
|
||||
}
|
||||
}
|
||||
|
||||
i_init_execute_data(execute_data, op_array, return_value, VM_FRAME_TOP_FUNCTION TSRMLS_CC);
|
||||
|
||||
return execute_data;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ZEND_API zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */
|
||||
ZEND_API zend_execute_data *zend_create_execute_data(zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
return i_create_execute_data_from_op_array(op_array, return_value, frame_kind TSRMLS_CC);
|
||||
zend_execute_data *execute_data;
|
||||
|
||||
execute_data = EG(current_execute_data)->call;
|
||||
EX(prev_execute_data) = EG(current_execute_data);
|
||||
i_init_execute_data(execute_data, op_array, return_value, frame_kind TSRMLS_CC);
|
||||
|
||||
return execute_data;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(zend_op *opline, call_slot *call TSRMLS_DC) /* {{{ */
|
||||
static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch(zend_op *opline, zend_execute_data *call TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_uint arg_num = opline->extended_value & ZEND_FETCH_ARG_MASK;
|
||||
return ARG_SHOULD_BE_SENT_BY_REF(call->fbc, arg_num);
|
||||
return ARG_SHOULD_BE_SENT_BY_REF(call->func, arg_num);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static zval *zend_vm_stack_push_args_with_copy(int count TSRMLS_DC) /* {{{ */
|
||||
static zend_execute_data *zend_vm_stack_copy_call_frame(zend_execute_data *call, zend_uint passed_args, zend_uint additional_args TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_vm_stack p = EG(argument_stack);
|
||||
|
||||
zend_vm_stack_extend(count + 1 TSRMLS_CC);
|
||||
|
||||
EG(argument_stack)->top += count;
|
||||
ZVAL_LONG(EG(argument_stack)->top, count);
|
||||
while (count-- > 0) {
|
||||
zval *data = --p->top;
|
||||
ZVAL_COPY_VALUE(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + count, data);
|
||||
|
||||
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_execute_data *new_call;
|
||||
int used_stack = (EG(argument_stack)->top - (zval*)call) + additional_args;
|
||||
|
||||
/* copy call frame into new stack segment */
|
||||
zend_vm_stack_extend(used_stack TSRMLS_CC);
|
||||
new_call = (zend_execute_data*)EG(argument_stack)->top;
|
||||
EG(argument_stack)->top += used_stack;
|
||||
*new_call = *call;
|
||||
if (passed_args) {
|
||||
zval *src = ZEND_CALL_ARG(call, 1);
|
||||
zval *dst = ZEND_CALL_ARG(new_call, 1);
|
||||
do {
|
||||
ZVAL_COPY_VALUE(dst, src);
|
||||
passed_args--;
|
||||
src++;
|
||||
dst++;
|
||||
} while (passed_args);
|
||||
}
|
||||
return EG(argument_stack)->top++;
|
||||
|
||||
/* delete old call_frame from previous stack segment */
|
||||
EG(argument_stack)->prev->top = (zval*)call;
|
||||
|
||||
/* delete previous stack segment if it becames empty */
|
||||
if (UNEXPECTED(EG(argument_stack)->prev->top == ZEND_VM_STACK_ELEMETS(EG(argument_stack)->prev))) {
|
||||
zend_vm_stack r = EG(argument_stack)->prev;
|
||||
|
||||
EG(argument_stack)->prev = r->prev;
|
||||
efree(r);
|
||||
}
|
||||
|
||||
return new_call;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static zend_always_inline zval *zend_vm_stack_push_args(int count TSRMLS_DC) /* {{{ */
|
||||
static zend_always_inline void zend_vm_stack_extend_call_frame(zend_execute_data **call, zend_uint passed_args, zend_uint additional_args 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)) {
|
||||
return zend_vm_stack_push_args_with_copy(count TSRMLS_CC);
|
||||
if (EXPECTED(EG(argument_stack)->end - EG(argument_stack)->top > additional_args)) {
|
||||
EG(argument_stack)->top += additional_args;
|
||||
} else {
|
||||
*call = zend_vm_stack_copy_call_frame(*call, passed_args, additional_args TSRMLS_CC);
|
||||
}
|
||||
ZVAL_LONG(EG(argument_stack)->top, count);
|
||||
return EG(argument_stack)->top++;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
#define ZEND_VM_NEXT_OPCODE() \
|
||||
CHECK_SYMBOL_TABLES() \
|
||||
ZEND_VM_INC_OPCODE(); \
|
||||
|
|
|
@ -35,7 +35,8 @@ ZEND_API extern void (*zend_execute_internal)(zend_execute_data *execute_data_pt
|
|||
void init_executor(TSRMLS_D);
|
||||
void shutdown_executor(TSRMLS_D);
|
||||
void shutdown_destructors(TSRMLS_D);
|
||||
ZEND_API zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC);
|
||||
ZEND_API zend_execute_data *zend_create_execute_data(zend_op_array *op_array, zval *return_value, vm_frame_kind frame_kind TSRMLS_DC);
|
||||
ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_op_array *op_array, zval *return_value TSRMLS_DC);
|
||||
ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value 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 TSRMLS_DC);
|
||||
|
@ -48,7 +49,7 @@ ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name,
|
|||
ZEND_API int zend_eval_stringl_ex(char *str, int str_len, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC);
|
||||
|
||||
ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, ulong fetch_type, char **class_name, zend_class_entry **pce TSRMLS_DC);
|
||||
ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zend_uint arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind TSRMLS_DC);
|
||||
ZEND_API void zend_verify_arg_error(int error_type, const zend_function *zf, zend_uint arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg TSRMLS_DC);
|
||||
|
||||
static zend_always_inline void i_zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC TSRMLS_DC)
|
||||
{
|
||||
|
@ -149,7 +150,7 @@ ZEND_API int zval_update_constant_no_inline_change(zval *pp, zend_class_entry *s
|
|||
ZEND_API int zval_update_constant_ex(zval *pp, zend_bool inline_change, zend_class_entry *scope TSRMLS_DC);
|
||||
|
||||
/* dedicated Zend executor functions - do not use! */
|
||||
#define ZEND_VM_STACK_PAGE_SIZE ((16 * 1024) - 16)
|
||||
#define ZEND_VM_STACK_PAGE_SIZE (16 * 1024) /* should be a power of 2 */
|
||||
|
||||
struct _zend_vm_stack {
|
||||
zval *top;
|
||||
|
@ -157,22 +158,26 @@ struct _zend_vm_stack {
|
|||
zend_vm_stack prev;
|
||||
};
|
||||
|
||||
#define ZEND_VM_STACK_ELEMETS(stack) \
|
||||
((zval*)(((char*)(stack)) + ZEND_MM_ALIGNED_SIZE(sizeof(struct _zend_vm_stack))))
|
||||
#define ZEND_VM_STACK_HEADER_SLOT \
|
||||
((ZEND_MM_ALIGNED_SIZE(sizeof(struct _zend_vm_stack)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval)) - 1) / ZEND_MM_ALIGNED_SIZE(sizeof(zval)))
|
||||
|
||||
#define ZEND_VM_STACK_GROW_IF_NEEDED(count) \
|
||||
do { \
|
||||
if (UNEXPECTED((count) > \
|
||||
EG(argument_stack)->end - EG(argument_stack)->top)) { \
|
||||
zend_vm_stack_extend((count) TSRMLS_CC); \
|
||||
} \
|
||||
#define ZEND_VM_STACK_ELEMETS(stack) \
|
||||
(((zval*)(stack)) + ZEND_VM_STACK_HEADER_SLOT)
|
||||
|
||||
#define ZEND_VM_STACK_GROW_IF_NEEDED(count) \
|
||||
do { \
|
||||
if (UNEXPECTED(((count) * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) > \
|
||||
((char*)EG(argument_stack)->end) - \
|
||||
((char*)EG(argument_stack)->top))) { \
|
||||
zend_vm_stack_extend((count) TSRMLS_CC); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static zend_always_inline zend_vm_stack zend_vm_stack_new_page(int count) {
|
||||
zend_vm_stack page = (zend_vm_stack)emalloc(ZEND_MM_ALIGNED_SIZE(sizeof(*page)) + sizeof(zval) * count);
|
||||
zend_vm_stack page = (zend_vm_stack)emalloc(count * ZEND_MM_ALIGNED_SIZE(sizeof(zval)));
|
||||
|
||||
page->top = ZEND_VM_STACK_ELEMETS(page);
|
||||
page->end = page->top + count;
|
||||
page->end = (zval*)page + count;
|
||||
page->prev = NULL;
|
||||
return page;
|
||||
}
|
||||
|
@ -180,6 +185,7 @@ static zend_always_inline zend_vm_stack zend_vm_stack_new_page(int count) {
|
|||
static zend_always_inline void zend_vm_stack_init(TSRMLS_D)
|
||||
{
|
||||
EG(argument_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE);
|
||||
EG(argument_stack)->top++;
|
||||
}
|
||||
|
||||
static zend_always_inline void zend_vm_stack_destroy(TSRMLS_D)
|
||||
|
@ -195,95 +201,90 @@ static zend_always_inline void zend_vm_stack_destroy(TSRMLS_D)
|
|||
|
||||
static zend_always_inline void zend_vm_stack_extend(int count TSRMLS_DC)
|
||||
{
|
||||
zend_vm_stack p = zend_vm_stack_new_page(count >= ZEND_VM_STACK_PAGE_SIZE ? count : ZEND_VM_STACK_PAGE_SIZE);
|
||||
int size = count * ZEND_MM_ALIGNED_SIZE(sizeof(zval));
|
||||
zend_vm_stack p = zend_vm_stack_new_page(
|
||||
(size >= (ZEND_VM_STACK_PAGE_SIZE - ZEND_VM_STACK_HEADER_SLOT) * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) ?
|
||||
(size + ((ZEND_VM_STACK_HEADER_SLOT + ZEND_VM_STACK_PAGE_SIZE) * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) - 1) &
|
||||
~((ZEND_VM_STACK_PAGE_SIZE * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) - 1) :
|
||||
ZEND_VM_STACK_PAGE_SIZE);
|
||||
p->prev = EG(argument_stack);
|
||||
EG(argument_stack) = p;
|
||||
}
|
||||
|
||||
static zend_always_inline zval *zend_vm_stack_top(TSRMLS_D)
|
||||
static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(zend_function *func, zend_uint num_args, zend_uchar flags, zend_class_entry *called_scope, zend_object *object, zend_execute_data *prev TSRMLS_DC)
|
||||
{
|
||||
return EG(argument_stack)->top;
|
||||
}
|
||||
|
||||
static zend_always_inline zval *zend_vm_stack_top_inc(TSRMLS_D)
|
||||
{
|
||||
return EG(argument_stack)->top++;
|
||||
}
|
||||
|
||||
static zend_always_inline void zend_vm_stack_push(zval *ptr TSRMLS_DC)
|
||||
{
|
||||
ZVAL_COPY_VALUE(EG(argument_stack)->top, ptr);
|
||||
EG(argument_stack)->top++;
|
||||
}
|
||||
|
||||
static zend_always_inline zval *zend_vm_stack_pop(TSRMLS_D)
|
||||
{
|
||||
return --EG(argument_stack)->top;
|
||||
}
|
||||
|
||||
static zend_always_inline void *zend_vm_stack_alloc(size_t size TSRMLS_DC)
|
||||
{
|
||||
zval *ret;
|
||||
int count = (size + (sizeof(zval) - 1)) / sizeof(zval);
|
||||
|
||||
ZEND_VM_STACK_GROW_IF_NEEDED(count);
|
||||
ret = EG(argument_stack)->top;
|
||||
EG(argument_stack)->top += count;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static zend_always_inline zval* zend_vm_stack_frame_base(zend_execute_data *ex)
|
||||
{
|
||||
return (zval*)((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(void *ptr TSRMLS_DC)
|
||||
{
|
||||
if (UNEXPECTED((void*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == ptr)) {
|
||||
zend_vm_stack p = EG(argument_stack);
|
||||
|
||||
EG(argument_stack) = p->prev;
|
||||
efree(p);
|
||||
} else {
|
||||
EG(argument_stack)->top = (zval*)ptr;
|
||||
int used_stack = ZEND_CALL_FRAME_SLOT + num_args;
|
||||
zend_execute_data *call;
|
||||
|
||||
if (ZEND_USER_CODE(func->type)) {
|
||||
used_stack += func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args);
|
||||
}
|
||||
ZEND_VM_STACK_GROW_IF_NEEDED(used_stack);
|
||||
call = (zend_execute_data*)EG(argument_stack)->top;
|
||||
EG(argument_stack)->top += used_stack;
|
||||
call->func = func;
|
||||
call->num_args = 0;
|
||||
call->flags = flags;
|
||||
call->called_scope = called_scope;
|
||||
call->object = object;
|
||||
call->prev_nested_call = prev;
|
||||
return call;
|
||||
}
|
||||
|
||||
static zend_always_inline void zend_vm_stack_clear_multiple(int nested TSRMLS_DC)
|
||||
static zend_always_inline void zend_vm_stack_free_extra_args(zend_execute_data *call TSRMLS_DC)
|
||||
{
|
||||
zval *p = EG(argument_stack)->top - 1;
|
||||
zend_uint first_extra_arg = call->func->op_array.num_args - ((call->func->common.fn_flags & ZEND_ACC_VARIADIC) != 0);
|
||||
|
||||
if (EXPECTED(Z_LVAL_P(p) > 0)) {
|
||||
zval *end = p - Z_LVAL_P(p);
|
||||
if (UNEXPECTED(call->num_args > first_extra_arg)) {
|
||||
zval *end = EX_VAR_NUM_2(call, call->func->op_array.last_var + call->func->op_array.T);
|
||||
zval *p = end + (call->num_args - first_extra_arg);
|
||||
do {
|
||||
p--;
|
||||
i_zval_ptr_dtor_nogc(p ZEND_FILE_LINE_CC TSRMLS_CC);
|
||||
} while (p != end);
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline void zend_vm_stack_free_args(zend_execute_data *call TSRMLS_DC)
|
||||
{
|
||||
zend_uint num_args = call->num_args;
|
||||
|
||||
if (num_args > 0) {
|
||||
zval *p = ZEND_CALL_ARG(call, num_args + 1);
|
||||
zval *end = p - num_args;;
|
||||
|
||||
do {
|
||||
p--;
|
||||
i_zval_ptr_dtor_nogc(p ZEND_FILE_LINE_CC TSRMLS_CC);
|
||||
} while (p != end);
|
||||
}
|
||||
if (nested) {
|
||||
EG(argument_stack)->top = p;
|
||||
}
|
||||
|
||||
static zend_always_inline void zend_vm_stack_free_call_frame(zend_execute_data *call TSRMLS_DC)
|
||||
{
|
||||
if (UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (zval*)call)) {
|
||||
zend_vm_stack p = EG(argument_stack);
|
||||
|
||||
EG(argument_stack) = p->prev;
|
||||
efree(p);
|
||||
} else {
|
||||
zend_vm_stack_free(p TSRMLS_CC);
|
||||
EG(argument_stack)->top = (zval*)call;
|
||||
}
|
||||
}
|
||||
|
||||
static zend_always_inline int zend_vm_stack_get_args_count_ex(zend_execute_data *ex)
|
||||
{
|
||||
zval *p = ex->function_state.arguments;
|
||||
return Z_LVAL_P(p);
|
||||
return ex->call->num_args;
|
||||
}
|
||||
|
||||
static zend_always_inline zval* zend_vm_stack_get_arg_ex(zend_execute_data *ex, int requested_arg)
|
||||
{
|
||||
zval *p = ex->function_state.arguments;
|
||||
int arg_count = Z_LVAL_P(p);
|
||||
int arg_count = ex->call->num_args;
|
||||
|
||||
if (UNEXPECTED(requested_arg > arg_count)) {
|
||||
return NULL;
|
||||
}
|
||||
return p - arg_count + requested_arg - 1;
|
||||
return ZEND_CALL_ARG(ex->call, requested_arg);
|
||||
}
|
||||
|
||||
static zend_always_inline int zend_vm_stack_get_args_count(TSRMLS_D)
|
||||
|
|
|
@ -156,7 +156,6 @@ void init_executor(TSRMLS_D) /* {{{ */
|
|||
EG(error_handling) = EH_NORMAL;
|
||||
|
||||
zend_vm_stack_init(TSRMLS_C);
|
||||
ZVAL_LONG(zend_vm_stack_top_inc(TSRMLS_C), 0);
|
||||
|
||||
zend_hash_init(&EG(symbol_table).ht, 64, NULL, ZVAL_PTR_DTOR, 0);
|
||||
GC_REFCOUNT(&EG(symbol_table)) = 1;
|
||||
|
@ -393,17 +392,25 @@ void shutdown_executor(TSRMLS_D) /* {{{ */
|
|||
/* return class name and "::" or "". */
|
||||
ZEND_API const char *get_active_class_name(const char **space TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_function *func;
|
||||
|
||||
if (!zend_is_executing(TSRMLS_C)) {
|
||||
if (space) {
|
||||
*space = "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
switch (EG(current_execute_data)->function_state.function->type) {
|
||||
|
||||
if (EG(current_execute_data)->call && (EG(current_execute_data)->call->flags & ZEND_CALL_DONE)) {
|
||||
func = EG(current_execute_data)->call->func;
|
||||
} else {
|
||||
func = EG(current_execute_data)->func;
|
||||
}
|
||||
switch (func->type) {
|
||||
case ZEND_USER_FUNCTION:
|
||||
case ZEND_INTERNAL_FUNCTION:
|
||||
{
|
||||
zend_class_entry *ce = EG(current_execute_data)->function_state.function->common.scope;
|
||||
zend_class_entry *ce = func->common.scope;
|
||||
|
||||
if (space) {
|
||||
*space = ce ? "::" : "";
|
||||
|
@ -421,12 +428,19 @@ ZEND_API const char *get_active_class_name(const char **space TSRMLS_DC) /* {{{
|
|||
|
||||
ZEND_API const char *get_active_function_name(TSRMLS_D) /* {{{ */
|
||||
{
|
||||
zend_function *func;
|
||||
|
||||
if (!zend_is_executing(TSRMLS_C)) {
|
||||
return NULL;
|
||||
}
|
||||
switch (EG(current_execute_data)->function_state.function->type) {
|
||||
if (EG(current_execute_data)->call && (EG(current_execute_data)->call->flags & ZEND_CALL_DONE)) {
|
||||
func = EG(current_execute_data)->call->func;
|
||||
} else {
|
||||
func = EG(current_execute_data)->func;
|
||||
}
|
||||
switch (func->type) {
|
||||
case ZEND_USER_FUNCTION: {
|
||||
zend_string *function_name = ((zend_op_array *) EG(current_execute_data)->function_state.function)->function_name;
|
||||
zend_string *function_name = func->common.function_name;
|
||||
|
||||
if (function_name) {
|
||||
return function_name->val;
|
||||
|
@ -436,7 +450,7 @@ ZEND_API const char *get_active_function_name(TSRMLS_D) /* {{{ */
|
|||
}
|
||||
break;
|
||||
case ZEND_INTERNAL_FUNCTION:
|
||||
return ((zend_internal_function *) EG(current_execute_data)->function_state.function)->function_name->val;
|
||||
return func->common.function_name->val;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
|
@ -655,6 +669,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
|
|||
zend_class_entry *called_scope = NULL;
|
||||
zend_execute_data execute_data;
|
||||
zend_fcall_info_cache fci_cache_local;
|
||||
zend_function *func;
|
||||
zval tmp;
|
||||
|
||||
ZVAL_UNDEF(fci->retval);
|
||||
|
@ -681,7 +696,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
|
|||
EX(object) = Z_OBJ(EG(This));
|
||||
EX(scope) = EG(scope);
|
||||
EX(called_scope) = EG(called_scope);
|
||||
EX(op_array) = NULL;
|
||||
EX(func) = NULL;
|
||||
EX(opline) = NULL;
|
||||
} else {
|
||||
/* This only happens when we're called outside any execute()'s
|
||||
|
@ -719,7 +734,8 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
|
|||
STR_RELEASE(callable_name);
|
||||
}
|
||||
|
||||
EX(function_state).function = fci_cache->function_handler;
|
||||
func = fci_cache->function_handler;
|
||||
EX(call) = zend_vm_stack_push_call_frame(func, fci->param_count, ZEND_CALL_DONE, fci_cache->called_scope, fci_cache->object, NULL TSRMLS_CC);
|
||||
calling_scope = fci_cache->calling_scope;
|
||||
called_scope = fci_cache->called_scope;
|
||||
fci->object = fci_cache->object;
|
||||
|
@ -729,24 +745,22 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
|
|||
return FAILURE;
|
||||
}
|
||||
|
||||
if (EX(function_state).function->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) {
|
||||
if (EX(function_state).function->common.fn_flags & ZEND_ACC_ABSTRACT) {
|
||||
zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EX(function_state).function->common.scope->name->val, EX(function_state).function->common.function_name->val);
|
||||
if (func->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) {
|
||||
if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
|
||||
zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", func->common.scope->name->val, func->common.function_name->val);
|
||||
}
|
||||
if (EX(function_state).function->common.fn_flags & ZEND_ACC_DEPRECATED) {
|
||||
if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
|
||||
zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated",
|
||||
EX(function_state).function->common.scope ? EX(function_state).function->common.scope->name->val : "",
|
||||
EX(function_state).function->common.scope ? "::" : "",
|
||||
EX(function_state).function->common.function_name->val);
|
||||
func->common.scope ? func->common.scope->name->val : "",
|
||||
func->common.scope ? "::" : "",
|
||||
func->common.function_name->val);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_VM_STACK_GROW_IF_NEEDED(fci->param_count + 1);
|
||||
|
||||
for (i=0; i<fci->param_count; i++) {
|
||||
zval *param;
|
||||
|
||||
if (ARG_SHOULD_BE_SENT_BY_REF(EX(function_state).function, i + 1)) {
|
||||
if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) {
|
||||
// TODO: Scalar values don't have reference counters anymore.
|
||||
// They are assumed to be 1, and they may be easily passed by
|
||||
// reference now. However, previously scalars with refcount==1
|
||||
|
@ -766,19 +780,19 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
|
|||
(!Z_ISREF(fci->params[i]) && Z_REFCOUNT(fci->params[i]) > 1)) {
|
||||
|
||||
if (fci->no_separation &&
|
||||
!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))) {
|
||||
!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) {
|
||||
if (i) {
|
||||
/* hack to clean up the stack */
|
||||
ZVAL_LONG(&tmp, i);
|
||||
zend_vm_stack_push(&tmp TSRMLS_CC);
|
||||
zend_vm_stack_clear_multiple(0 TSRMLS_CC);
|
||||
EX(call)->num_args = i;
|
||||
zend_vm_stack_free_args(EX(call) TSRMLS_CC);
|
||||
}
|
||||
zend_vm_stack_free_call_frame(EX(call) TSRMLS_CC);
|
||||
|
||||
zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
|
||||
i+1,
|
||||
EX(function_state).function->common.scope ? EX(function_state).function->common.scope->name->val : "",
|
||||
EX(function_state).function->common.scope ? "::" : "",
|
||||
EX(function_state).function->common.function_name->val);
|
||||
func->common.scope ? func->common.scope->name->val : "",
|
||||
func->common.scope ? "::" : "",
|
||||
func->common.function_name->val);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
|
@ -794,27 +808,26 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
|
|||
} else if (Z_REFCOUNTED(fci->params[i])) {
|
||||
Z_ADDREF(fci->params[i]);
|
||||
}
|
||||
param = &fci->params[i];
|
||||
param = ZEND_CALL_ARG(EX(call), i+1);
|
||||
ZVAL_COPY_VALUE(param, &fci->params[i]);
|
||||
} else if (Z_ISREF(fci->params[i]) &&
|
||||
/* don't separate references for __call */
|
||||
(EX(function_state).function->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) {
|
||||
(func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) {
|
||||
param = &tmp;
|
||||
param = ZEND_CALL_ARG(EX(call), i+1);
|
||||
ZVAL_DUP(param, Z_REFVAL(fci->params[i]));
|
||||
} else {
|
||||
param = &tmp;
|
||||
param = ZEND_CALL_ARG(EX(call), i+1);
|
||||
ZVAL_COPY(param, &fci->params[i]);
|
||||
}
|
||||
zend_vm_stack_push(param TSRMLS_CC);
|
||||
}
|
||||
|
||||
EX(function_state).arguments = zend_vm_stack_top_inc(TSRMLS_C);
|
||||
ZVAL_LONG(EX(function_state).arguments, fci->param_count);
|
||||
EX(call)->num_args = fci->param_count;
|
||||
|
||||
EG(scope) = calling_scope;
|
||||
EG(called_scope) = called_scope;
|
||||
if (!fci->object ||
|
||||
(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) {
|
||||
Z_OBJ(EG(This)) = NULL;
|
||||
(func->common.fn_flags & ZEND_ACC_STATIC)) {
|
||||
Z_OBJ(EG(This)) = EX(call)->object = NULL;
|
||||
} else {
|
||||
Z_OBJ(EG(This)) = fci->object;
|
||||
Z_ADDREF(EG(This));
|
||||
|
@ -823,9 +836,9 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
|
|||
EX(prev_execute_data) = EG(current_execute_data);
|
||||
EG(current_execute_data) = &execute_data;
|
||||
|
||||
if (EX(function_state).function->type == ZEND_USER_FUNCTION) {
|
||||
if (func->type == ZEND_USER_FUNCTION) {
|
||||
calling_symbol_table = EG(active_symbol_table);
|
||||
EG(scope) = EX(function_state).function->common.scope;
|
||||
EG(scope) = func->common.scope;
|
||||
if (fci->symbol_table) {
|
||||
EG(active_symbol_table) = fci->symbol_table;
|
||||
} else {
|
||||
|
@ -833,7 +846,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
|
|||
}
|
||||
|
||||
original_op_array = EG(active_op_array);
|
||||
EG(active_op_array) = (zend_op_array *) EX(function_state).function;
|
||||
EG(active_op_array) = (zend_op_array *) func;
|
||||
original_opline_ptr = EG(opline_ptr);
|
||||
|
||||
if (EXPECTED((EG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) == 0)) {
|
||||
|
@ -848,18 +861,21 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
|
|||
zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC);
|
||||
}
|
||||
EG(active_symbol_table) = calling_symbol_table;
|
||||
} else if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) {
|
||||
int call_via_handler = (EX(function_state).function->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
|
||||
} else if (func->type == ZEND_INTERNAL_FUNCTION) {
|
||||
int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
|
||||
ZVAL_NULL(fci->retval);
|
||||
if (EX(function_state).function->common.scope) {
|
||||
EG(scope) = EX(function_state).function->common.scope;
|
||||
if (func->common.scope) {
|
||||
EG(scope) = func->common.scope;
|
||||
}
|
||||
if (EXPECTED(zend_execute_internal == NULL)) {
|
||||
/* saves one function call if zend_execute_internal is not used */
|
||||
EX(function_state).function->internal_function.handler(fci->param_count, fci->retval TSRMLS_CC);
|
||||
func->internal_function.handler(fci->param_count, fci->retval TSRMLS_CC);
|
||||
} else {
|
||||
zend_execute_internal(&execute_data, fci TSRMLS_CC);
|
||||
}
|
||||
zend_vm_stack_free_args(EX(call) TSRMLS_CC);
|
||||
zend_vm_stack_free_call_frame(EX(call) TSRMLS_CC);
|
||||
|
||||
/* We shouldn't fix bad extensions here,
|
||||
because it can break proper ones (Bug #34045)
|
||||
if (!EX(function_state).function->common.return_reference)
|
||||
|
@ -880,22 +896,21 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
|
|||
|
||||
/* Not sure what should be done here if it's a static method */
|
||||
if (fci->object) {
|
||||
fci->object->handlers->call_method(EX(function_state).function->common.function_name, fci->object, fci->param_count, fci->retval TSRMLS_CC);
|
||||
fci->object->handlers->call_method(func->common.function_name, fci->object, fci->param_count, fci->retval TSRMLS_CC);
|
||||
} else {
|
||||
zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object");
|
||||
}
|
||||
|
||||
if (EX(function_state).function->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
|
||||
STR_RELEASE(EX(function_state).function->common.function_name);
|
||||
if (func->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
|
||||
STR_RELEASE(func->common.function_name);
|
||||
}
|
||||
efree(EX(function_state).function);
|
||||
efree(func);
|
||||
|
||||
if (EG(exception)) {
|
||||
zval_ptr_dtor(fci->retval);
|
||||
ZVAL_UNDEF(fci->retval);
|
||||
}
|
||||
}
|
||||
zend_vm_stack_clear_multiple(0 TSRMLS_CC);
|
||||
|
||||
if (Z_OBJ(EG(This))) {
|
||||
zval_ptr_dtor(&EG(This));
|
||||
|
@ -1080,6 +1095,10 @@ ZEND_API int zend_eval_stringl(char *str, int str_len, zval *retval_ptr, char *s
|
|||
|
||||
zend_try {
|
||||
ZVAL_UNDEF(&local_retval);
|
||||
if (EG(current_execute_data)) {
|
||||
EG(current_execute_data)->call = zend_vm_stack_push_call_frame(
|
||||
(zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EG(current_execute_data)->call TSRMLS_CC);
|
||||
}
|
||||
zend_execute(new_op_array, &local_retval TSRMLS_CC);
|
||||
} zend_catch {
|
||||
destroy_op_array(new_op_array TSRMLS_CC);
|
||||
|
@ -1583,33 +1602,34 @@ ZEND_API void zend_rebuild_symbol_table(TSRMLS_D) /* {{{ */
|
|||
|
||||
/* Search for last called user function */
|
||||
ex = EG(current_execute_data);
|
||||
while (ex && !ex->op_array) {
|
||||
while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->common.type))) {
|
||||
ex = ex->prev_execute_data;
|
||||
}
|
||||
if (ex && ex->symbol_table) {
|
||||
if (!ex) {
|
||||
return;
|
||||
}
|
||||
if (ex->symbol_table) {
|
||||
EG(active_symbol_table) = ex->symbol_table;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ex && ex->op_array) {
|
||||
if (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
|
||||
/*printf("Cache hit! Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/
|
||||
EG(active_symbol_table) = *(EG(symtable_cache_ptr)--);
|
||||
} else {
|
||||
EG(active_symbol_table) = emalloc(sizeof(zend_array));
|
||||
GC_REFCOUNT(EG(active_symbol_table)) = 0;
|
||||
GC_TYPE_INFO(EG(active_symbol_table)) = IS_ARRAY;
|
||||
zend_hash_init(&EG(active_symbol_table)->ht, ex->op_array->last_var, NULL, ZVAL_PTR_DTOR, 0);
|
||||
/*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/
|
||||
}
|
||||
ex->symbol_table = EG(active_symbol_table);
|
||||
for (i = 0; i < ex->op_array->last_var; i++) {
|
||||
zval zv;
|
||||
|
||||
ZVAL_INDIRECT(&zv, EX_VAR_NUM_2(ex, i));
|
||||
zend_hash_add_new(&EG(active_symbol_table)->ht,
|
||||
ex->op_array->vars[i], &zv);
|
||||
}
|
||||
if (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
|
||||
/*printf("Cache hit! Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/
|
||||
EG(active_symbol_table) = *(EG(symtable_cache_ptr)--);
|
||||
} else {
|
||||
EG(active_symbol_table) = emalloc(sizeof(zend_array));
|
||||
GC_REFCOUNT(EG(active_symbol_table)) = 0;
|
||||
GC_TYPE_INFO(EG(active_symbol_table)) = IS_ARRAY;
|
||||
zend_hash_init(&EG(active_symbol_table)->ht, ex->func->op_array.last_var, NULL, ZVAL_PTR_DTOR, 0);
|
||||
/*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/
|
||||
}
|
||||
ex->symbol_table = EG(active_symbol_table);
|
||||
for (i = 0; i < ex->func->op_array.last_var; i++) {
|
||||
zval zv;
|
||||
|
||||
ZVAL_INDIRECT(&zv, EX_VAR_NUM_2(ex, i));
|
||||
zend_hash_add_new(&EG(active_symbol_table)->ht,
|
||||
ex->func->op_array.vars[i], &zv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1618,7 +1638,7 @@ ZEND_API void zend_rebuild_symbol_table(TSRMLS_D) /* {{{ */
|
|||
ZEND_API void zend_attach_symbol_table(zend_execute_data *execute_data) /* {{{ */
|
||||
{
|
||||
int i;
|
||||
zend_op_array *op_array = execute_data->op_array;
|
||||
zend_op_array *op_array = &execute_data->func->op_array;
|
||||
HashTable *ht = &execute_data->symbol_table->ht;
|
||||
|
||||
/* copy real values from symbol table into CV slots and create
|
||||
|
@ -1649,7 +1669,7 @@ ZEND_API void zend_attach_symbol_table(zend_execute_data *execute_data) /* {{{ *
|
|||
ZEND_API void zend_detach_symbol_table(zend_execute_data *execute_data) /* {{{ */
|
||||
{
|
||||
int i;
|
||||
zend_op_array *op_array = execute_data->op_array;
|
||||
zend_op_array *op_array = &execute_data->func->op_array;
|
||||
HashTable *ht = &execute_data->symbol_table->ht;
|
||||
|
||||
/* copy real values from CV slots into symbol table */
|
||||
|
@ -1669,7 +1689,7 @@ ZEND_API int zend_set_local_var(zend_string *name, zval *value, int force TSRMLS
|
|||
if (!EG(active_symbol_table)) {
|
||||
int i;
|
||||
zend_execute_data *execute_data = EG(current_execute_data);
|
||||
zend_op_array *op_array = execute_data->op_array;
|
||||
zend_op_array *op_array = &execute_data->func->op_array;
|
||||
zend_ulong h = STR_HASH_VAL(name);
|
||||
|
||||
if (op_array) {
|
||||
|
@ -1702,7 +1722,7 @@ ZEND_API int zend_set_local_var_str(const char *name, int len, zval *value, int
|
|||
if (!EG(active_symbol_table)) {
|
||||
int i;
|
||||
zend_execute_data *execute_data = EG(current_execute_data);
|
||||
zend_op_array *op_array = execute_data->op_array;
|
||||
zend_op_array *op_array = &execute_data->func->op_array;
|
||||
zend_ulong h = zend_hash_func(name, len);
|
||||
|
||||
if (op_array) {
|
||||
|
|
|
@ -32,7 +32,7 @@ static zend_object *zend_generator_create(zend_class_entry *class_type TSRMLS_DC
|
|||
static void zend_generator_cleanup_unfinished_execution(zend_generator *generator TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
zend_execute_data *execute_data = generator->execute_data;
|
||||
zend_op_array *op_array = execute_data->op_array;
|
||||
zend_op_array *op_array = &execute_data->func->op_array;
|
||||
|
||||
if (generator->send_target) {
|
||||
if (Z_REFCOUNTED_P(generator->send_target)) Z_DELREF_P(generator->send_target);
|
||||
|
@ -75,23 +75,13 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato
|
|||
}
|
||||
}
|
||||
|
||||
/* Clear any backed up stack arguments */
|
||||
{
|
||||
zval *ptr = generator->stack->top - 1;
|
||||
zval *end = zend_vm_stack_frame_base(execute_data);
|
||||
|
||||
for (; ptr >= end; --ptr) {
|
||||
zval_ptr_dtor((zval*) ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* If yield was used as a function argument there may be active
|
||||
* method calls those objects need to be freed */
|
||||
while (execute_data->call >= execute_data->call_slots) {
|
||||
while (execute_data->call) {
|
||||
if (execute_data->call->object) {
|
||||
OBJ_RELEASE(execute_data->call->object);
|
||||
}
|
||||
execute_data->call--;
|
||||
execute_data->call = execute_data->call->prev_nested_call;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -110,7 +100,7 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
|
|||
|
||||
if (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->func->op_array;
|
||||
|
||||
if (!execute_data->symbol_table) {
|
||||
zend_free_compiled_variables(execute_data TSRMLS_CC);
|
||||
|
@ -128,23 +118,7 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
|
|||
return;
|
||||
}
|
||||
|
||||
/* 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
|
||||
* generator (for func_get_args) so those have to be freed too. */
|
||||
{
|
||||
zend_execute_data *prev_execute_data = execute_data->prev_execute_data;
|
||||
zval *arguments = prev_execute_data->function_state.arguments;
|
||||
|
||||
if (arguments) {
|
||||
int arguments_count = Z_LVAL_P(arguments);
|
||||
zval *arguments_start = arguments - arguments_count;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < arguments_count; ++i) {
|
||||
zval_ptr_dtor(arguments_start + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
zend_vm_stack_free_extra_args(generator->execute_data TSRMLS_CC);
|
||||
|
||||
/* Some cleanups are only necessary if the generator was closued
|
||||
* before it could finish execution (reach a return statement). */
|
||||
|
@ -158,6 +132,10 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
|
|||
efree(op_array);
|
||||
}
|
||||
|
||||
if (generator->execute_data->prev_execute_data) {
|
||||
generator->execute_data->prev_execute_data->call = generator->execute_data->prev_nested_call;
|
||||
}
|
||||
|
||||
efree(generator->stack);
|
||||
generator->execute_data = NULL;
|
||||
}
|
||||
|
@ -171,18 +149,18 @@ static void zend_generator_dtor_storage(zend_object *object TSRMLS_DC) /* {{{ */
|
|||
zend_uint op_num, finally_op_num;
|
||||
int i;
|
||||
|
||||
if (!ex || !ex->op_array->has_finally_block) {
|
||||
if (!ex || !ex->func->op_array.has_finally_block) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* -1 required because we want the last run opcode, not the
|
||||
* next to-be-run one. */
|
||||
op_num = ex->opline - ex->op_array->opcodes - 1;
|
||||
op_num = ex->opline - ex->func->op_array.opcodes - 1;
|
||||
|
||||
/* Find next finally block */
|
||||
finally_op_num = 0;
|
||||
for (i = 0; i < ex->op_array->last_try_catch; i++) {
|
||||
zend_try_catch_element *try_catch = &ex->op_array->try_catch_array[i];
|
||||
for (i = 0; i < ex->func->op_array.last_try_catch; i++) {
|
||||
zend_try_catch_element *try_catch = &ex->func->op_array.try_catch_array[i];
|
||||
|
||||
if (op_num < try_catch->try_op) {
|
||||
break;
|
||||
|
@ -196,7 +174,7 @@ static void zend_generator_dtor_storage(zend_object *object TSRMLS_DC) /* {{{ */
|
|||
/* If a finally block was found we jump directly to it and
|
||||
* resume the generator. */
|
||||
if (finally_op_num) {
|
||||
ex->opline = &ex->op_array->opcodes[finally_op_num];
|
||||
ex->opline = &ex->func->op_array.opcodes[finally_op_num];
|
||||
ex->fast_ret = NULL;
|
||||
generator->flags |= ZEND_GENERATOR_FORCED_CLOSE;
|
||||
zend_generator_resume(generator TSRMLS_CC);
|
||||
|
@ -288,7 +266,7 @@ ZEND_API void zend_generator_create_zval(zend_op_array *op_array, zval *return_v
|
|||
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, return_value, VM_FRAME_TOP_FUNCTION TSRMLS_CC);
|
||||
execute_data = zend_create_generator_execute_data(op_array, return_value TSRMLS_CC);
|
||||
EG(active_symbol_table) = current_symbol_table;
|
||||
EG(current_execute_data) = current_execute_data;
|
||||
EG(opline_ptr) = opline_ptr;
|
||||
|
@ -300,8 +278,8 @@ ZEND_API void zend_generator_create_zval(zend_op_array *op_array, zval *return_v
|
|||
}
|
||||
|
||||
/* Save execution context in generator object. */
|
||||
execute_data->prev_execute_data->object = Z_OBJ_P(return_value);
|
||||
generator = (zend_generator *) Z_OBJ_P(return_value);
|
||||
execute_data->prev_execute_data = NULL;
|
||||
generator->execute_data = execute_data;
|
||||
generator->stack = EG(argument_stack);
|
||||
EG(argument_stack) = current_stack;
|
||||
|
@ -343,13 +321,14 @@ ZEND_API void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{
|
|||
zend_class_entry *original_scope = EG(scope);
|
||||
zend_class_entry *original_called_scope = EG(called_scope);
|
||||
zend_vm_stack original_stack = EG(argument_stack);
|
||||
zend_execute_data *prev_execute_data;
|
||||
|
||||
original_This = Z_OBJ(EG(This));
|
||||
|
||||
/* Set executor globals */
|
||||
EG(current_execute_data) = generator->execute_data;
|
||||
EG(opline_ptr) = &generator->execute_data->opline;
|
||||
EG(active_op_array) = generator->execute_data->op_array;
|
||||
EG(active_op_array) = &generator->execute_data->func->op_array;
|
||||
EG(active_symbol_table) = generator->execute_data->symbol_table;
|
||||
Z_OBJ(EG(This)) = generator->execute_data->object;
|
||||
EG(scope) = generator->execute_data->scope;
|
||||
|
@ -358,17 +337,32 @@ ZEND_API void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{
|
|||
|
||||
/* We want the backtrace to look as if the generator function was
|
||||
* called from whatever method we are current running (e.g. next()).
|
||||
* The first prev_execute_data contains an additional stack frame,
|
||||
* which makes the generator function show up in the backtrace and
|
||||
* makes the arguments available to func_get_args(). So we have to
|
||||
* set the prev_execute_data of that prev_execute_data :) */
|
||||
generator->execute_data->prev_execute_data->prev_execute_data = original_execute_data;
|
||||
* So we have to link generator call frame with caller call frames */
|
||||
|
||||
prev_execute_data = original_execute_data;
|
||||
if (prev_execute_data &&
|
||||
prev_execute_data->call &&
|
||||
(prev_execute_data->call->flags & ZEND_CALL_DONE)) {
|
||||
prev_execute_data->call->prev_execute_data = prev_execute_data;
|
||||
prev_execute_data = prev_execute_data->call;
|
||||
}
|
||||
generator->execute_data->prev_execute_data = prev_execute_data;
|
||||
if (prev_execute_data) {
|
||||
generator->execute_data->prev_nested_call = prev_execute_data->call;
|
||||
prev_execute_data->call = generator->execute_data;
|
||||
}
|
||||
|
||||
/* Resume execution */
|
||||
generator->flags |= ZEND_GENERATOR_CURRENTLY_RUNNING;
|
||||
zend_execute_ex(generator->execute_data TSRMLS_CC);
|
||||
generator->flags &= ~ZEND_GENERATOR_CURRENTLY_RUNNING;
|
||||
|
||||
/* Unlink generator call_frame from the caller */
|
||||
if (generator->execute_data && generator->execute_data->prev_execute_data) {
|
||||
generator->execute_data->prev_execute_data->call = generator->execute_data->prev_nested_call;
|
||||
generator->execute_data->prev_execute_data = NULL;
|
||||
}
|
||||
|
||||
/* Restore executor globals */
|
||||
EG(current_execute_data) = original_execute_data;
|
||||
EG(opline_ptr) = original_opline_ptr;
|
||||
|
@ -670,7 +664,7 @@ zend_object_iterator *zend_generator_get_iterator(zend_class_entry *ce, zval *ob
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (by_ref && !(generator->execute_data->op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
|
||||
if (by_ref && !(generator->execute_data->func->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
|
||||
zend_throw_exception(NULL, "You can only iterate a generator by-reference if it declared that it yields by-reference", 0 TSRMLS_CC);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -905,7 +905,7 @@ static void zend_std_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{
|
|||
|
||||
ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
|
||||
{
|
||||
zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->function_state.function;
|
||||
zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->call->func;
|
||||
zval method_name, method_args;
|
||||
zval method_result;
|
||||
zend_class_entry *ce = Z_OBJCE_P(getThis());
|
||||
|
@ -1123,7 +1123,7 @@ static union _zend_function *zend_std_get_method(zend_object **obj_ptr, zend_str
|
|||
|
||||
ZEND_API void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
|
||||
{
|
||||
zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->function_state.function;
|
||||
zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->call->func;
|
||||
zval method_name, method_args;
|
||||
zval method_result;
|
||||
zend_class_entry *ce = EG(scope);
|
||||
|
|
|
@ -70,9 +70,6 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz
|
|||
|
||||
op_array->T = 0;
|
||||
|
||||
op_array->nested_calls = 0;
|
||||
op_array->used_stack = 0;
|
||||
|
||||
op_array->function_name = NULL;
|
||||
op_array->filename = zend_get_compiled_filename(TSRMLS_C);
|
||||
op_array->doc_comment = NULL;
|
||||
|
@ -631,7 +628,7 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
|
|||
{
|
||||
zend_op *opline, *end;
|
||||
|
||||
if (op_array->type!=ZEND_USER_FUNCTION && op_array->type!=ZEND_EVAL_CODE) {
|
||||
if (!ZEND_USER_CODE(op_array->type)) {
|
||||
return 0;
|
||||
}
|
||||
if (op_array->has_finally_block) {
|
||||
|
|
1065
Zend/zend_vm_def.h
1065
Zend/zend_vm_def.h
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -33,10 +33,21 @@ ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *execute_data TSRMLS_DC)
|
|||
|
||||
ZEND_API void zend_{%EXECUTOR_NAME%}(zend_op_array *op_array, zval *return_value TSRMLS_DC)
|
||||
{
|
||||
zend_execute_data *execute_data;
|
||||
|
||||
if (EG(exception) != NULL) {
|
||||
return;
|
||||
}
|
||||
zend_{%EXECUTOR_NAME%}_ex(i_create_execute_data_from_op_array(op_array, return_value, EG(active_symbol_table) ? VM_FRAME_TOP_CODE : VM_FRAME_TOP_FUNCTION TSRMLS_CC) TSRMLS_CC);
|
||||
}
|
||||
|
||||
if (EG(current_execute_data) && EG(current_execute_data)->call) {
|
||||
execute_data = EG(current_execute_data)->call;
|
||||
} else {
|
||||
execute_data = zend_vm_stack_push_call_frame(
|
||||
(zend_function*)op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), NULL TSRMLS_CC);
|
||||
}
|
||||
EX(prev_execute_data) = EG(current_execute_data);
|
||||
i_init_execute_data(execute_data, op_array, return_value, EG(active_symbol_table) ? VM_FRAME_TOP_CODE : VM_FRAME_TOP_FUNCTION TSRMLS_CC);
|
||||
zend_{%EXECUTOR_NAME%}_ex(execute_data TSRMLS_CC);
|
||||
}
|
||||
|
||||
{%EXTERNAL_EXECUTOR%}
|
||||
|
|
|
@ -83,7 +83,7 @@ const char *zend_vm_opcodes_map[169] = {
|
|||
"ZEND_END_SILENCE",
|
||||
"ZEND_INIT_FCALL_BY_NAME",
|
||||
"ZEND_DO_FCALL",
|
||||
"ZEND_DO_FCALL_BY_NAME",
|
||||
"ZEND_INIT_FCALL",
|
||||
"ZEND_RETURN",
|
||||
"ZEND_RECV",
|
||||
"ZEND_RECV_INIT",
|
||||
|
|
|
@ -84,7 +84,7 @@ ZEND_API const char *zend_get_opcode_name(zend_uchar opcode);
|
|||
#define ZEND_END_SILENCE 58
|
||||
#define ZEND_INIT_FCALL_BY_NAME 59
|
||||
#define ZEND_DO_FCALL 60
|
||||
#define ZEND_DO_FCALL_BY_NAME 61
|
||||
#define ZEND_INIT_FCALL 61
|
||||
#define ZEND_RETURN 62
|
||||
#define ZEND_RECV 63
|
||||
#define ZEND_RECV_INIT 64
|
||||
|
|
|
@ -1958,7 +1958,6 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char *
|
|||
case ZEND_ASSIGN:
|
||||
case ZEND_ASSIGN_REF:
|
||||
case ZEND_DO_FCALL:
|
||||
case ZEND_DO_FCALL_BY_NAME:
|
||||
if (ZEND_RESULT_TYPE(opline) == IS_VAR) {
|
||||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
|
||||
ZEND_RESULT_TYPE(opline) |= EXT_TYPE_UNUSED;
|
||||
|
|
|
@ -108,8 +108,8 @@ static void optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_c
|
|||
end = opline + op_array->last;
|
||||
while (opline < end) {
|
||||
switch (opline->opcode) {
|
||||
case ZEND_DO_FCALL:
|
||||
LITERAL_INFO(opline->op1.constant, LITERAL_FUNC, 1, 1, 1);
|
||||
case ZEND_INIT_FCALL:
|
||||
LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 1);
|
||||
break;
|
||||
case ZEND_INIT_FCALL_BY_NAME:
|
||||
if (ZEND_OP2_TYPE(opline) == IS_CONST) {
|
||||
|
|
|
@ -12,9 +12,15 @@ static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx
|
|||
zend_op *opline = op_array->opcodes;
|
||||
zend_op *end = opline + op_array->last;
|
||||
int call = 0;
|
||||
void *checkpoint = zend_arena_checkpoint(ctx->arena);
|
||||
optimizer_call_info *call_stack = zend_arena_calloc(&ctx->arena, op_array->nested_calls + 1, sizeof(optimizer_call_info));
|
||||
void *checkpoint;
|
||||
optimizer_call_info *call_stack;
|
||||
|
||||
if (op_array->last < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkpoint = zend_arena_checkpoint(ctx->arena);
|
||||
call_stack = zend_arena_calloc(&ctx->arena, op_array->last / 2, sizeof(optimizer_call_info));
|
||||
while (opline < end) {
|
||||
switch (opline->opcode) {
|
||||
case ZEND_INIT_FCALL_BY_NAME:
|
||||
|
@ -31,23 +37,27 @@ static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx
|
|||
case ZEND_NEW:
|
||||
case ZEND_INIT_METHOD_CALL:
|
||||
case ZEND_INIT_STATIC_METHOD_CALL:
|
||||
case ZEND_INIT_FCALL:
|
||||
call_stack[call].opline = opline;
|
||||
call++;
|
||||
break;
|
||||
case ZEND_DO_FCALL_BY_NAME:
|
||||
case ZEND_DO_FCALL:
|
||||
call--;
|
||||
if (call_stack[call].func && call_stack[call].opline) {
|
||||
zend_op *fcall = call_stack[call].opline;
|
||||
|
||||
opline->opcode = ZEND_DO_FCALL;
|
||||
ZEND_OP1_TYPE(opline) = IS_CONST;
|
||||
opline->op1.constant = fcall->op2.constant + 1;
|
||||
Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]);
|
||||
literal_dtor(&ZEND_OP2_LITERAL(fcall));
|
||||
if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
|
||||
if (fcall->opcode == ZEND_INIT_FCALL_BY_NAME) {
|
||||
fcall->opcode = ZEND_INIT_FCALL;
|
||||
literal_dtor(&ZEND_OP2_LITERAL(fcall));
|
||||
fcall->op2.constant = fcall->op2.constant + 1;
|
||||
} else if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
|
||||
fcall->opcode = ZEND_INIT_FCALL;
|
||||
literal_dtor(&op_array->literals[fcall->op2.constant]);
|
||||
literal_dtor(&op_array->literals[fcall->op2.constant + 2]);
|
||||
fcall->op2.constant = fcall->op2.constant + 1;
|
||||
} else {
|
||||
ZEND_ASSERT(0);
|
||||
}
|
||||
MAKE_NOP(fcall);
|
||||
} else if (opline->extended_value == 0 &&
|
||||
call_stack[call].opline &&
|
||||
call_stack[call].opline->opcode == ZEND_INIT_FCALL_BY_NAME &&
|
||||
|
@ -55,12 +65,9 @@ static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx
|
|||
|
||||
zend_op *fcall = call_stack[call].opline;
|
||||
|
||||
opline->opcode = ZEND_DO_FCALL;
|
||||
ZEND_OP1_TYPE(opline) = IS_CONST;
|
||||
opline->op1.constant = fcall->op2.constant + 1;
|
||||
Z_CACHE_SLOT(op_array->literals[fcall->op2.constant + 1]) = Z_CACHE_SLOT(op_array->literals[fcall->op2.constant]);
|
||||
fcall->opcode = ZEND_INIT_FCALL;
|
||||
literal_dtor(&ZEND_OP2_LITERAL(fcall));
|
||||
MAKE_NOP(fcall);
|
||||
fcall->op2.constant = fcall->op2.constant + 1;
|
||||
}
|
||||
call_stack[call].func = NULL;
|
||||
call_stack[call].opline = NULL;
|
||||
|
@ -79,21 +86,21 @@ static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx
|
|||
}
|
||||
break;
|
||||
case ZEND_SEND_VAL:
|
||||
if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) {
|
||||
if (!(opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) && call_stack[call - 1].func) {
|
||||
if (ARG_MUST_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) {
|
||||
/* We won't convert it into_DO_FCALL to emit error at run-time */
|
||||
call_stack[call - 1].opline = NULL;
|
||||
} else {
|
||||
opline->extended_value = ZEND_DO_FCALL;
|
||||
opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZEND_SEND_VAR:
|
||||
if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) {
|
||||
if (!(opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) && call_stack[call - 1].func) {
|
||||
if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) {
|
||||
opline->opcode = ZEND_SEND_REF;
|
||||
}
|
||||
opline->extended_value = ZEND_DO_FCALL;
|
||||
opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND;
|
||||
}
|
||||
break;
|
||||
case ZEND_SEND_VAR_NO_REF:
|
||||
|
@ -104,12 +111,12 @@ static void optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx
|
|||
opline->extended_value |= ZEND_ARG_COMPILE_TIME_BOUND;
|
||||
} else {
|
||||
opline->opcode = ZEND_SEND_VAR;
|
||||
opline->extended_value = ZEND_DO_FCALL;
|
||||
opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZEND_SEND_REF:
|
||||
if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) {
|
||||
if (opline->extended_value != ZEND_ARG_COMPILE_TIME_BOUND && call_stack[call - 1].func) {
|
||||
/* We won't handle run-time pass by reference */
|
||||
call_stack[call - 1].opline = NULL;
|
||||
}
|
||||
|
|
|
@ -320,22 +320,25 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
|
|||
#endif
|
||||
break;
|
||||
|
||||
case ZEND_DO_FCALL:
|
||||
case ZEND_INIT_FCALL:
|
||||
/* define("name", scalar); */
|
||||
if (collect_constants &&
|
||||
opline->extended_value == 2 &&
|
||||
ZEND_OP1_TYPE(opline) == IS_CONST &&
|
||||
Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING &&
|
||||
Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("define")-1 &&
|
||||
zend_binary_strcasecmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)), "define", sizeof("define")-1) == 0 &&
|
||||
(opline-1)->opcode == ZEND_SEND_VAL &&
|
||||
ZEND_OP1_TYPE(opline-1) == IS_CONST &&
|
||||
Z_TYPE(ZEND_OP1_LITERAL(opline-1)) <= IS_STRING &&
|
||||
(opline-2)->opcode == ZEND_SEND_VAL &&
|
||||
ZEND_OP1_TYPE(opline-2) == IS_CONST &&
|
||||
Z_TYPE(ZEND_OP1_LITERAL(opline-2)) == IS_STRING) {
|
||||
zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline-2), &ZEND_OP1_LITERAL(opline-1));
|
||||
break;
|
||||
ZEND_OP2_TYPE(opline) == IS_CONST &&
|
||||
Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING &&
|
||||
Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("define")-1 &&
|
||||
zend_binary_strcasecmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), "define", sizeof("define")-1) == 0) {
|
||||
|
||||
if ((opline+1)->opcode == ZEND_SEND_VAL &&
|
||||
ZEND_OP1_TYPE(opline+1) == IS_CONST &&
|
||||
Z_TYPE(ZEND_OP1_LITERAL(opline+1)) == IS_STRING &&
|
||||
(opline+2)->opcode == ZEND_SEND_VAL &&
|
||||
ZEND_OP1_TYPE(opline+2) == IS_CONST &&
|
||||
Z_TYPE(ZEND_OP1_LITERAL(opline+2)) <= IS_STRING &&
|
||||
(opline+3)->opcode == ZEND_DO_FCALL) {
|
||||
|
||||
zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline+1), &ZEND_OP1_LITERAL(opline+2));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* don't colllect constants after any other function call */
|
||||
collect_constants = 0;
|
||||
|
@ -348,40 +351,42 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
|
|||
is_callable(x)
|
||||
extension_loaded(x)
|
||||
*/
|
||||
if (opline->extended_value == 1 && (opline - 1)->opcode == ZEND_SEND_VAL &&
|
||||
ZEND_OP1_TYPE(opline - 1) == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline - 1)) == IS_STRING &&
|
||||
ZEND_OP1_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
|
||||
if ((Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("function_exists")-1 &&
|
||||
!memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)),
|
||||
if ((opline + 1)->opcode == ZEND_SEND_VAL &&
|
||||
(opline + 2)->opcode == ZEND_DO_FCALL &&
|
||||
ZEND_OP1_TYPE(opline + 1) == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline + 1)) == IS_STRING &&
|
||||
ZEND_OP2_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
|
||||
if ((Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("function_exists")-1 &&
|
||||
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)),
|
||||
"function_exists", sizeof("function_exists")-1)) ||
|
||||
(Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("is_callable")-1 &&
|
||||
!memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)),
|
||||
(Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("is_callable")-1 &&
|
||||
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)),
|
||||
"is_callable", sizeof("is_callable")))) {
|
||||
zend_internal_function *func;
|
||||
char *lc_name = zend_str_tolower_dup(
|
||||
Z_STRVAL(ZEND_OP1_LITERAL(opline - 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline - 1)));
|
||||
Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)));
|
||||
|
||||
if ((func = zend_hash_str_find_ptr(EG(function_table), lc_name, Z_STRLEN(ZEND_OP1_LITERAL(opline - 1)))) != NULL &&
|
||||
if ((func = zend_hash_str_find_ptr(EG(function_table), lc_name, Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)))) != NULL &&
|
||||
func->type == ZEND_INTERNAL_FUNCTION &&
|
||||
func->module->type == MODULE_PERSISTENT) {
|
||||
zval t;
|
||||
ZVAL_BOOL(&t, 1);
|
||||
if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) {
|
||||
literal_dtor(&ZEND_OP1_LITERAL(opline - 1));
|
||||
MAKE_NOP((opline - 1));
|
||||
literal_dtor(&ZEND_OP1_LITERAL(opline));
|
||||
if (replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
|
||||
literal_dtor(&ZEND_OP2_LITERAL(opline));
|
||||
MAKE_NOP(opline);
|
||||
literal_dtor(&ZEND_OP1_LITERAL(opline + 1));
|
||||
MAKE_NOP(opline + 1);
|
||||
MAKE_NOP(opline + 2);
|
||||
}
|
||||
}
|
||||
efree(lc_name);
|
||||
} else if (Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("extension_loaded")-1 &&
|
||||
!memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)),
|
||||
} else if (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("extension_loaded")-1 &&
|
||||
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)),
|
||||
"extension_loaded", sizeof("extension_loaded")-1)) {
|
||||
zval t;
|
||||
char *lc_name = zend_str_tolower_dup(
|
||||
Z_STRVAL(ZEND_OP1_LITERAL(opline - 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline - 1)));
|
||||
Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)));
|
||||
zend_module_entry *m = zend_hash_str_find_ptr(&module_registry,
|
||||
lc_name, Z_STRLEN(ZEND_OP1_LITERAL(opline - 1)));
|
||||
lc_name, Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)));
|
||||
|
||||
efree(lc_name);
|
||||
if (!m) {
|
||||
|
@ -398,51 +403,55 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
|
|||
}
|
||||
}
|
||||
|
||||
if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) {
|
||||
literal_dtor(&ZEND_OP1_LITERAL(opline - 1));
|
||||
MAKE_NOP((opline - 1));
|
||||
literal_dtor(&ZEND_OP1_LITERAL(opline));
|
||||
if (replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
|
||||
literal_dtor(&ZEND_OP2_LITERAL(opline));
|
||||
MAKE_NOP(opline);
|
||||
literal_dtor(&ZEND_OP1_LITERAL(opline + 1));
|
||||
MAKE_NOP(opline + 1);
|
||||
MAKE_NOP(opline + 2);
|
||||
}
|
||||
} else if (Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("defined")-1 &&
|
||||
!memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)),
|
||||
} else if (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("defined")-1 &&
|
||||
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)),
|
||||
"defined", sizeof("defined")-1)) {
|
||||
zval t;
|
||||
|
||||
if (zend_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline - 1)), &t, 0 TSRMLS_CC)) {
|
||||
if (zend_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline + 1)), &t, 0 TSRMLS_CC)) {
|
||||
|
||||
ZVAL_BOOL(&t, 1);
|
||||
if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) {
|
||||
literal_dtor(&ZEND_OP1_LITERAL(opline - 1));
|
||||
MAKE_NOP((opline - 1));
|
||||
literal_dtor(&ZEND_OP1_LITERAL(opline));
|
||||
if (replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
|
||||
literal_dtor(&ZEND_OP2_LITERAL(opline));
|
||||
MAKE_NOP(opline);
|
||||
literal_dtor(&ZEND_OP1_LITERAL(opline + 1));
|
||||
MAKE_NOP(opline + 1);
|
||||
MAKE_NOP(opline + 2);
|
||||
}
|
||||
}
|
||||
} else if (Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("constant")-1 &&
|
||||
!memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)),
|
||||
} else if (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("constant")-1 &&
|
||||
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)),
|
||||
"constant", sizeof("constant")-1)) {
|
||||
zval t;
|
||||
|
||||
if (zend_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline - 1)), &t, 1 TSRMLS_CC)) {
|
||||
if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) {
|
||||
literal_dtor(&ZEND_OP1_LITERAL(opline - 1));
|
||||
MAKE_NOP((opline - 1));
|
||||
literal_dtor(&ZEND_OP1_LITERAL(opline));
|
||||
if (zend_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline + 1)), &t, 1 TSRMLS_CC)) {
|
||||
if (replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
|
||||
literal_dtor(&ZEND_OP2_LITERAL(opline));
|
||||
MAKE_NOP(opline);
|
||||
literal_dtor(&ZEND_OP1_LITERAL(opline + 1));
|
||||
MAKE_NOP(opline + 1);
|
||||
MAKE_NOP(opline + 2);
|
||||
}
|
||||
}
|
||||
} else if (Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("strlen")-1 &&
|
||||
!memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)),
|
||||
} else if (Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("strlen")-1 &&
|
||||
!memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)),
|
||||
"strlen", sizeof("strlen")-1)) {
|
||||
zval t;
|
||||
|
||||
ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline - 1)));
|
||||
if (replace_var_by_const(op_array, opline + 1, ZEND_RESULT(opline).var, &t TSRMLS_CC)) {
|
||||
literal_dtor(&ZEND_OP1_LITERAL(opline - 1));
|
||||
MAKE_NOP((opline - 1));
|
||||
literal_dtor(&ZEND_OP1_LITERAL(opline));
|
||||
ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)));
|
||||
if (replace_var_by_const(op_array, opline + 3, ZEND_RESULT(opline + 2).var, &t TSRMLS_CC)) {
|
||||
literal_dtor(&ZEND_OP2_LITERAL(opline));
|
||||
MAKE_NOP(opline);
|
||||
literal_dtor(&ZEND_OP1_LITERAL(opline + 1));
|
||||
MAKE_NOP(opline + 1);
|
||||
MAKE_NOP(opline + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -485,7 +494,7 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
|
|||
case ZEND_FE_RESET:
|
||||
case ZEND_FE_FETCH:
|
||||
case ZEND_NEW:
|
||||
case ZEND_DO_FCALL_BY_NAME:
|
||||
case ZEND_DO_FCALL:
|
||||
#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
|
||||
case ZEND_JMP_SET:
|
||||
#endif
|
||||
|
|
|
@ -178,12 +178,6 @@ static void update_op1_const(zend_op_array *op_array,
|
|||
zend_optimizer_add_literal(op_array, val TSRMLS_CC);
|
||||
STR_HASH_VAL(Z_STR(op_array->literals[opline->op1.constant+1]));
|
||||
break;
|
||||
case ZEND_DO_FCALL:
|
||||
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
|
||||
opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
|
||||
STR_HASH_VAL(Z_STR(ZEND_OP1_LITERAL(opline)));
|
||||
Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->last_cache_slot++;
|
||||
break;
|
||||
default:
|
||||
opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
|
||||
STR_HASH_VAL(Z_STR(ZEND_OP1_LITERAL(opline)));
|
||||
|
@ -204,6 +198,13 @@ static void update_op2_const(zend_op_array *op_array,
|
|||
{
|
||||
ZEND_OP2_TYPE(opline) = IS_CONST;
|
||||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
|
||||
if (opline->opcode == ZEND_INIT_FCALL) {
|
||||
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
|
||||
opline->op2.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
|
||||
STR_HASH_VAL(Z_STR(ZEND_OP2_LITERAL(opline)));
|
||||
Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->last_cache_slot++;
|
||||
return;
|
||||
}
|
||||
opline->op2.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
|
||||
if (Z_TYPE_P(val) == IS_STRING) {
|
||||
STR_HASH_VAL(Z_STR(ZEND_OP2_LITERAL(opline)));
|
||||
|
@ -340,9 +341,9 @@ static int replace_var_by_const(zend_op_array *op_array,
|
|||
if (opline->extended_value & ZEND_ARG_SEND_BY_REF) {
|
||||
return 0;
|
||||
}
|
||||
opline->extended_value = ZEND_DO_FCALL;
|
||||
opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND;
|
||||
} else {
|
||||
opline->extended_value = ZEND_DO_FCALL_BY_NAME;
|
||||
opline->extended_value = 0;
|
||||
}
|
||||
opline->opcode = ZEND_SEND_VAL;
|
||||
break;
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
#define INV_EX_COND_EX(op) ((op) == ZEND_JMPZ_EX ? ZEND_JMPNZ_EX : ZEND_JMPZ_EX)
|
||||
|
||||
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
|
||||
# define MAKE_NOP(opline) { opline->opcode = ZEND_NOP; memset(&opline->result,0,sizeof(opline->result)); memset(&opline->op1,0,sizeof(opline->op1)); memset(&opline->op2,0,sizeof(opline->op2)); opline->result_type=opline->op1_type=opline->op2_type=IS_UNUSED; opline->handler = zend_opcode_handlers[ZEND_NOP]; }
|
||||
# define MAKE_NOP(opline) { (opline)->opcode = ZEND_NOP; memset(&(opline)->result, 0, sizeof((opline)->result)); memset(&(opline)->op1, 0, sizeof((opline)->op1)); memset(&(opline)->op2, 0, sizeof((opline)->op2));(opline)->result_type=(opline)->op1_type=(opline)->op2_type=IS_UNUSED; (opline)->handler = zend_opcode_handlers[ZEND_NOP]; }
|
||||
# define RESULT_USED(op) (((op->result_type & IS_VAR) && !(op->result_type & EXT_TYPE_UNUSED)) || op->result_type == IS_TMP_VAR)
|
||||
# define RESULT_UNUSED(op) ((op->result_type & EXT_TYPE_UNUSED) != 0)
|
||||
# define SAME_VAR(op1, op2) ((((op1 ## _type & IS_VAR) && (op2 ## _type & IS_VAR)) || (op1 ## _type == IS_TMP_VAR && op2 ## _type == IS_TMP_VAR)) && op1.var == op2.var)
|
||||
|
|
|
@ -286,6 +286,10 @@ static int phar_file_action(phar_archive_data *phar, phar_entry_info *info, char
|
|||
EG(active_op_array) = new_op_array;
|
||||
|
||||
zend_try {
|
||||
if (EG(current_execute_data)) {
|
||||
EG(current_execute_data)->call = zend_vm_stack_push_call_frame(
|
||||
(zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EG(current_execute_data)->call TSRMLS_CC);
|
||||
}
|
||||
zend_execute(new_op_array, &result TSRMLS_CC);
|
||||
if (PHAR_G(cwd)) {
|
||||
efree(PHAR_G(cwd));
|
||||
|
|
|
@ -292,6 +292,10 @@ static int spl_autoload(zend_string *class_name, zend_string *lc_name, const cha
|
|||
}
|
||||
|
||||
ZVAL_UNDEF(&result);
|
||||
if (EG(current_execute_data)) {
|
||||
EG(current_execute_data)->call = zend_vm_stack_push_call_frame(
|
||||
(zend_function*)new_op_array, 0, 0, EG(called_scope), Z_OBJ(EG(This)), EG(current_execute_data)->call TSRMLS_CC);
|
||||
}
|
||||
zend_execute(new_op_array, &result TSRMLS_CC);
|
||||
|
||||
destroy_op_array(new_op_array TSRMLS_CC);
|
||||
|
|
|
@ -1102,7 +1102,6 @@ static int do_cli(int argc, char **argv TSRMLS_DC) /* {{{ */
|
|||
|
||||
memset(&execute_data, 0, sizeof(zend_execute_data));
|
||||
EG(current_execute_data) = &execute_data;
|
||||
EX(function_state).function = pce->constructor;
|
||||
zend_call_method_with_1_params(&ref, pce, &pce->constructor, "__construct", NULL, &arg);
|
||||
|
||||
if (EG(exception)) {
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
|
||||
static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
// TODO: fpm_php_trace_dump() has to be reimplemented ???
|
||||
#if 0
|
||||
int callers_limit = 20;
|
||||
pid_t pid = child->pid;
|
||||
struct timeval tv;
|
||||
|
@ -131,6 +133,7 @@ static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog TSRMLS_DC
|
|||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue