Backported call frame initialization improvement

This commit is contained in:
Dmitry Stogov 2019-04-12 02:35:42 +03:00
parent 88a2268d6b
commit 55cc280429
10 changed files with 423 additions and 366 deletions

View File

@ -482,13 +482,6 @@ union _zend_function {
zend_internal_function internal_function;
};
typedef enum _zend_call_kind {
ZEND_CALL_NESTED_FUNCTION, /* stackless VM call to function */
ZEND_CALL_NESTED_CODE, /* stackless VM call to include/require/eval */
ZEND_CALL_TOP_FUNCTION, /* direct VM call to function from external C code */
ZEND_CALL_TOP_CODE /* direct VM call to "main" code from external C code */
} zend_call_kind;
struct _zend_execute_data {
const zend_op *opline; /* executed opline */
zend_execute_data *call; /* current call */
@ -502,24 +495,30 @@ struct _zend_execute_data {
#endif
};
#define ZEND_CALL_FUNCTION (0 << 0)
#define ZEND_CALL_CODE (1 << 0)
#define ZEND_CALL_NESTED (0 << 1)
#define ZEND_CALL_TOP (1 << 1)
#define ZEND_CALL_FREE_EXTRA_ARGS (1 << 2)
#define ZEND_CALL_HAS_SYMBOL_TABLE (1 << 4)
#define ZEND_CALL_CLOSURE (1 << 5)
#define ZEND_CALL_RELEASE_THIS (1 << 6)
#define ZEND_CALL_ALLOCATED (1 << 7)
#define ZEND_CALL_GENERATOR (1 << 8)
#define ZEND_CALL_DYNAMIC (1 << 9)
#define ZEND_CALL_FAKE_CLOSURE (1 << 10)
#define ZEND_CALL_SEND_ARG_BY_REF (1 << 11)
#define ZEND_CALL_HAS_THIS IS_OBJECT_EX
#define ZEND_CALL_INFO_SHIFT 16
/* Top 16 bits of Z_TYPE_INFO(EX(This)) are used as call_info flags */
#define ZEND_CALL_FUNCTION (0 << 16)
#define ZEND_CALL_CODE (1 << 16)
#define ZEND_CALL_NESTED (0 << 17)
#define ZEND_CALL_TOP (1 << 17)
#define ZEND_CALL_ALLOCATED (1 << 18)
#define ZEND_CALL_FREE_EXTRA_ARGS (1 << 19)
#define ZEND_CALL_HAS_SYMBOL_TABLE (1 << 20)
#define ZEND_CALL_RELEASE_THIS (1 << 21)
#define ZEND_CALL_CLOSURE (1 << 22)
#define ZEND_CALL_FAKE_CLOSURE (1 << 23)
#define ZEND_CALL_GENERATOR (1 << 24)
#define ZEND_CALL_DYNAMIC (1 << 25)
#define ZEND_CALL_SEND_ARG_BY_REF (1 << 31)
#define ZEND_CALL_NESTED_FUNCTION (ZEND_CALL_FUNCTION | ZEND_CALL_NESTED)
#define ZEND_CALL_NESTED_CODE (ZEND_CALL_CODE | ZEND_CALL_NESTED)
#define ZEND_CALL_TOP_FUNCTION (ZEND_CALL_TOP | ZEND_CALL_FUNCTION)
#define ZEND_CALL_TOP_CODE (ZEND_CALL_CODE | ZEND_CALL_TOP)
#define ZEND_CALL_INFO(call) \
(Z_TYPE_INFO((call)->This) >> ZEND_CALL_INFO_SHIFT)
Z_TYPE_INFO((call)->This)
#define ZEND_CALL_KIND_EX(call_info) \
(call_info & (ZEND_CALL_CODE | ZEND_CALL_TOP))
@ -527,16 +526,12 @@ struct _zend_execute_data {
#define ZEND_CALL_KIND(call) \
ZEND_CALL_KIND_EX(ZEND_CALL_INFO(call))
#define ZEND_SET_CALL_INFO(call, object, info) do { \
Z_TYPE_INFO((call)->This) = ((object) ? IS_OBJECT_EX : IS_UNDEF) | ((info) << ZEND_CALL_INFO_SHIFT); \
} while (0)
#define ZEND_ADD_CALL_FLAG_EX(call_info, flag) do { \
call_info |= ((flag) << ZEND_CALL_INFO_SHIFT); \
call_info |= (flag); \
} while (0)
#define ZEND_DEL_CALL_FLAG_EX(call_info, flag) do { \
call_info &= ~((flag) << ZEND_CALL_INFO_SHIFT); \
call_info &= ~(flag); \
} while (0)
#define ZEND_ADD_CALL_FLAG(call, flag) do { \

View File

@ -3855,13 +3855,14 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_s
}
return zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC,
fbc, num_args, called_scope, NULL);
fbc, num_args, called_scope);
}
/* }}} */
static zend_never_inline zend_execute_data *zend_init_dynamic_call_object(zval *function, uint32_t num_args) /* {{{ */
{
zend_function *fbc;
void *object_or_called_scope;
zend_class_entry *called_scope;
zend_object *object;
uint32_t call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC;
@ -3869,6 +3870,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_object(zval *
if (EXPECTED(Z_OBJ_HANDLER_P(function, get_closure)) &&
EXPECTED(Z_OBJ_HANDLER_P(function, get_closure)(function, &called_scope, &fbc, &object) == SUCCESS)) {
object_or_called_scope = called_scope;
if (fbc->common.fn_flags & ZEND_ACC_CLOSURE) {
/* Delay closure destruction until its invocation */
GC_ADDREF(ZEND_CLOSURE_OBJECT(fbc));
@ -3876,9 +3878,14 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_object(zval *
if (fbc->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
call_info |= ZEND_CALL_FAKE_CLOSURE;
}
if (object) {
call_info |= ZEND_CALL_HAS_THIS;
object_or_called_scope = object;
}
} else if (object) {
call_info |= ZEND_CALL_RELEASE_THIS;
call_info |= ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS;
GC_ADDREF(object); /* For $this pointer */
object_or_called_scope = object;
}
} else {
zend_throw_error(NULL, "Function name must be a string");
@ -3890,15 +3897,14 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_object(zval *
}
return zend_vm_stack_push_call_frame(call_info,
fbc, num_args, called_scope, object);
fbc, num_args, object_or_called_scope);
}
/* }}} */
static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_array *function, uint32_t num_args) /* {{{ */
{
zend_function *fbc;
zend_class_entry *called_scope;
zend_object *object;
void *object_or_called_scope;
uint32_t call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC;
if (zend_hash_num_elements(function) == 2) {
@ -3925,8 +3931,8 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_ar
}
if (Z_TYPE_P(obj) == IS_STRING) {
object = NULL;
called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
zend_class_entry *called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
if (UNEXPECTED(called_scope == NULL)) {
return NULL;
}
@ -3948,9 +3954,9 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_ar
return NULL;
}
}
object_or_called_scope = called_scope;
} else {
called_scope = Z_OBJCE_P(obj);
object = Z_OBJ_P(obj);
zend_object *object = Z_OBJ_P(obj);
fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL);
if (UNEXPECTED(fbc == NULL)) {
@ -3961,10 +3967,11 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_ar
}
if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
object = NULL;
object_or_called_scope = object->ce;
} else {
call_info |= ZEND_CALL_RELEASE_THIS;
call_info |= ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS;
GC_ADDREF(object); /* For $this pointer */
object_or_called_scope = object;
}
}
} else {
@ -3977,7 +3984,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_ar
}
return zend_vm_stack_push_call_frame(call_info,
fbc, num_args, called_scope, object);
fbc, num_args, object_or_called_scope);
}
/* }}} */

View File

@ -206,20 +206,15 @@ ZEND_API void zend_vm_stack_init_ex(size_t page_size);
ZEND_API void zend_vm_stack_destroy(void);
ZEND_API void* zend_vm_stack_extend(size_t size);
static zend_always_inline void zend_vm_init_call_frame(zend_execute_data *call, uint32_t call_info, zend_function *func, uint32_t num_args, zend_class_entry *called_scope, zend_object *object)
static zend_always_inline void zend_vm_init_call_frame(zend_execute_data *call, uint32_t call_info, zend_function *func, uint32_t num_args, void *object_or_called_scope)
{
call->func = func;
if (object) {
Z_OBJ(call->This) = object;
ZEND_SET_CALL_INFO(call, 1, call_info);
} else {
Z_CE(call->This) = called_scope;
ZEND_SET_CALL_INFO(call, 0, call_info);
}
Z_PTR(call->This) = object_or_called_scope;
ZEND_CALL_INFO(call) = call_info;
ZEND_CALL_NUM_ARGS(call) = num_args;
}
static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame_ex(uint32_t used_stack, uint32_t call_info, zend_function *func, uint32_t num_args, zend_class_entry *called_scope, zend_object *object)
static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame_ex(uint32_t used_stack, uint32_t call_info, zend_function *func, uint32_t num_args, void *object_or_called_scope)
{
zend_execute_data *call = (zend_execute_data*)EG(vm_stack_top);
@ -228,11 +223,11 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame_ex(ui
if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
call = (zend_execute_data*)zend_vm_stack_extend(used_stack);
ZEND_ASSERT_VM_STACK_GLOBAL;
zend_vm_init_call_frame(call, call_info | ZEND_CALL_ALLOCATED, func, num_args, called_scope, object);
zend_vm_init_call_frame(call, call_info | ZEND_CALL_ALLOCATED, func, num_args, object_or_called_scope);
return call;
} else {
EG(vm_stack_top) = (zval*)((char*)call + used_stack);
zend_vm_init_call_frame(call, call_info, func, num_args, called_scope, object);
zend_vm_init_call_frame(call, call_info, func, num_args, object_or_called_scope);
return call;
}
}
@ -247,12 +242,12 @@ static zend_always_inline uint32_t zend_vm_calc_used_stack(uint32_t num_args, ze
return used_stack * sizeof(zval);
}
static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(uint32_t call_info, zend_function *func, uint32_t num_args, zend_class_entry *called_scope, zend_object *object)
static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(uint32_t call_info, zend_function *func, uint32_t num_args, void *object_or_called_scope)
{
uint32_t used_stack = zend_vm_calc_used_stack(num_args, func);
return zend_vm_stack_push_call_frame_ex(used_stack, call_info,
func, num_args, called_scope, object);
func, num_args, object_or_called_scope);
}
static zend_always_inline void zend_vm_stack_free_extra_args_ex(uint32_t call_info, zend_execute_data *call)

View File

@ -655,6 +655,8 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
zend_execute_data *call, dummy_execute_data;
zend_fcall_info_cache fci_cache_local;
zend_function *func;
uint32_t call_info;
void *object_or_called_scope;
ZVAL_UNDEF(fci->retval);
@ -727,11 +729,18 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
}
func = fci_cache->function_handler;
fci->object = (func->common.fn_flags & ZEND_ACC_STATIC) ?
NULL : fci_cache->object;
if ((func->common.fn_flags & ZEND_ACC_STATIC) || !fci_cache->object) {
fci->object = NULL;
object_or_called_scope = fci_cache->called_scope;
call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_DYNAMIC;
} else {
fci->object = fci_cache->object;
object_or_called_scope = fci->object;
call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_HAS_THIS;
}
call = zend_vm_stack_push_call_frame(ZEND_CALL_TOP_FUNCTION | ZEND_CALL_DYNAMIC,
func, fci->param_count, fci_cache->called_scope, fci->object);
call = zend_vm_stack_push_call_frame(call_info,
func, fci->param_count, object_or_called_scope);
if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_DEPRECATED)) {
zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated",

View File

@ -40,10 +40,7 @@ ZEND_API void zend_generator_restore_call_stack(zend_generator *generator) /* {{
(ZEND_CALL_INFO(call) & ~ZEND_CALL_ALLOCATED),
call->func,
ZEND_CALL_NUM_ARGS(call),
(Z_TYPE(call->This) == IS_UNDEF) ?
(zend_class_entry*)Z_OBJ(call->This) : NULL,
(Z_TYPE(call->This) != IS_UNDEF) ?
Z_OBJ(call->This) : NULL);
Z_PTR(call->This));
memcpy(((zval*)new_call) + ZEND_CALL_FRAME_SLOT, ((zval*)call) + ZEND_CALL_FRAME_SLOT, ZEND_CALL_NUM_ARGS(call) * sizeof(zval));
new_call->prev_execute_data = prev_call;
prev_call = new_call;

View File

@ -201,7 +201,6 @@ struct _zval_struct {
zend_uchar type, /* active type */
zend_uchar type_flags,
union {
uint16_t call_info; /* call info for EX(This) */
uint16_t extra; /* not further specified */
} u)
} v;

View File

@ -3427,27 +3427,29 @@ ZEND_VM_HOT_OBJ_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|THIS|CV,
FREE_OP2();
}
call_info = ZEND_CALL_NESTED_FUNCTION;
call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_HAS_THIS;
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0)) {
obj = NULL;
FREE_OP1();
if ((OP1_TYPE & (IS_VAR|IS_TMP_VAR)) && UNEXPECTED(EG(exception))) {
HANDLE_EXCEPTION();
}
/* call static method */
obj = (zend_object*)called_scope;
call_info = ZEND_CALL_NESTED_FUNCTION;
} else if (OP1_TYPE & (IS_VAR|IS_TMP_VAR|IS_CV)) {
/* CV may be changed indirectly (e.g. when it's a reference) */
call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_RELEASE_THIS;
if (OP1_TYPE == IS_CV) {
GC_ADDREF(obj); /* For $this pointer */
} else if (free_op1 != object) {
GC_ADDREF(obj); /* For $this pointer */
FREE_OP1();
}
/* CV may be changed indirectly (e.g. when it's a reference) */
call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS;
}
call = zend_vm_stack_push_call_frame(call_info,
fbc, opline->extended_value, called_scope, obj);
fbc, opline->extended_value, obj);
call->prev_execute_data = EX(call);
EX(call) = call;
@ -3459,7 +3461,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR,
USE_OPLINE
zval *function_name;
zend_class_entry *ce;
zend_object *object;
uint32_t call_info;
zend_function *fbc;
zend_execute_data *call;
@ -3560,33 +3562,34 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR,
}
}
object = NULL;
if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
if (Z_TYPE(EX(This)) == IS_OBJECT && instanceof_function(Z_OBJCE(EX(This)), ce)) {
object = Z_OBJ(EX(This));
ce = object->ce;
ce = (zend_class_entry*)Z_OBJ(EX(This));
call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_HAS_THIS;
} else {
zend_non_static_method_call(fbc);
if (UNEXPECTED(EG(exception) != NULL)) {
HANDLE_EXCEPTION();
}
ZEND_VM_C_GOTO(check_parent_and_self);
}
}
if (OP1_TYPE == IS_UNUSED) {
} else {
ZEND_VM_C_LABEL(check_parent_and_self):
/* previous opcode is ZEND_FETCH_CLASS */
if ((opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT ||
(opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) {
if (OP1_TYPE == IS_UNUSED
&& ((opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT ||
(opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF)) {
if (Z_TYPE(EX(This)) == IS_OBJECT) {
ce = Z_OBJCE(EX(This));
} else {
ce = Z_CE(EX(This));
}
}
call_info = ZEND_CALL_NESTED_FUNCTION;
}
call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
fbc, opline->extended_value, ce, object);
call = zend_vm_stack_push_call_frame(call_info,
fbc, opline->extended_value, ce);
call->prev_execute_data = EX(call);
EX(call) = call;
@ -3614,7 +3617,7 @@ ZEND_VM_HOT_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
CACHE_PTR(opline->result.num, fbc);
}
call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
fbc, opline->extended_value, NULL, NULL);
fbc, opline->extended_value, NULL);
call->prev_execute_data = EX(call);
EX(call) = call;
@ -3686,8 +3689,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
zend_fcall_info_cache fcc;
char *error = NULL;
zend_function *func;
zend_class_entry *called_scope;
zend_object *object;
void *object_or_called_scope;
zend_execute_data *call;
uint32_t call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC;
@ -3695,8 +3697,6 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) {
func = fcc.function_handler;
called_scope = fcc.called_scope;
object = fcc.object;
if (error) {
efree(error);
/* This is the only soft error is_callable() can generate */
@ -3706,6 +3706,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
HANDLE_EXCEPTION();
}
}
object_or_called_scope = fcc.called_scope;
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
/* Delay closure destruction until its invocation */
GC_ADDREF(ZEND_CLOSURE_OBJECT(func));
@ -3713,18 +3714,22 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
call_info |= ZEND_CALL_FAKE_CLOSURE;
}
} else if (object) {
call_info |= ZEND_CALL_RELEASE_THIS;
GC_ADDREF(object); /* For $this pointer */
if (fcc.object) {
object_or_called_scope = fcc.object;
call_info |= ZEND_CALL_HAS_THIS;
}
} else if (fcc.object) {
GC_ADDREF(fcc.object); /* For $this pointer */
object_or_called_scope = fcc.object;
call_info |= ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS;
}
FREE_OP2();
if ((OP2_TYPE & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) {
if (call_info & ZEND_CALL_CLOSURE) {
zend_object_release(ZEND_CLOSURE_OBJECT(func));
}
if (call_info & ZEND_CALL_RELEASE_THIS) {
zend_object_release(object);
} else if (call_info & ZEND_CALL_RELEASE_THIS) {
zend_object_release(fcc.object);
}
HANDLE_EXCEPTION();
}
@ -3740,12 +3745,11 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
HANDLE_EXCEPTION();
}
func = (zend_function*)&zend_pass_function;
called_scope = NULL;
object = NULL;
object_or_called_scope = NULL;
}
call = zend_vm_stack_push_call_frame(call_info,
func, opline->extended_value, called_scope, object);
func, opline->extended_value, object_or_called_scope);
call->prev_execute_data = EX(call);
EX(call) = call;
@ -3778,7 +3782,7 @@ ZEND_VM_HOT_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
}
call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
fbc, opline->extended_value, NULL, NULL);
fbc, opline->extended_value, NULL);
call->prev_execute_data = EX(call);
EX(call) = call;
@ -3809,7 +3813,7 @@ ZEND_VM_HOT_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM|CACHE_SLOT)
call = zend_vm_stack_push_call_frame_ex(
opline->op1.num, ZEND_CALL_NESTED_FUNCTION,
fbc, opline->extended_value, NULL, NULL);
fbc, opline->extended_value, NULL);
call->prev_execute_data = EX(call);
EX(call) = call;
@ -4298,7 +4302,7 @@ ZEND_VM_HANDLER(41, ZEND_GENERATOR_CREATE, ANY, ANY)
gen_execute_data->return_value = (zval*)generator;
call_info = Z_TYPE_INFO(EX(This));
if ((call_info & Z_TYPE_MASK) == IS_OBJECT
&& (!(call_info & ((ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS) << ZEND_CALL_INFO_SHIFT))
&& (!(call_info & (ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS))
/* Bug #72523 */
|| UNEXPECTED(zend_execute_ex != execute_ex))) {
ZEND_ADD_CALL_FLAG_EX(call_info, ZEND_CALL_RELEASE_THIS);
@ -4916,13 +4920,12 @@ ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY, NUM)
zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array, %s given", zend_get_type_by_const(Z_TYPE_P(args)));
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(call)->func));
}
if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
} else if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_RELEASE_THIS) {
OBJ_RELEASE(Z_OBJ(EX(call)->This));
}
EX(call)->func = (zend_function*)&zend_pass_function;
Z_OBJ(EX(call)->This) = NULL;
ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
ZEND_CALL_INFO(EX(call)) &= ~(ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS);
FREE_UNFETCHED_OP2();
} else {
uint32_t arg_num;
@ -5287,17 +5290,16 @@ ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, UNUSED|CACHE_SLOT, N
/* Perform a dummy function call */
call = zend_vm_stack_push_call_frame(
ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function,
opline->extended_value, NULL, NULL);
opline->extended_value, NULL);
} else {
if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) {
init_func_run_time_cache(&constructor->op_array);
}
/* We are not handling overloaded classes right now */
call = zend_vm_stack_push_call_frame(
ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS,
ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS,
constructor,
opline->extended_value,
ce,
Z_OBJ_P(result));
Z_ADDREF_P(result);
}
@ -5704,10 +5706,10 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY, EVAL)
new_op_array->scope = EX(func)->op_array.scope;
call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_CODE | ZEND_CALL_HAS_SYMBOL_TABLE,
call = zend_vm_stack_push_call_frame(
(Z_TYPE_INFO(EX(This)) & ZEND_CALL_HAS_THIS) | ZEND_CALL_NESTED_CODE | ZEND_CALL_HAS_SYMBOL_TABLE,
(zend_function*)new_op_array, 0,
Z_TYPE(EX(This)) != IS_OBJECT ? Z_CE(EX(This)) : NULL,
Z_TYPE(EX(This)) == IS_OBJECT ? Z_OBJ(EX(This)) : NULL);
Z_PTR(EX(This)));
if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) {
call->symbol_table = EX(symbol_table);

File diff suppressed because it is too large Load Diff

View File

@ -24,13 +24,22 @@ ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *ex)
ZEND_API void zend_{%EXECUTOR_NAME%}(zend_op_array *op_array, zval *return_value)
{
zend_execute_data *execute_data;
void *object_or_called_scope;
uint32_t call_info;
if (EG(exception) != NULL) {
return;
}
execute_data = zend_vm_stack_push_call_frame(ZEND_CALL_TOP_CODE | ZEND_CALL_HAS_SYMBOL_TABLE,
(zend_function*)op_array, 0, zend_get_called_scope(EG(current_execute_data)), zend_get_this_object(EG(current_execute_data)));
object_or_called_scope = zend_get_this_object(EG(current_execute_data));
if (EXPECTED(!object_or_called_scope)) {
object_or_called_scope = zend_get_called_scope(EG(current_execute_data));
call_info = ZEND_CALL_TOP_CODE | ZEND_CALL_HAS_SYMBOL_TABLE;
} else {
call_info = ZEND_CALL_TOP_CODE | ZEND_CALL_HAS_SYMBOL_TABLE | ZEND_CALL_HAS_THIS;
}
execute_data = zend_vm_stack_push_call_frame(call_info,
(zend_function*)op_array, 0, object_or_called_scope);
if (EG(current_execute_data)) {
execute_data->symbol_table = zend_rebuild_symbol_table();
} else {

View File

@ -99,9 +99,9 @@ static int fpm_php_trace_dump(struct fpm_child_s *child, FILE *slowlog) /* {{{ *
return -1;
}
if (ZEND_CALL_KIND_EX((*call_info) >> ZEND_CALL_INFO_SHIFT) == ZEND_CALL_TOP_CODE) {
if (ZEND_CALL_KIND_EX(*call_info) == ZEND_CALL_TOP_CODE) {
return 0;
} else if (ZEND_CALL_KIND_EX(*(call_info) >> ZEND_CALL_INFO_SHIFT) == ZEND_CALL_NESTED_CODE) {
} else if (ZEND_CALL_KIND_EX(*call_info) == ZEND_CALL_NESTED_CODE) {
memcpy(buf, "[INCLUDE_OR_EVAL]", sizeof("[INCLUDE_OR_EVAL]"));
} else {
ZEND_ASSERT(0);