Skip to content

Commit 81c5215

Browse files
committed
fix CI
1 parent 1692bfd commit 81c5215

8 files changed

Lines changed: 162 additions & 30 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: 13 additions & 5 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;
@@ -831,7 +833,8 @@ ZEND_API zend_function *zend_get_or_synthesize_call_monomorph(
831833
if (cache_slot
832834
&& (uintptr_t) cache_slot[1] == ZEND_TURBOFISH_CACHE_KEY_MONOMORPH
833835
&& cache_slot[3] == (void *) base) {
834-
*out_type_args = (zend_type_arg_table *) cache_slot[4];
836+
zend_type_arg_table *cached = (zend_type_arg_table *) cache_slot[4];
837+
*out_type_args = cached ? cached : zend_build_concrete_call_type_args(base, args_box);
835838
return (zend_function *) cache_slot[0];
836839
}
837840

@@ -861,15 +864,17 @@ ZEND_API zend_function *zend_get_or_synthesize_call_monomorph(
861864
}
862865

863866
zend_type_arg_table *table = zend_build_concrete_call_type_args(base, args_box);
864-
if (table) {
867+
bool can_cache_table = table && cache_slot && EG(current_execute_data)
868+
&& (EG(current_execute_data)->func->common.fn_flags & ZEND_ACC_HEAP_RT_CACHE);
869+
if (can_cache_table) {
865870
table->persisted = true;
866871
}
867872

868873
if (cache_slot) {
869874
cache_slot[0] = mono;
870875
cache_slot[1] = (void *) ZEND_TURBOFISH_CACHE_KEY_MONOMORPH;
871876
cache_slot[3] = (void *) base;
872-
cache_slot[4] = table;
877+
cache_slot[4] = can_cache_table ? table : NULL;
873878
}
874879
*out_type_args = table;
875880
return mono;
@@ -1783,6 +1788,9 @@ static bool zend_try_attach_concrete_call_table_for(zend_op_array *caller,
17831788
zend_turbofish_args_entry *entry =
17841789
zend_hash_index_find_ptr(gtt->turbofish_args, args_id);
17851790
ZEND_ASSERT(entry != NULL);
1791+
if (entry->concrete_table && !entry->concrete_table->persisted) {
1792+
zend_type_arg_table_destroy(entry->concrete_table);
1793+
}
17861794
entry->concrete_table = ct;
17871795
entry->concrete_skip_value_check =
17881796
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: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2939,6 +2939,9 @@ static void do_inherit_property(zend_property_info *parent_info, zend_string *ke
29392939
clone->hooks = clone_hooks;
29402940
}
29412941

2942+
if (ZEND_TYPE_HAS_LIST(sub) || ZEND_TYPE_HAS_NAMED_WITH_ARGS(sub)) {
2943+
zend_type_release(sub, /* persistent */ false);
2944+
}
29422945
info = clone;
29432946
}
29442947
}
@@ -6107,6 +6110,8 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
61076110
zval *zv;
61086111
zend_string *synthesized_lc_parent = NULL;
61096112
zend_class_entry *cache_key_proto = NULL;
6113+
zend_class_name *detached_interface_names = NULL;
6114+
uint32_t detached_interface_count = 0;
61106115
ALLOCA_FLAG(use_heap)
61116116

61126117
SET_ALLOCA_FLAG(use_heap);
@@ -6142,10 +6147,12 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
61426147
zend_string_addref(ce->interface_names[k].name);
61436148
zend_string_addref(ce->interface_names[k].lc_name);
61446149
}
6150+
detached_interface_names = ce->interface_names;
6151+
detached_interface_count = ce->num_interfaces;
61456152
}
61466153
if (ce->num_traits) {
61476154
zend_class_name *src = ce->trait_names;
6148-
ce->trait_names = emalloc(sizeof(zend_class_name) * ce->num_traits);
6155+
ce->trait_names = zend_arena_alloc(&CG(arena), sizeof(zend_class_name) * ce->num_traits);
61496156
memcpy(ce->trait_names, src, sizeof(zend_class_name) * ce->num_traits);
61506157
for (uint32_t k = 0; k < ce->num_traits; k++) {
61516158
zend_string_addref(ce->trait_names[k].name);
@@ -6230,9 +6237,8 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
62306237
? ce->generic_types->trait_uses : NULL;
62316238
bool ce_is_mono_for_trait = zend_class_is_monomorph(ce);
62326239
bool *trait_skip_mono = NULL;
6233-
ALLOCA_FLAG(trait_skip_use_heap)
62346240
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);
6241+
trait_skip_mono = emalloc(sizeof(bool) * ce->num_traits);
62366242
zend_mark_duplicate_lc_names(ce->trait_names, ce->num_traits, trait_skip_mono);
62376243
}
62386244

@@ -6257,14 +6263,14 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
62576263
ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_EXCEPTION);
62586264
if (UNEXPECTED(base_trait == NULL)) {
62596265
free_alloca(traits_and_interfaces, use_heap);
6260-
if (trait_skip_mono) free_alloca(trait_skip_mono, trait_skip_use_heap);
6266+
if (trait_skip_mono) efree(trait_skip_mono);
62616267
return NULL;
62626268
}
62636269
if (UNEXPECTED(!(base_trait->ce_flags & ZEND_ACC_TRAIT))) {
62646270
zend_throw_error(NULL, "%s cannot use %s - it is not a trait",
62656271
ZSTR_VAL(ce->name), ZSTR_VAL(base_trait->name));
62666272
free_alloca(traits_and_interfaces, use_heap);
6267-
if (trait_skip_mono) free_alloca(trait_skip_mono, trait_skip_use_heap);
6273+
if (trait_skip_mono) efree(trait_skip_mono);
62686274
return NULL;
62696275
}
62706276
if (base_trait->generic_parameters) {
@@ -6273,15 +6279,15 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
62736279
if (EG(exception)) {
62746280
check_unrecoverable_load_failure(ce);
62756281
free_alloca(traits_and_interfaces, use_heap);
6276-
if (trait_skip_mono) free_alloca(trait_skip_mono, trait_skip_use_heap);
6282+
if (trait_skip_mono) efree(trait_skip_mono);
62776283
return NULL;
62786284
}
62796285
zend_class_entry *mono = zend_synthesize_monomorph(
62806286
base_trait, nwa->args, nwa->count);
62816287
if (!mono) {
62826288
check_unrecoverable_load_failure(ce);
62836289
free_alloca(traits_and_interfaces, use_heap);
6284-
if (trait_skip_mono) free_alloca(trait_skip_mono, trait_skip_use_heap);
6290+
if (trait_skip_mono) efree(trait_skip_mono);
62856291
return NULL;
62866292
}
62876293
zend_string_release(ce->trait_names[i].name);
@@ -6295,20 +6301,20 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
62956301
ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT | ZEND_FETCH_CLASS_EXCEPTION);
62966302
if (UNEXPECTED(trait == NULL)) {
62976303
free_alloca(traits_and_interfaces, use_heap);
6298-
if (trait_skip_mono) free_alloca(trait_skip_mono, trait_skip_use_heap);
6304+
if (trait_skip_mono) efree(trait_skip_mono);
62996305
return NULL;
63006306
}
63016307
if (UNEXPECTED(!(trait->ce_flags & ZEND_ACC_TRAIT))) {
63026308
zend_throw_error(NULL, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name));
63036309
free_alloca(traits_and_interfaces, use_heap);
6304-
if (trait_skip_mono) free_alloca(trait_skip_mono, trait_skip_use_heap);
6310+
if (trait_skip_mono) efree(trait_skip_mono);
63056311
return NULL;
63066312
}
63076313
if (UNEXPECTED(trait->ce_flags & ZEND_ACC_DEPRECATED)) {
63086314
zend_use_of_deprecated_trait(trait, ce->name);
63096315
if (UNEXPECTED(EG(exception))) {
63106316
free_alloca(traits_and_interfaces, use_heap);
6311-
if (trait_skip_mono) free_alloca(trait_skip_mono, trait_skip_use_heap);
6317+
if (trait_skip_mono) efree(trait_skip_mono);
63126318
return NULL;
63136319
}
63146320
}
@@ -6339,7 +6345,7 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
63396345
}
63406346
}
63416347
if (trait_skip_mono) {
6342-
free_alloca(trait_skip_mono, trait_skip_use_heap);
6348+
efree(trait_skip_mono);
63436349
}
63446350
}
63456351

@@ -6559,6 +6565,13 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
65596565
sizeof(zend_class_entry *) * ce->num_interfaces);
65606566

65616567
zend_do_implement_interfaces(ce, interfaces);
6568+
if (detached_interface_names) {
6569+
for (uint32_t k = 0; k < detached_interface_count; k++) {
6570+
zend_string_release_ex(detached_interface_names[k].name, 0);
6571+
zend_string_release_ex(detached_interface_names[k].lc_name, 0);
6572+
}
6573+
efree(detached_interface_names);
6574+
}
65626575
} else if (parent && parent->num_interfaces) {
65636576
zend_do_inherit_interfaces(ce, parent);
65646577
}
@@ -7925,17 +7938,12 @@ ZEND_API zend_function *zend_synthesize_function_monomorph(
79257938
zend_type_arg_table *mono_targs = NULL;
79267939
{
79277940
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;
7941+
mono_targs = zend_type_arg_table_alloc(tcount);
79317942
mono_targs->persisted = true;
79327943
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);
79367944
if (i < arity && ZEND_TYPE_IS_SET(args[i])) {
79377945
zend_type owned = args[i];
7938-
zend_type_copy_ctor(&owned, /* use_arena */ true, /* persistent */ false);
7946+
zend_type_copy_ctor(&owned, /* use_arena */ false, /* persistent */ false);
79397947
mono_targs->entries[i].owned_type = owned;
79407948
zend_string *cname = zend_type_arg_canonical_name(args[i]);
79417949
mono_targs->entries[i].name = cname;
@@ -8079,14 +8087,9 @@ ZEND_API zend_function *zend_synthesize_specialized_monomorph_into(
80798087

80808088
zend_arg_info *new_arg_info = zend_monomorph_build_arg_info(src, args, arity, /* use_arena */ false);
80818089

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;
8090+
zend_type_arg_table *mono_targs = zend_type_arg_table_alloc(total);
8091+
mono_targs->persisted = true;
80868092
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);
80908093
if (i < arity && ZEND_TYPE_IS_SET(args[i])) {
80918094
zend_type owned = args[i];
80928095
zend_type_copy_ctor(&owned, /* use_arena */ false, /* persistent */ false);

Zend/zend_opcode.c

Lines changed: 73 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) {
@@ -698,6 +720,10 @@ ZEND_API void destroy_zend_class(zval *zv)
698720
}
699721
}
700722
} else if (prop_info->flags & ZEND_ACC_GENERIC_CLONE) {
723+
zend_type_release(prop_info->type, /* persistent */ false);
724+
if (prop_info->name) {
725+
zend_string_release_ex(prop_info->name, 0);
726+
}
701727
if (prop_info->hooks) {
702728
for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
703729
if (prop_info->hooks[i]) {
@@ -867,6 +893,36 @@ ZEND_API void zend_destroy_static_vars(zend_op_array *op_array)
867893
}
868894
}
869895

896+
static void zend_release_transient_monomorph(zend_function *cm)
897+
{
898+
if (!cm || cm->type != ZEND_USER_FUNCTION
899+
|| !(cm->common.fn_flags2 & ZEND_ACC2_MONOMORPH_TYPE_ARGS)
900+
|| (cm->common.fn_flags & ZEND_ACC_IMMUTABLE)) {
901+
return;
902+
}
903+
zend_op_array *moa = &cm->op_array;
904+
if (moa->generic_types && moa->generic_types->monomorph_type_args) {
905+
zend_type_arg_table_release(moa->generic_types->monomorph_type_args);
906+
moa->generic_types->monomorph_type_args = NULL;
907+
}
908+
if (moa->arg_info) {
909+
bool has_ret = (moa->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) != 0;
910+
uint32_t total = moa->num_args + (has_ret ? 1 : 0)
911+
+ ((moa->fn_flags & ZEND_ACC_VARIADIC) ? 1 : 0);
912+
zend_arg_info *block = moa->arg_info - (has_ret ? 1 : 0);
913+
for (uint32_t a = 0; a < total; a++) {
914+
zend_type_release(block[a].type, 0);
915+
if (block[a].name) {
916+
zend_string_release(block[a].name);
917+
}
918+
if (block[a].doc_comment) {
919+
zend_string_release(block[a].doc_comment);
920+
}
921+
}
922+
moa->arg_info = NULL;
923+
}
924+
}
925+
870926
ZEND_API void destroy_op_array(zend_op_array *op_array)
871927
{
872928
uint32_t i;
@@ -892,6 +948,14 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
892948
if (cache_buf) {
893949
for (uint32_t op_idx = 0; op_idx < op_array->last; op_idx++) {
894950
const zend_op *op = &op_array->opcodes[op_idx];
951+
if ((op->opcode == ZEND_INIT_FCALL_BY_NAME
952+
|| op->opcode == ZEND_INIT_NS_FCALL_BY_NAME)
953+
&& op->result.num) {
954+
void **cache_slot = (void **) (cache_buf + op->result.num);
955+
zend_release_transient_monomorph((zend_function *) cache_slot[0]);
956+
cache_slot[0] = NULL;
957+
continue;
958+
}
895959
if ((op->opcode == ZEND_VERIFY_GENERIC_ARGUMENTS
896960
|| op->opcode == ZEND_INSTALL_GENERIC_ARGS)
897961
&& op->op1_type == IS_UNUSED
@@ -906,6 +970,7 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
906970
zend_type_arg_table_destroy(mt);
907971
cache_slot[4] = NULL;
908972
}
973+
zend_release_transient_monomorph((zend_function *) cache_slot[0]);
909974
cache_slot[0] = NULL;
910975
cache_slot[1] = NULL;
911976
continue;
@@ -931,6 +996,14 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
931996
zend_string_release_ex(op_array->function_name, 0);
932997
}
933998

999+
if ((op_array->fn_flags2 & ZEND_ACC2_MONOMORPH_TYPE_ARGS)
1000+
&& !(op_array->fn_flags & ZEND_ACC_IMMUTABLE)
1001+
&& op_array->generic_types
1002+
&& op_array->generic_types->monomorph_type_args) {
1003+
zend_type_arg_table_release(op_array->generic_types->monomorph_type_args);
1004+
op_array->generic_types->monomorph_type_args = NULL;
1005+
}
1006+
9341007
if (!op_array->refcount || --(*op_array->refcount) > 0) {
9351008
return;
9361009
}

0 commit comments

Comments
 (0)