Skip to content

Commit 3335ce1

Browse files
committed
fix CI
1 parent 1692bfd commit 3335ce1

8 files changed

Lines changed: 144 additions & 27 deletions

File tree

Zend/zend_closures.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,11 @@ static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_en
803803
if (closure->func.op_array.refcount) {
804804
(*closure->func.op_array.refcount)++;
805805
}
806+
if ((closure->func.common.fn_flags2 & ZEND_ACC2_MONOMORPH_TYPE_ARGS)
807+
&& closure->func.op_array.generic_types
808+
&& closure->func.op_array.generic_types->monomorph_type_args) {
809+
closure->func.op_array.generic_types->monomorph_type_args->refcount++;
810+
}
806811

807812
/* For fake closures, we want to reuse the static variables of the original function. */
808813
HashTable *ht = ZEND_MAP_PTR_GET(func->op_array.static_variables_ptr);

Zend/zend_compile.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,8 @@ ZEND_API zend_type_arg_table *zend_build_or_get_cached_type_args(
794794
return (zend_type_arg_table *)cache_slot[0];
795795
}
796796
zend_type_arg_table *nt = zend_build_generic_call_type_args(call, NULL);
797-
if (nt && nkey && !cache_slot[0]) {
797+
if (nt && nkey && !cache_slot[0]
798+
&& (EG(current_execute_data)->func->common.fn_flags & ZEND_ACC_HEAP_RT_CACHE)) {
798799
cache_slot[0] = nt;
799800
cache_slot[1] = (void *)nkey;
800801
nt->persisted = true;
@@ -808,7 +809,8 @@ ZEND_API zend_type_arg_table *zend_build_or_get_cached_type_args(
808809
}
809810
zend_type_arg_table *t = zend_build_generic_call_type_args(call, args_box);
810811
if (t && key && cache_slot && !cache_slot[0]
811-
&& zend_call_is_cacheable_against_args(call->func, args_box)) {
812+
&& zend_call_is_cacheable_against_args(call->func, args_box)
813+
&& (caller->func->common.fn_flags & ZEND_ACC_HEAP_RT_CACHE)) {
812814
cache_slot[0] = t;
813815
cache_slot[1] = (void *)key;
814816
t->persisted = true;
@@ -1783,6 +1785,9 @@ static bool zend_try_attach_concrete_call_table_for(zend_op_array *caller,
17831785
zend_turbofish_args_entry *entry =
17841786
zend_hash_index_find_ptr(gtt->turbofish_args, args_id);
17851787
ZEND_ASSERT(entry != NULL);
1788+
if (entry->concrete_table && !entry->concrete_table->persisted) {
1789+
zend_type_arg_table_destroy(entry->concrete_table);
1790+
}
17861791
entry->concrete_table = ct;
17871792
entry->concrete_skip_value_check =
17881793
fbc->op_array.generic_types

Zend/zend_compile.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ typedef struct _zend_type_arg_table {
261261
* as part of a persisted class entry's `generic_type_args`. Tells the
262262
* destroy path to leave the table and its name/type contents alone. */
263263
bool persisted;
264+
uint32_t refcount;
264265
zend_type_arg_entry entries[1];
265266
} zend_type_arg_table;
266267

@@ -335,6 +336,7 @@ static zend_always_inline zend_turbofish_args_entry *zend_generic_get_or_cache_a
335336

336337
ZEND_API zend_type_arg_table *zend_type_arg_table_alloc(uint32_t count);
337338
ZEND_API void zend_type_arg_table_destroy(zend_type_arg_table *table);
339+
ZEND_API void zend_type_arg_table_release(zend_type_arg_table *table);
338340
ZEND_API zend_type_arg_table *zend_type_arg_table_capture_clone(const zend_type_arg_table *src);
339341
ZEND_API zend_string *zend_type_arg_canonical_name(zend_type type);
340342
ZEND_API zend_type_arg_table *zend_build_generic_call_type_args(zend_execute_data *call, const zend_type *args_box);

Zend/zend_execute.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,9 +345,16 @@ static zend_always_inline void zend_vm_init_call_frame(zend_execute_data *call,
345345
* call-frame teardown skips destroying it. VERIFY_GENERIC_ARGUMENTS may
346346
* still overwrite type_args later for explicit-turbofish calls. */
347347
if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CLOSURE)) {
348+
#if defined(__GNUC__) && !defined(__clang__)
349+
# pragma GCC diagnostic push
350+
# pragma GCC diagnostic ignored "-Warray-bounds"
351+
#endif
348352
const zend_closure *closure =
349353
(const zend_closure *) ZEND_CLOSURE_OBJECT(func);
350354
call->type_args = closure->captured_type_args;
355+
#if defined(__GNUC__) && !defined(__clang__)
356+
# pragma GCC diagnostic pop
357+
#endif
351358
} else if (UNEXPECTED(ZEND_USER_CODE(func->type)
352359
&& (func->op_array.fn_flags2 & ZEND_ACC2_MONOMORPH_TYPE_ARGS))) {
353360
/* Monomorph reached via by-name dispatch: bind its concrete type-arg table. */

Zend/zend_inheritance.c

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6107,6 +6107,8 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
61076107
zval *zv;
61086108
zend_string *synthesized_lc_parent = NULL;
61096109
zend_class_entry *cache_key_proto = NULL;
6110+
zend_class_name *detached_interface_names = NULL;
6111+
uint32_t detached_interface_count = 0;
61106112
ALLOCA_FLAG(use_heap)
61116113

61126114
SET_ALLOCA_FLAG(use_heap);
@@ -6142,10 +6144,12 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
61426144
zend_string_addref(ce->interface_names[k].name);
61436145
zend_string_addref(ce->interface_names[k].lc_name);
61446146
}
6147+
detached_interface_names = ce->interface_names;
6148+
detached_interface_count = ce->num_interfaces;
61456149
}
61466150
if (ce->num_traits) {
61476151
zend_class_name *src = ce->trait_names;
6148-
ce->trait_names = emalloc(sizeof(zend_class_name) * ce->num_traits);
6152+
ce->trait_names = zend_arena_alloc(&CG(arena), sizeof(zend_class_name) * ce->num_traits);
61496153
memcpy(ce->trait_names, src, sizeof(zend_class_name) * ce->num_traits);
61506154
for (uint32_t k = 0; k < ce->num_traits; k++) {
61516155
zend_string_addref(ce->trait_names[k].name);
@@ -6230,9 +6234,8 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
62306234
? ce->generic_types->trait_uses : NULL;
62316235
bool ce_is_mono_for_trait = zend_class_is_monomorph(ce);
62326236
bool *trait_skip_mono = NULL;
6233-
ALLOCA_FLAG(trait_skip_use_heap)
62346237
if (trait_uses_table_for_synth && ce->num_traits > 1) {
6235-
trait_skip_mono = do_alloca(sizeof(bool) * ce->num_traits, trait_skip_use_heap);
6238+
trait_skip_mono = emalloc(sizeof(bool) * ce->num_traits);
62366239
zend_mark_duplicate_lc_names(ce->trait_names, ce->num_traits, trait_skip_mono);
62376240
}
62386241

@@ -6257,14 +6260,14 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
62576260
ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_EXCEPTION);
62586261
if (UNEXPECTED(base_trait == NULL)) {
62596262
free_alloca(traits_and_interfaces, use_heap);
6260-
if (trait_skip_mono) free_alloca(trait_skip_mono, trait_skip_use_heap);
6263+
if (trait_skip_mono) efree(trait_skip_mono);
62616264
return NULL;
62626265
}
62636266
if (UNEXPECTED(!(base_trait->ce_flags & ZEND_ACC_TRAIT))) {
62646267
zend_throw_error(NULL, "%s cannot use %s - it is not a trait",
62656268
ZSTR_VAL(ce->name), ZSTR_VAL(base_trait->name));
62666269
free_alloca(traits_and_interfaces, use_heap);
6267-
if (trait_skip_mono) free_alloca(trait_skip_mono, trait_skip_use_heap);
6270+
if (trait_skip_mono) efree(trait_skip_mono);
62686271
return NULL;
62696272
}
62706273
if (base_trait->generic_parameters) {
@@ -6273,15 +6276,15 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
62736276
if (EG(exception)) {
62746277
check_unrecoverable_load_failure(ce);
62756278
free_alloca(traits_and_interfaces, use_heap);
6276-
if (trait_skip_mono) free_alloca(trait_skip_mono, trait_skip_use_heap);
6279+
if (trait_skip_mono) efree(trait_skip_mono);
62776280
return NULL;
62786281
}
62796282
zend_class_entry *mono = zend_synthesize_monomorph(
62806283
base_trait, nwa->args, nwa->count);
62816284
if (!mono) {
62826285
check_unrecoverable_load_failure(ce);
62836286
free_alloca(traits_and_interfaces, use_heap);
6284-
if (trait_skip_mono) free_alloca(trait_skip_mono, trait_skip_use_heap);
6287+
if (trait_skip_mono) efree(trait_skip_mono);
62856288
return NULL;
62866289
}
62876290
zend_string_release(ce->trait_names[i].name);
@@ -6295,20 +6298,20 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
62956298
ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_EXCEPTION);
62966299
if (UNEXPECTED(trait == NULL)) {
62976300
free_alloca(traits_and_interfaces, use_heap);
6298-
if (trait_skip_mono) free_alloca(trait_skip_mono, trait_skip_use_heap);
6301+
if (trait_skip_mono) efree(trait_skip_mono);
62996302
return NULL;
63006303
}
63016304
if (UNEXPECTED(!(trait->ce_flags & ZEND_ACC_TRAIT))) {
63026305
zend_throw_error(NULL, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name));
63036306
free_alloca(traits_and_interfaces, use_heap);
6304-
if (trait_skip_mono) free_alloca(trait_skip_mono, trait_skip_use_heap);
6307+
if (trait_skip_mono) efree(trait_skip_mono);
63056308
return NULL;
63066309
}
63076310
if (UNEXPECTED(trait->ce_flags & ZEND_ACC_DEPRECATED)) {
63086311
zend_use_of_deprecated_trait(trait, ce->name);
63096312
if (UNEXPECTED(EG(exception))) {
63106313
free_alloca(traits_and_interfaces, use_heap);
6311-
if (trait_skip_mono) free_alloca(trait_skip_mono, trait_skip_use_heap);
6314+
if (trait_skip_mono) efree(trait_skip_mono);
63126315
return NULL;
63136316
}
63146317
}
@@ -6339,7 +6342,7 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
63396342
}
63406343
}
63416344
if (trait_skip_mono) {
6342-
free_alloca(trait_skip_mono, trait_skip_use_heap);
6345+
efree(trait_skip_mono);
63436346
}
63446347
}
63456348

@@ -6559,6 +6562,13 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
65596562
sizeof(zend_class_entry *) * ce->num_interfaces);
65606563

65616564
zend_do_implement_interfaces(ce, interfaces);
6565+
if (detached_interface_names) {
6566+
for (uint32_t k = 0; k < detached_interface_count; k++) {
6567+
zend_string_release_ex(detached_interface_names[k].name, 0);
6568+
zend_string_release_ex(detached_interface_names[k].lc_name, 0);
6569+
}
6570+
efree(detached_interface_names);
6571+
}
65626572
} else if (parent && parent->num_interfaces) {
65636573
zend_do_inherit_interfaces(ce, parent);
65646574
}
@@ -7925,17 +7935,12 @@ ZEND_API zend_function *zend_synthesize_function_monomorph(
79257935
zend_type_arg_table *mono_targs = NULL;
79267936
{
79277937
uint32_t tcount = params->count;
7928-
mono_targs = zend_arena_alloc(&CG(arena), ZEND_TYPE_ARG_TABLE_SIZE(tcount));
7929-
mono_targs->count = tcount;
7930-
mono_targs->generation = 0;
7938+
mono_targs = zend_type_arg_table_alloc(tcount);
79317939
mono_targs->persisted = true;
79327940
for (uint32_t i = 0; i < tcount; i++) {
7933-
mono_targs->entries[i].name = NULL;
7934-
mono_targs->entries[i].type_ref = NULL;
7935-
mono_targs->entries[i].owned_type = (zend_type) ZEND_TYPE_INIT_NONE(0);
79367941
if (i < arity && ZEND_TYPE_IS_SET(args[i])) {
79377942
zend_type owned = args[i];
7938-
zend_type_copy_ctor(&owned, /* use_arena */ true, /* persistent */ false);
7943+
zend_type_copy_ctor(&owned, /* use_arena */ false, /* persistent */ false);
79397944
mono_targs->entries[i].owned_type = owned;
79407945
zend_string *cname = zend_type_arg_canonical_name(args[i]);
79417946
mono_targs->entries[i].name = cname;
@@ -8079,14 +8084,9 @@ ZEND_API zend_function *zend_synthesize_specialized_monomorph_into(
80798084

80808085
zend_arg_info *new_arg_info = zend_monomorph_build_arg_info(src, args, arity, /* use_arena */ false);
80818086

8082-
zend_type_arg_table *mono_targs = emalloc(ZEND_TYPE_ARG_TABLE_SIZE(total));
8083-
mono_targs->count = total;
8084-
mono_targs->generation = 0;
8085-
mono_targs->persisted = false;
8087+
zend_type_arg_table *mono_targs = zend_type_arg_table_alloc(total);
8088+
mono_targs->persisted = true;
80868089
for (uint32_t i = 0; i < total; i++) {
8087-
mono_targs->entries[i].name = NULL;
8088-
mono_targs->entries[i].type_ref = NULL;
8089-
mono_targs->entries[i].owned_type = (zend_type) ZEND_TYPE_INIT_NONE(0);
80908090
if (i < arity && ZEND_TYPE_IS_SET(args[i])) {
80918091
zend_type owned = args[i];
80928092
zend_type_copy_ctor(&owned, /* use_arena */ false, /* persistent */ false);

Zend/zend_opcode.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ ZEND_API zend_type_arg_table *zend_type_arg_table_alloc(uint32_t count) {
335335
table->count = count;
336336
table->generation = zend_type_arg_table_generation_counter++;
337337
table->persisted = false;
338+
table->refcount = 1;
338339
for (uint32_t i = 0; i < count; i++) {
339340
table->entries[i].name = NULL;
340341
table->entries[i].type_ref = NULL;
@@ -343,6 +344,21 @@ ZEND_API zend_type_arg_table *zend_type_arg_table_alloc(uint32_t count) {
343344
return table;
344345
}
345346

347+
ZEND_API void zend_type_arg_table_release(zend_type_arg_table *table) {
348+
if (!table || table->refcount == 0 || --table->refcount > 0) {
349+
return;
350+
}
351+
for (uint32_t i = 0; i < table->count; i++) {
352+
if (table->entries[i].name) {
353+
zend_string_release(table->entries[i].name);
354+
}
355+
if (ZEND_TYPE_IS_SET(table->entries[i].owned_type)) {
356+
zend_type_release(table->entries[i].owned_type, false);
357+
}
358+
}
359+
efree(table);
360+
}
361+
346362
ZEND_API void zend_type_arg_table_destroy(zend_type_arg_table *table) {
347363
if (!table || table->persisted) {
348364
return;
@@ -657,6 +673,12 @@ ZEND_API void destroy_zend_class(zval *zv)
657673
if (ce->num_traits > 0) {
658674
_destroy_zend_class_traits_info(ce);
659675
}
676+
} else if (ce->num_traits > 0) {
677+
uint32_t i;
678+
for (i = 0; i < ce->num_traits; i++) {
679+
zend_string_release_ex(ce->trait_names[i].name, 0);
680+
zend_string_release_ex(ce->trait_names[i].lc_name, 0);
681+
}
660682
}
661683

662684
if (ce->default_properties_table) {
@@ -892,6 +914,40 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
892914
if (cache_buf) {
893915
for (uint32_t op_idx = 0; op_idx < op_array->last; op_idx++) {
894916
const zend_op *op = &op_array->opcodes[op_idx];
917+
if ((op->opcode == ZEND_INIT_FCALL_BY_NAME
918+
|| op->opcode == ZEND_INIT_NS_FCALL_BY_NAME)
919+
&& op->result.num) {
920+
void **cache_slot = (void **) (cache_buf + op->result.num);
921+
zend_function *cached = (zend_function *) cache_slot[0];
922+
if (cached
923+
&& cached->type == ZEND_USER_FUNCTION
924+
&& (cached->common.fn_flags2 & ZEND_ACC2_MONOMORPH_TYPE_ARGS)
925+
&& !(cached->common.fn_flags & ZEND_ACC_IMMUTABLE)) {
926+
zend_op_array *moa = &cached->op_array;
927+
if (moa->generic_types && moa->generic_types->monomorph_type_args) {
928+
zend_type_arg_table_release(moa->generic_types->monomorph_type_args);
929+
moa->generic_types->monomorph_type_args = NULL;
930+
}
931+
if (moa->arg_info) {
932+
bool has_ret = (moa->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) != 0;
933+
uint32_t total = moa->num_args + (has_ret ? 1 : 0)
934+
+ ((moa->fn_flags & ZEND_ACC_VARIADIC) ? 1 : 0);
935+
zend_arg_info *block = moa->arg_info - (has_ret ? 1 : 0);
936+
for (uint32_t a = 0; a < total; a++) {
937+
zend_type_release(block[a].type, 0);
938+
if (block[a].name) {
939+
zend_string_release(block[a].name);
940+
}
941+
if (block[a].doc_comment) {
942+
zend_string_release(block[a].doc_comment);
943+
}
944+
}
945+
moa->arg_info = NULL;
946+
}
947+
cache_slot[0] = NULL;
948+
}
949+
continue;
950+
}
895951
if ((op->opcode == ZEND_VERIFY_GENERIC_ARGUMENTS
896952
|| op->opcode == ZEND_INSTALL_GENERIC_ARGS)
897953
&& op->op1_type == IS_UNUSED
@@ -931,6 +987,14 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
931987
zend_string_release_ex(op_array->function_name, 0);
932988
}
933989

990+
if ((op_array->fn_flags2 & ZEND_ACC2_MONOMORPH_TYPE_ARGS)
991+
&& !(op_array->fn_flags & ZEND_ACC_IMMUTABLE)
992+
&& op_array->generic_types
993+
&& op_array->generic_types->monomorph_type_args) {
994+
zend_type_arg_table_release(op_array->generic_types->monomorph_type_args);
995+
op_array->generic_types->monomorph_type_args = NULL;
996+
}
997+
934998
if (!op_array->refcount || --(*op_array->refcount) > 0) {
935999
return;
9361000
}

Zend/zend_vm_def.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4419,6 +4419,8 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
44194419
}
44204420
if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) {
44214421
OBJ_RELEASE(Z_OBJ(call->This));
4422+
} else if (ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE) {
4423+
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(call->func));
44224424
}
44234425
EX(call) = call->prev_execute_data;
44244426
zend_vm_stack_free_call_frame(call);
@@ -9356,6 +9358,10 @@ ZEND_VM_HANDLER(213, ZEND_INSTALL_GENERIC_ARGS, TMP|UNUSED, UNUSED)
93569358

93579359
generic_install_check_exception:
93589360
if (UNEXPECTED(EG(exception))) {
9361+
if (call->type_args && !call->type_args->persisted) {
9362+
zend_type_arg_table_destroy(call->type_args);
9363+
call->type_args = NULL;
9364+
}
93599365
zend_vm_stack_free_args(call);
93609366

93619367
if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {

0 commit comments

Comments
 (0)