Skip to content

Commit a759967

Browse files
committed
Mark call frames to closures with ZEND_CALL_CLOSURE flag to avoid expensive check at zend_leave_helper()
1 parent ec8671d commit a759967

File tree

6 files changed

+64
-35
lines changed

6 files changed

+64
-35
lines changed

Zend/zend_compile.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -429,19 +429,27 @@ struct _zend_execute_data {
429429
#define ZEND_CALL_FREE_EXTRA_ARGS (1 << 2) /* equal to IS_TYPE_REFCOUNTED */
430430
#define ZEND_CALL_CTOR (1 << 3)
431431
#define ZEND_CALL_CTOR_RESULT_UNUSED (1 << 4)
432+
#define ZEND_CALL_CLOSURE (1 << 5)
432433

433434
#define ZEND_CALL_INFO(call) \
434435
(Z_TYPE_INFO((call)->This) >> 24)
435436

437+
#define ZEND_CALL_KIND_EX(call_info) \
438+
(call_info & (ZEND_CALL_CODE | ZEND_CALL_TOP))
439+
436440
#define ZEND_CALL_KIND(call) \
437-
(ZEND_CALL_INFO(call) & (ZEND_CALL_CODE | ZEND_CALL_TOP))
441+
ZEND_CALL_KIND_EX(ZEND_CALL_INFO(call))
438442

439443
#define ZEND_SET_CALL_INFO(call, info) do { \
440444
Z_TYPE_INFO((call)->This) = IS_OBJECT_EX | ((info) << 24); \
441445
} while (0)
442446

443-
#define ZEND_ADD_CALL_FLAG(call, info) do { \
444-
Z_TYPE_INFO((call)->This) |= ((info) << 24); \
447+
#define ZEND_ADD_CALL_FLAG_EX(call_info, flag) do { \
448+
call_info |= ((flag) << 24); \
449+
} while (0)
450+
451+
#define ZEND_ADD_CALL_FLAG(call, flag) do { \
452+
ZEND_ADD_CALL_FLAG_EX(Z_TYPE_INFO((call)->This), flag); \
445453
} while (0)
446454

447455
#define ZEND_CALL_NUM_ARGS(call) \

Zend/zend_execute.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,9 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(uint3
192192
func, num_args, called_scope, object);
193193
}
194194

195-
static zend_always_inline void zend_vm_stack_free_extra_args(zend_execute_data *call)
195+
static zend_always_inline void zend_vm_stack_free_extra_args_ex(uint32_t call_info, zend_execute_data *call)
196196
{
197-
if (ZEND_CALL_INFO(call) & ZEND_CALL_FREE_EXTRA_ARGS) {
197+
if (call_info & ZEND_CALL_FREE_EXTRA_ARGS) {
198198
zval *end = ZEND_CALL_VAR_NUM(call, call->func->op_array.last_var + call->func->op_array.T);
199199
zval *p = end + (ZEND_CALL_NUM_ARGS(call) - call->func->op_array.num_args);
200200
do {
@@ -204,6 +204,11 @@ static zend_always_inline void zend_vm_stack_free_extra_args(zend_execute_data *
204204
}
205205
}
206206

207+
static zend_always_inline void zend_vm_stack_free_extra_args(zend_execute_data *call)
208+
{
209+
zend_vm_stack_free_extra_args_ex(ZEND_CALL_INFO(call), call);
210+
}
211+
207212
static zend_always_inline void zend_vm_stack_free_args(zend_execute_data *call)
208213
{
209214
uint32_t num_args = ZEND_CALL_NUM_ARGS(call);

Zend/zend_execute_API.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
833833
if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
834834
ZEND_ASSERT(GC_TYPE(func->op_array.prototype) == IS_OBJECT);
835835
GC_REFCOUNT(func->op_array.prototype)++;
836+
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_CLOSURE);
836837
}
837838
if (EXPECTED((func->op_array.fn_flags & ZEND_ACC_GENERATOR) == 0)) {
838839
zend_init_execute_data(call, &func->op_array, fci->retval);

Zend/zend_generators.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
103103

104104
if (generator->execute_data) {
105105
zend_execute_data *execute_data = generator->execute_data;
106-
zend_op_array *op_array = &execute_data->func->op_array;
107106

108107
if (!execute_data->symbol_table) {
109108
zend_free_compiled_variables(execute_data);
@@ -131,8 +130,8 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
131130
}
132131

133132
/* Free closure object */
134-
if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
135-
OBJ_RELEASE((zend_object *) op_array->prototype);
133+
if (EX_CALL_INFO() & ZEND_CALL_CLOSURE) {
134+
OBJ_RELEASE((zend_object *) EX(func)->common.prototype);
136135
}
137136

138137
efree(generator->stack);

Zend/zend_vm_def.h

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,9 +2352,9 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV)
23522352
ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
23532353
{
23542354
zend_execute_data *old_execute_data;
2355-
zend_call_kind call_kind = EX_CALL_KIND();
2355+
uint32_t call_info = EX_CALL_INFO();
23562356

2357-
if (call_kind == ZEND_CALL_NESTED_FUNCTION) {
2357+
if (ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_NESTED_FUNCTION) {
23582358
zend_object *object;
23592359

23602360
i_free_compiled_variables(execute_data);
@@ -2364,7 +2364,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
23642364
zend_vm_stack_free_extra_args(execute_data);
23652365
old_execute_data = execute_data;
23662366
execute_data = EG(current_execute_data) = EX(prev_execute_data);
2367-
if (UNEXPECTED(old_execute_data->func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
2367+
if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
23682368
OBJ_RELEASE((zend_object*)old_execute_data->func->op_array.prototype);
23692369
}
23702370
object = Z_OBJ(old_execute_data->This);
@@ -2395,7 +2395,7 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
23952395
LOAD_OPLINE();
23962396
ZEND_VM_INC_OPCODE();
23972397
ZEND_VM_LEAVE();
2398-
} else if (call_kind == ZEND_CALL_NESTED_CODE) {
2398+
} else if (ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_NESTED_CODE) {
23992399
zend_detach_symbol_table(execute_data);
24002400
destroy_op_array(&EX(func)->op_array);
24012401
efree_size(EX(func), sizeof(zend_op_array));
@@ -2413,14 +2413,14 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
24132413
ZEND_VM_INC_OPCODE();
24142414
ZEND_VM_LEAVE();
24152415
} else {
2416-
if (call_kind == ZEND_CALL_TOP_FUNCTION) {
2416+
if (ZEND_CALL_KIND_EX(call_info) == ZEND_CALL_TOP_FUNCTION) {
24172417
i_free_compiled_variables(execute_data);
24182418
if (UNEXPECTED(EX(symbol_table) != NULL)) {
24192419
zend_clean_and_cache_symbol_table(EX(symbol_table));
24202420
}
24212421
zend_vm_stack_free_extra_args(execute_data);
24222422
EG(current_execute_data) = EX(prev_execute_data);
2423-
if (EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) {
2423+
if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
24242424
OBJ_RELEASE((zend_object*)EX(func)->op_array.prototype);
24252425
}
24262426
} else /* if (call_kind == ZEND_CALL_TOP_CODE) */ {
@@ -3112,6 +3112,7 @@ ZEND_VM_HANDLER(128, ZEND_INIT_DYNAMIC_CALL, ANY, CONST|TMPVAR|CV)
31123112
zend_class_entry *called_scope;
31133113
zend_object *object;
31143114
zend_execute_data *call;
3115+
uint32_t call_info = ZEND_CALL_NESTED_FUNCTION;
31153116

31163117
SAVE_OPLINE();
31173118
function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
@@ -3147,6 +3148,7 @@ ZEND_VM_C_LABEL(try_function_name):
31473148
/* Delay closure destruction until its invocation */
31483149
ZEND_ASSERT(GC_TYPE(fbc->common.prototype) == IS_OBJECT);
31493150
GC_REFCOUNT(fbc->common.prototype)++;
3151+
call_info |= ZEND_CALL_CLOSURE;
31503152
}
31513153
FREE_OP2();
31523154
} else if (EXPECTED(Z_TYPE_P(function_name) == IS_ARRAY) &&
@@ -3241,7 +3243,7 @@ ZEND_VM_C_LABEL(try_function_name):
32413243
FREE_OP2();
32423244
HANDLE_EXCEPTION();
32433245
}
3244-
call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
3246+
call = zend_vm_stack_push_call_frame(call_info,
32453247
fbc, opline->extended_value, called_scope, object);
32463248
call->prev_execute_data = EX(call);
32473249
EX(call) = call;
@@ -3261,6 +3263,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV)
32613263
zend_class_entry *called_scope;
32623264
zend_object *object;
32633265
zend_execute_data *call;
3266+
uint32_t call_info = ZEND_CALL_NESTED_FUNCTION;
32643267

32653268
SAVE_OPLINE();
32663269
function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
@@ -3276,6 +3279,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV)
32763279
}
32773280
ZEND_ASSERT(GC_TYPE(func->common.prototype) == IS_OBJECT);
32783281
GC_REFCOUNT(func->common.prototype)++;
3282+
call_info |= ZEND_CALL_CLOSURE;
32793283
}
32803284
called_scope = fcc.called_scope;
32813285
object = fcc.object;
@@ -3304,7 +3308,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV)
33043308
object = NULL;
33053309
}
33063310

3307-
call = zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
3311+
call = zend_vm_stack_push_call_frame(call_info,
33083312
func, opline->extended_value, called_scope, object);
33093313
call->prev_execute_data = EX(call);
33103314
EX(call) = call;
@@ -4434,7 +4438,7 @@ ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY)
44344438
}
44354439
}
44364440
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)));
4437-
if (EX(call)->func->common.fn_flags & ZEND_ACC_CLOSURE) {
4441+
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
44384442
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
44394443
}
44404444
if (Z_OBJ(EX(call)->This)) {
@@ -4481,7 +4485,7 @@ ZEND_VM_C_LABEL(send_array):
44814485
EX(call)->func->common.scope ? "::" : "",
44824486
EX(call)->func->common.function_name->val);
44834487

4484-
if (EX(call)->func->common.fn_flags & ZEND_ACC_CLOSURE) {
4488+
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
44854489
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
44864490
}
44874491
if (Z_OBJ(EX(call)->This)) {
@@ -4539,7 +4543,7 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, ANY)
45394543
EX(call)->func->common.scope ? "::" : "",
45404544
EX(call)->func->common.function_name->val);
45414545

4542-
if (EX(call)->func->common.fn_flags & ZEND_ACC_CLOSURE) {
4546+
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
45434547
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
45444548
}
45454549
if (Z_OBJ(EX(call)->This)) {

0 commit comments

Comments
 (0)