Refactoring: use call_frames instead of call_slots

This commit is contained in:
Dmitry Stogov 2014-06-24 02:17:16 +04:00
parent ba45650d63
commit 43477bc7a2
23 changed files with 1701 additions and 1762 deletions

View File

@ -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);
@ -80,19 +78,17 @@ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */
ZEND_API int _zend_get_parameters_array(int ht, int param_count, zval *argument_array TSRMLS_DC) /* {{{ */
{
zval *p;
int arg_count;
zval *param_ptr;
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) {
param_ptr = (p-arg_count);
if (Z_REFCOUNTED_P(param_ptr) &&
!Z_ISREF_P(param_ptr) &&
Z_REFCOUNT_P(param_ptr) > 1) {
@ -105,7 +101,7 @@ ZEND_API int _zend_get_parameters_array(int ht, int param_count, zval *argument_
ZVAL_COPY_VALUE(argument_array, param_ptr);
}
argument_array++;
arg_count--;
param_ptr++;
}
return SUCCESS;
@ -116,14 +112,13 @@ ZEND_API int _zend_get_parameters_array(int ht, int param_count, zval *argument_
/* 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;
@ -132,7 +127,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);
@ -142,22 +138,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;
@ -166,22 +160,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);
add_next_index_zval(argument_array, param_ptr);
param_ptr++;
}
return SUCCESS;
@ -841,7 +835,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,
@ -861,7 +855,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,
@ -884,7 +878,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,
@ -898,7 +892,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",
@ -922,7 +916,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;
@ -933,7 +927,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 */
@ -1004,7 +998,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);

View File

@ -396,8 +396,8 @@ ZEND_FUNCTION(func_num_args)
{
zend_execute_data *ex = EG(current_execute_data)->prev_execute_data;
if (ex && ex->function_state.arguments) {
RETURN_LONG(Z_LVAL_P(ex->function_state.arguments));
if (ex && ex->call) {
RETURN_LONG(ex->call->num_args);
} else {
zend_error(E_WARNING, "func_num_args(): Called from the global scope - no function context");
RETURN_LONG(-1);
@ -409,7 +409,6 @@ 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;
zval *arg;
long requested_offset;
@ -424,20 +423,19 @@ ZEND_FUNCTION(func_get_arg)
RETURN_FALSE;
}
if (!ex || !ex->function_state.arguments) {
if (!ex || !ex->call) {
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->call->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);
arg = ZEND_CALL_ARG(ex->call, requested_offset + 1);
RETURN_ZVAL_FAST(arg);
}
/* }}} */
@ -451,19 +449,18 @@ ZEND_FUNCTION(func_get_args)
int i;
zend_execute_data *ex = EG(current_execute_data)->prev_execute_data;
if (!ex || !ex->function_state.arguments) {
if (!ex || !ex->call) {
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->call->num_args;
array_init_size(return_value, arg_count);
if (arg_count) {
Bucket *q;
p -= arg_count;
p = ZEND_CALL_ARG(ex->call, 1);
zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
q = Z_ARRVAL_P(return_value)->arData;
for (i=0; i<arg_count; i++) {
@ -1957,22 +1954,24 @@ 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_call_frame *call, zval *arg_array TSRMLS_DC)
{
zval *p = curpos;
zval *p;
zval *arg;
int arg_count = Z_LVAL_P(p);
int arg_count = call->num_args;
array_init_size(arg_array, arg_count);
p -= arg_count;
if (arg_count > 0) {
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);
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);
}
}
}
}
@ -1996,6 +1995,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;
@ -2029,7 +2029,6 @@ ZEND_FUNCTION(debug_print_backtrace)
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;
}
@ -2044,41 +2043,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 = (zend_function*)(ptr->op_array);
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 (!ptr->opline || ptr->opline->opcode == ZEND_DO_FCALL) {
if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0) {
debug_backtrace_get_args(ptr->call, &arg_array TSRMLS_CC);
}
}
} else {
@ -2137,8 +2142,9 @@ 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 &&
prev->call->func->common.type != ZEND_USER_FUNCTION) {
prev = NULL;
break;
}
@ -2166,6 +2172,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;
@ -2198,7 +2205,6 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
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;
}
@ -2216,10 +2222,11 @@ 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 &&
prev->call->func->common.type != ZEND_USER_FUNCTION &&
!(prev->call->func->common.type == ZEND_INTERNAL_FUNCTION &&
(prev->call->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER))) {
break;
}
if (prev->op_array) {
@ -2235,28 +2242,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 = (zend_function*)(ptr->op_array);
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 +2283,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) {
(!ptr->opline || ptr->opline->opcode == ZEND_DO_FCALL)) {
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);
}
}

View File

@ -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());

View File

@ -182,7 +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;
@ -1949,6 +1948,7 @@ 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_function *function;
zend_string *lcname;
char *is_compound = memchr(Z_STRVAL(function_name->u.constant), '\\', Z_STRLEN(function_name->u.constant));
@ -1977,10 +1977,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;
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 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;
}
CG(context).used_stack += ZEND_CALL_FRAME_SLOT;
zend_do_extended_fcall_begin(TSRMLS_C);
return 0;
}
@ -2017,12 +2021,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;
@ -2034,9 +2036,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;
}
CG(context).used_stack += ZEND_CALL_FRAME_SLOT;
zend_do_extended_fcall_begin(TSRMLS_C);
}
/* }}} */
@ -2063,14 +2063,12 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML
/* In run-time PHP will check for function with full name and
internal function with short name */
opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
opline->result.num = CG(context).nested_calls;
SET_UNUSED(opline->op1);
opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_ns_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC);
GET_CACHE_SLOT(opline->op2.constant);
} else {
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
opline->result.num = CG(context).nested_calls;
SET_UNUSED(opline->op1);
if (function_name->op_type == IS_CONST) {
opline->op2_type = IS_CONST;
@ -2082,9 +2080,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;
}
CG(context).used_stack += ZEND_CALL_FRAME_SLOT;
zend_do_extended_fcall_begin(TSRMLS_C);
}
/* }}} */
@ -2508,7 +2504,6 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na
opline->extended_value = class_node.EA ;
}
opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
opline->result.num = CG(context).nested_calls;
if (class_node.op_type == IS_CONST) {
opline->op1_type = IS_CONST;
opline->op1.constant =
@ -2530,9 +2525,7 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na
}
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;
}
CG(context).used_stack += ZEND_CALL_FRAME_SLOT;
zend_do_extended_fcall_begin(TSRMLS_C);
return 1; /* Dynamic */
}
@ -2551,25 +2544,9 @@ 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;
/* 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->opcode = ZEND_DO_FCALL;
SET_UNUSED(opline->op1);
SET_UNUSED(opline->op2);
}
opline->result.var = get_temporary_variable(CG(active_op_array));
@ -2577,10 +2554,10 @@ 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;
if (CG(context).used_stack > CG(active_op_array)->used_stack) {
CG(active_op_array)->used_stack = CG(context).used_stack;
}
CG(context).used_stack -= fcall->arg_num;
CG(context).used_stack -= ZEND_CALL_FRAME_SLOT + fcall->arg_num;
zend_stack_del_top(&CG(function_call_stack));
}
/* }}} */
@ -2682,9 +2659,7 @@ 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;
@ -2692,9 +2667,7 @@ void zend_do_pass_param(znode *param, zend_uchar op TSRMLS_DC) /* {{{ */
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;
}
CG(context).used_stack++;
}
/* }}} */
@ -2705,25 +2678,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 +5573,13 @@ 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;
}
CG(context).used_stack += ZEND_CALL_FRAME_SLOT;
}
/* }}} */
@ -5819,6 +5770,13 @@ 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;
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,27 +5788,21 @@ 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;
if (CG(context).used_stack + ZEND_CALL_FRAME_SLOT + 1 > CG(active_op_array)->used_stack) {
CG(active_op_array)->used_stack = CG(context).used_stack + ZEND_CALL_FRAME_SLOT + 1;
}
}
/* }}} */

View File

@ -59,7 +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;
@ -266,7 +265,6 @@ struct _zend_op_array {
zend_uint T;
zend_uint nested_calls;
zend_uint used_stack;
zend_brk_cont_element *brk_cont_array;
@ -336,12 +334,6 @@ 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 arg_num;
@ -361,14 +353,26 @@ 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 struct _zend_call_frame zend_call_frame;
struct _zend_call_frame {
zend_function *func;
zend_uint num_args;
zend_uint flags;
zend_class_entry *called_scope;
zend_object *object;
zend_call_frame *prev;
};
#define ZEND_CALL_CTOR (1 << 0)
#define ZEND_CALL_CTOR_RESULT_USED (1 << 1)
#define ZEND_CALL_DONE (1 << 2)
#define ZEND_CALL_FRAME_SLOT \
((ZEND_MM_ALIGNED_SIZE(sizeof(zend_call_frame)) + 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)))
typedef enum _vm_frame_kind {
VM_FRAME_NESTED_FUNCTION, /* stackless VM call to function */
@ -380,7 +384,7 @@ 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_call_frame *call; /* current call */
zend_object *object; /* current $this */
zend_class_entry *scope; /* function scope (self) */
zend_class_entry *called_scope; /* function called scope (static) */
@ -393,8 +397,6 @@ struct _zend_execute_data {
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;
};
#define EX(element) execute_data.element
@ -877,7 +879,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;

View File

@ -1468,13 +1468,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
);
}
}
@ -1536,12 +1536,10 @@ void zend_free_compiled_variables(zend_execute_data *execute_data TSRMLS_DC) /*
* | VAR[op_array->last_var] |
* | ... |
* | VAR[op_array->last_var+op_array->T-1] |
* zend_vm_stack_frame_base -> +----------------------------------------+
* EX(call_slot) -> | CALL_SLOT |
* +----------------------------------------+
* EX(call_slots) -> | CALL_SLOT[0] |
* | ... |
* | CALL_SLOT[op_array->nested_calls-1] |
* +----------------------------------------+
* zend_vm_stack_frame_base -> | ARGUMENTS STACK [0] |
* | ARGUMENTS STACK [0] |
* | ... |
* zend_vm_stack_top --------> | ... |
* | ... |
@ -1566,9 +1564,8 @@ static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array
*/
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;
size_t total_size = execute_data_size + vars_size + stack_size;
/*
* Normally the execute_data is allocated on the VM stack (because it does
@ -1585,7 +1582,7 @@ static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array
* 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);
size_t args_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval)) * (ZEND_CALL_FRAME_SLOT + args_count);
total_size += args_size + execute_data_size;
@ -1596,11 +1593,15 @@ static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array
/* 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)));
EX(prev_execute_data)->call = (zend_call_frame*)(((char*)EX(prev_execute_data)) + sizeof(zend_execute_data));
EX(prev_execute_data)->call->func = (zend_function*)op_array;
EX(prev_execute_data)->call->num_args = args_count;
EX(prev_execute_data)->call->flags = ZEND_CALL_DONE;
EX(prev_execute_data)->call->called_scope = NULL;
EX(prev_execute_data)->call->object = NULL;
EX(prev_execute_data)->call->prev = NULL;
/* 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);
@ -1619,13 +1620,10 @@ static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array
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);
@ -1674,24 +1672,28 @@ ZEND_API zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array
}
/* }}} */
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_call_frame *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_call_frame *zend_vm_stack_copy_call_frame(zend_call_frame *call TSRMLS_DC) /* {{{ */
{
zend_uint count;
zend_call_frame *new_call;
zend_vm_stack p = EG(argument_stack);
zend_vm_stack_extend(count + 1 TSRMLS_CC);
zend_vm_stack_extend(ZEND_CALL_FRAME_SLOT + call->num_args TSRMLS_CC);
EG(argument_stack)->top += count;
ZVAL_LONG(EG(argument_stack)->top, count);
new_call = (zend_call_frame*)ZEND_VM_STACK_ELEMETS(EG(argument_stack));
*new_call = *call;
EG(argument_stack)->top += ZEND_CALL_FRAME_SLOT + call->num_args;
count = call->num_args;
while (count-- > 0) {
zval *data = --p->top;
ZVAL_COPY_VALUE(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + count, data);
ZVAL_COPY_VALUE(ZEND_CALL_ARG(new_call, count), data);
if (UNEXPECTED(p->top == ZEND_VM_STACK_ELEMETS(p))) {
zend_vm_stack r = p;
@ -1701,18 +1703,16 @@ static zval *zend_vm_stack_push_args_with_copy(int count TSRMLS_DC) /* {{{ */
efree(r);
}
}
return EG(argument_stack)->top++;
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_adjust_call_frame(zend_call_frame **call TSRMLS_DC) /* {{{ */
{
if (UNEXPECTED(EG(argument_stack)->top - ZEND_VM_STACK_ELEMETS(EG(argument_stack)) < count)
if (UNEXPECTED(EG(argument_stack)->top - ZEND_VM_STACK_ELEMETS(EG(argument_stack)) < ZEND_CALL_FRAME_SLOT + (*call)->num_args)
|| UNEXPECTED(EG(argument_stack)->top == EG(argument_stack)->end)) {
return zend_vm_stack_push_args_with_copy(count TSRMLS_CC);
*call = zend_vm_stack_copy_call_frame(*call TSRMLS_CC);
}
ZVAL_LONG(EG(argument_stack)->top, count);
return EG(argument_stack)->top++;
}
/* }}} */

View File

@ -221,6 +221,19 @@ static zend_always_inline zval *zend_vm_stack_pop(TSRMLS_D)
return --EG(argument_stack)->top;
}
static zend_always_inline zend_call_frame *zend_vm_stack_push_call_frame(zend_function *func, zend_uint num_args, zend_uint flags, zend_class_entry *called_scope, zend_object *object, zend_call_frame *prev TSRMLS_DC)
{
zend_call_frame * call = (zend_call_frame*)EG(argument_stack)->top;
call->func = func;
call->num_args = num_args;
call->flags = flags;
call->called_scope = called_scope;
call->object = object;
call->prev = prev;
EG(argument_stack)->top += ZEND_CALL_FRAME_SLOT;
return call;
}
static zend_always_inline void *zend_vm_stack_alloc(size_t size TSRMLS_DC)
{
zval *ret;
@ -234,8 +247,7 @@ static zend_always_inline void *zend_vm_stack_alloc(size_t size TSRMLS_DC)
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);
return EX_VAR_NUM_2(ex, ex->op_array->last_var + ex->op_array->T);
}
static zend_always_inline void zend_vm_stack_free(void *ptr TSRMLS_DC)
@ -250,12 +262,13 @@ static zend_always_inline void zend_vm_stack_free(void *ptr TSRMLS_DC)
}
}
static zend_always_inline void zend_vm_stack_clear_multiple(int nested TSRMLS_DC)
static zend_always_inline void zend_vm_stack_free_call_frame(zend_call_frame *call, int nested TSRMLS_DC)
{
zval *p = EG(argument_stack)->top - 1;
zend_uint num_args = call->num_args;
if (EXPECTED(Z_LVAL_P(p) > 0)) {
zval *end = p - Z_LVAL_P(p);
if (num_args > 0) {
zval *p = ZEND_CALL_ARG(call, num_args + 1);
zval *end = p - num_args;
do {
p--;
@ -263,27 +276,25 @@ static zend_always_inline void zend_vm_stack_clear_multiple(int nested TSRMLS_DC
} while (p != end);
}
if (nested) {
EG(argument_stack)->top = p;
EG(argument_stack)->top = (zval*)call;
} else {
zend_vm_stack_free(p TSRMLS_CC);
zend_vm_stack_free((zval*)call TSRMLS_CC);
}
}
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)

View File

@ -393,17 +393,24 @@ 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 = (zend_function*)EG(current_execute_data)->op_array;
}
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 = (zend_function*)EG(current_execute_data)->op_array;
}
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);
@ -719,7 +734,10 @@ 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;
ZEND_VM_STACK_GROW_IF_NEEDED(ZEND_CALL_FRAME_SLOT + fci->param_count);
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 +747,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 +782,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)) {
!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) {
if (i || UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (EG(argument_stack)->top))) {
/* 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);
zend_vm_stack_free_call_frame(EX(call), 0 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;
}
@ -797,7 +813,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
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;
ZVAL_DUP(param, Z_REFVAL(fci->params[i]));
} else {
@ -807,13 +823,10 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
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);
EG(scope) = calling_scope;
EG(called_scope) = called_scope;
if (!fci->object ||
(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) {
(func->common.fn_flags & ZEND_ACC_STATIC)) {
Z_OBJ(EG(This)) = NULL;
} else {
Z_OBJ(EG(This)) = fci->object;
@ -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,15 +861,15 @@ 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);
}
@ -880,22 +893,22 @@ 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);
zend_vm_stack_free_call_frame(EX(call), 0 TSRMLS_CC);
if (Z_OBJ(EG(This))) {
zval_ptr_dtor(&EG(This));

View File

@ -87,11 +87,11 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato
/* 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;
}
}
/* }}} */
@ -133,11 +133,10 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
* 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;
if (prev_execute_data->call) {
int arguments_count = prev_execute_data->call->num_args;
zval *arguments_start = ZEND_CALL_ARG(prev_execute_data->call, 1);
int i;
for (i = 0; i < arguments_count; ++i) {

View File

@ -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);

View File

@ -70,7 +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;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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",

View File

@ -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

View File

@ -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;

View File

@ -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) {

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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)) {

View File

@ -74,9 +74,10 @@ static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog TSRMLS_DC
fprintf(slowlog, "[0x%" PTR_FMT "lx] ", execute_data);
if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, function_state.function), &l)) {
return -1;
}
// TODO: fpm_php_trace_dump() has be reimplemented ???
//??? if (0 > fpm_trace_get_long(execute_data + offsetof(zend_execute_data, function_state.function), &l)) {
//??? return -1;
//??? }
function = l;