Skip to content

Commit c9d830a

Browse files
committed
Only allocate new zend_type_list if types are being resolved
1 parent 8d11699 commit c9d830a

File tree

1 file changed

+54
-42
lines changed

1 file changed

+54
-42
lines changed

Zend/zend_inheritance.c

Lines changed: 54 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,6 +1898,31 @@ static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_e
18981898
return fn->common.scope->ce_flags & ZEND_ACC_TRAIT ? ce : fn->common.scope;
18991899
}
19001900

1901+
/* If the type was resolved then either the zend_string pointer is different, or the zend_type_list is */
1902+
static inline bool zend_was_type_resolved(zend_type original_type, zend_type resolved_type)
1903+
{
1904+
return original_type.ptr != resolved_type.ptr;
1905+
}
1906+
1907+
static zend_type zend_resolve_name_type(zend_type type, const zend_class_entry *const ce)
1908+
{
1909+
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(type));
1910+
if (ZEND_TYPE_IS_RELATIVE_SELF(type)) {
1911+
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(type));
1912+
return resolved_type;
1913+
} else if (ZEND_TYPE_IS_RELATIVE_PARENT(type)) {
1914+
if (!ce->parent) {
1915+
zend_error_noreturn(E_COMPILE_ERROR,
1916+
"Cannot use trait which has \"parent\" as a type when current class scope has no parent");
1917+
return (zend_type) ZEND_TYPE_INIT_NONE(0);
1918+
}
1919+
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->parent->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(type));
1920+
return resolved_type;
1921+
} else {
1922+
return type;
1923+
}
1924+
}
1925+
19011926
/* We cannot modify the type in-place (e.g. via a pointer) as it is written to SHM */
19021927
static zend_type zend_resolve_single_type(zend_type type, const zend_class_entry *const ce)
19031928
{
@@ -1908,62 +1933,49 @@ static zend_type zend_resolve_single_type(zend_type type, const zend_class_entry
19081933

19091934
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(type) || (ZEND_TYPE_HAS_LIST(type)));
19101935
if (ZEND_TYPE_HAS_NAME(type)) {
1911-
if (ZEND_TYPE_IS_RELATIVE_SELF(type)) {
1912-
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(type));
1913-
return resolved_type;
1914-
} else if (ZEND_TYPE_IS_RELATIVE_PARENT(type)) {
1915-
if (!ce->parent) {
1916-
zend_error_noreturn(E_COMPILE_ERROR,
1917-
"Cannot use trait which has \"parent\" as a type when current class scope has no parent");
1918-
return (zend_type) ZEND_TYPE_INIT_NONE(0);
1919-
}
1920-
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->parent->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(type));
1921-
return resolved_type;
1922-
} else {
1923-
return type;
1924-
}
1936+
return zend_resolve_name_type(type, ce);
19251937
}
19261938

19271939
/* Intersection types cannot have relative class_types */
19281940
if (ZEND_TYPE_IS_INTERSECTION(type)) {
19291941
return type;
19301942
}
19311943

1932-
const zend_type_list *union_type_list = ZEND_TYPE_LIST(type);
1933-
zend_type *single_type;
1934-
1935-
/* TODO Only do allocation if need to resolve types, as type is stored in SHM */
1936-
zend_type_list *new_union_type_list = zend_arena_alloc(&CG(arena), ZEND_TYPE_LIST_SIZE(union_type_list->num_types));
1937-
memcpy(new_union_type_list, union_type_list, ZEND_TYPE_LIST_SIZE(union_type_list->num_types));
1944+
zend_type_list *union_type_list = ZEND_TYPE_LIST(type);
1945+
bool has_resolved_type = false;
1946+
/* We don't use ZEND_TYPE_LIST_FOREACH() as we need to keep track of the array index */
1947+
for (uint32_t i = 0; i < union_type_list->num_types; i++) {
1948+
zend_type single_type = union_type_list->types[i];
19381949

1939-
ZEND_TYPE_LIST_FOREACH(new_union_type_list, single_type) {
1940-
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*single_type) || (ZEND_TYPE_IS_INTERSECTION(*single_type)));
1950+
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(single_type) || (ZEND_TYPE_IS_INTERSECTION(single_type)));
19411951

19421952
/* Intersections types cannot have self or parent */
1943-
if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
1953+
if (ZEND_TYPE_IS_INTERSECTION(single_type)) {
19441954
continue;
19451955
}
1946-
if (ZEND_TYPE_IS_RELATIVE_SELF(*single_type)) {
1947-
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(*single_type));
1948-
memmove(single_type, &resolved_type, sizeof(zend_type));
1949-
}
1950-
if (ZEND_TYPE_IS_RELATIVE_PARENT(*single_type)) {
1951-
if (!ce->parent) {
1952-
zend_error_noreturn(E_COMPILE_ERROR,
1953-
"Cannot use trait which has \"parent\" as a type when current class scope has no parent");
1954-
return (zend_type) ZEND_TYPE_INIT_NONE(0);
1956+
1957+
zend_type resolved_type = zend_resolve_name_type(single_type, ce);
1958+
if (zend_was_type_resolved(type, resolved_type)) {
1959+
if (!has_resolved_type) {
1960+
const zend_type_list *old_union_type_list = ZEND_TYPE_LIST(type);
1961+
union_type_list = zend_arena_alloc(&CG(arena), ZEND_TYPE_LIST_SIZE(old_union_type_list->num_types));
1962+
memcpy(union_type_list, old_union_type_list, ZEND_TYPE_LIST_SIZE(old_union_type_list->num_types));
1963+
has_resolved_type = true;
19551964
}
1956-
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->parent->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(*single_type));
1957-
memmove(single_type, &resolved_type, sizeof(zend_type));
1965+
union_type_list->types[i] = resolved_type;
19581966
}
1959-
} ZEND_TYPE_LIST_FOREACH_END();
1967+
}
19601968

1961-
zend_type new_type = (zend_type) ZEND_TYPE_INIT_NONE(0);
1962-
ZEND_TYPE_SET_LIST(new_type, new_union_type_list);
1963-
ZEND_TYPE_FULL_MASK(new_type) |= _ZEND_TYPE_ARENA_BIT;
1964-
/* Inform that the type list is a union type */
1965-
ZEND_TYPE_FULL_MASK(new_type) |= _ZEND_TYPE_UNION_BIT;
1966-
return new_type;
1969+
if (has_resolved_type) {
1970+
zend_type new_type = (zend_type) ZEND_TYPE_INIT_NONE(0);
1971+
ZEND_TYPE_SET_LIST(new_type, union_type_list);
1972+
ZEND_TYPE_FULL_MASK(new_type) |= _ZEND_TYPE_ARENA_BIT;
1973+
/* Inform that the type list is a union type */
1974+
ZEND_TYPE_FULL_MASK(new_type) |= _ZEND_TYPE_UNION_BIT;
1975+
return new_type;
1976+
} else {
1977+
return type;
1978+
}
19671979
}
19681980

19691981
static void zend_resolve_trait_relative_class_types(zend_function *const fn, const zend_class_entry *const ce)
@@ -1989,7 +2001,7 @@ static void zend_resolve_trait_relative_class_types(zend_function *const fn, con
19892001
for (uint32_t i = 0; i < num_args + has_return_type; i++) {
19902002
zend_type type = new_arg_infos[i].type;
19912003
zend_type resolved_type = zend_resolve_single_type(type, ce);
1992-
if (type.ptr != resolved_type.ptr) {
2004+
if (zend_was_type_resolved(type, resolved_type)) {
19932005
if (!has_resolved_type) {
19942006
new_arg_infos = zend_arena_alloc(&CG(arena), allocated_size);
19952007
memcpy(new_arg_infos, fn->common.arg_info - has_return_type, allocated_size);

0 commit comments

Comments
 (0)