From aea7467de08783ab372d1645358934c350ddeca3 Mon Sep 17 00:00:00 2001 From: Petr Shumilov Date: Thu, 9 Jul 2026 21:57:39 +0300 Subject: [PATCH 1/7] Temporary fix Signed-off-by: Petr Shumilov --- runtime-common/core/core-context.h | 12 ++++ .../core/core-types/definition/mixed.inl | 70 ++++++++++++++++--- 2 files changed, 73 insertions(+), 9 deletions(-) diff --git a/runtime-common/core/core-context.h b/runtime-common/core/core-context.h index 30137813fd..71345a7f5c 100644 --- a/runtime-common/core/core-context.h +++ b/runtime-common/core/core-context.h @@ -6,8 +6,11 @@ #include #include +#include #include "common/mixin/not_copyable.h" +#include "runtime-common/core/allocator/script-allocator.h" +#include "runtime-common/core/std/containers.h" #ifndef INCLUDED_FROM_KPHP_CORE #error "this file must be included only from runtime-core.h" @@ -17,6 +20,15 @@ struct RuntimeContext final : vk::not_copyable { int32_t show_migration_php8_warning{}; int32_t php_disable_warnings{}; uint32_t empty_obj_count{}; + struct { + kphp::stl::unordered_map objects; + void* bool_v{}; + void* int64_v{}; + void* double_v{}; + void* string_v{}; + void* mixed_v{}; + void* array_v{}; + } empty_value; string_buffer_lib_context sb_lib_context{}; string_buffer static_SB{}; diff --git a/runtime-common/core/core-types/definition/mixed.inl b/runtime-common/core/core-types/definition/mixed.inl index d291a7725c..e5c59a88ce 100644 --- a/runtime-common/core/core-types/definition/mixed.inl +++ b/runtime-common/core/core-types/definition/mixed.inl @@ -8,7 +8,11 @@ #include "common/smart_ptrs/intrusive_ptr.h" #include "runtime-common/core/class-instance/refcountable-php-classes.h" +#include "runtime-common/core/runtime-core.h" #include "runtime-common/core/utils/migration-php8.h" +#include +#include +#include #ifndef INCLUDED_FROM_KPHP_CORE #error "this file must be included only from runtime-core.h" @@ -173,22 +177,70 @@ inline void swap(mixed& lhs, mixed& rhs) { lhs.swap(rhs); } +template +struct dependent_false : std::false_type {}; + +template +inline constexpr bool dependent_false_v = dependent_false::value; + template T& mixed::empty_value() noexcept { static_assert(vk::is_type_in_list>{} || is_type_acceptable_for_mixed::value, "unsupported type"); - static T value; - value = T{}; - return value; + auto& ctx{RuntimeContext::get()}; + if constexpr (is_type_acceptable_for_mixed::value) { + auto& type2value{ctx.empty_value.objects}; + const auto it{type2value.find(std::type_index(typeid(T)))}; + if (it != type2value.end()) { + return *reinterpret_cast(it->second); + } + auto* obj{new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}}; + type2value.insert({std::type_index(typeid(T)), static_cast(obj)}); + return *obj; + } else if constexpr (std::is_same_v) { + if (ctx.empty_value.bool_v == nullptr) { + ctx.empty_value.bool_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; + } + return *reinterpret_cast(ctx.empty_value.bool_v); + } else if constexpr (std::is_same_v) { + if (ctx.empty_value.int64_v == nullptr) { + ctx.empty_value.int64_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; + } + return *reinterpret_cast(ctx.empty_value.int64_v); + } else if constexpr (std::is_same_v) { + if (ctx.empty_value.double_v == nullptr) { + ctx.empty_value.double_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; + } + return *reinterpret_cast(ctx.empty_value.double_v); + } else if constexpr (std::is_same_v) { + if (ctx.empty_value.string_v == nullptr) { + ctx.empty_value.string_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; + } + return *reinterpret_cast(ctx.empty_value.string_v); + } else if constexpr (std::is_same_v) { + if (ctx.empty_value.mixed_v == nullptr) { + ctx.empty_value.mixed_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; + } + return *reinterpret_cast(ctx.empty_value.mixed_v); + } else if constexpr (std::is_same_v>) { + if (ctx.empty_value.array_v == nullptr) { + ctx.empty_value.array_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; + } + return *reinterpret_cast(ctx.empty_value.array_v); + } else { + static_assert(dependent_false_v, "Unsupported type provided!"); + } } inline void mixed::reset_empty_values() noexcept { - empty_value(); - empty_value(); - empty_value(); - empty_value(); - empty_value(); - empty_value>(); + auto& ctx{RuntimeContext::get()}; + ctx.empty_value.objects.clear(); + ctx.empty_value.bool_v = nullptr; + ctx.empty_value.int64_v = nullptr; + ctx.empty_value.double_v = nullptr; + ctx.empty_value.string_v = nullptr; + ctx.empty_value.mixed_v = nullptr; + ctx.empty_value.array_v = nullptr; } template From a58cd3151da0619c4e362429089939a51e5c2de1 Mon Sep 17 00:00:00 2001 From: Petr Shumilov Date: Fri, 10 Jul 2026 19:19:57 +0300 Subject: [PATCH 2/7] Adjust semantics Signed-off-by: Petr Shumilov --- runtime-common/core/core-context.h | 13 +-- .../core/core-types/definition/mixed.inl | 83 ++++++------------- 2 files changed, 26 insertions(+), 70 deletions(-) diff --git a/runtime-common/core/core-context.h b/runtime-common/core/core-context.h index 71345a7f5c..5baab45526 100644 --- a/runtime-common/core/core-context.h +++ b/runtime-common/core/core-context.h @@ -6,11 +6,8 @@ #include #include -#include #include "common/mixin/not_copyable.h" -#include "runtime-common/core/allocator/script-allocator.h" -#include "runtime-common/core/std/containers.h" #ifndef INCLUDED_FROM_KPHP_CORE #error "this file must be included only from runtime-core.h" @@ -20,15 +17,7 @@ struct RuntimeContext final : vk::not_copyable { int32_t show_migration_php8_warning{}; int32_t php_disable_warnings{}; uint32_t empty_obj_count{}; - struct { - kphp::stl::unordered_map objects; - void* bool_v{}; - void* int64_v{}; - void* double_v{}; - void* string_v{}; - void* mixed_v{}; - void* array_v{}; - } empty_value; + void* empty_values{nullptr}; string_buffer_lib_context sb_lib_context{}; string_buffer static_SB{}; diff --git a/runtime-common/core/core-types/definition/mixed.inl b/runtime-common/core/core-types/definition/mixed.inl index e5c59a88ce..4de7129a27 100644 --- a/runtime-common/core/core-types/definition/mixed.inl +++ b/runtime-common/core/core-types/definition/mixed.inl @@ -4,15 +4,18 @@ #pragma once +#include +#include + #include "common/algorithms/find.h" #include "common/smart_ptrs/intrusive_ptr.h" +#include "runtime-common/core/allocator/script-allocator.h" #include "runtime-common/core/class-instance/refcountable-php-classes.h" #include "runtime-common/core/runtime-core.h" +#include "runtime-common/core/std/containers.h" +#include "runtime-common/core/utils/kphp-assert-core.h" #include "runtime-common/core/utils/migration-php8.h" -#include -#include -#include #ifndef INCLUDED_FROM_KPHP_CORE #error "this file must be included only from runtime-core.h" @@ -177,70 +180,34 @@ inline void swap(mixed& lhs, mixed& rhs) { lhs.swap(rhs); } -template -struct dependent_false : std::false_type {}; - -template -inline constexpr bool dependent_false_v = dependent_false::value; - template T& mixed::empty_value() noexcept { static_assert(vk::is_type_in_list>{} || is_type_acceptable_for_mixed::value, "unsupported type"); auto& ctx{RuntimeContext::get()}; - if constexpr (is_type_acceptable_for_mixed::value) { - auto& type2value{ctx.empty_value.objects}; - const auto it{type2value.find(std::type_index(typeid(T)))}; - if (it != type2value.end()) { - return *reinterpret_cast(it->second); - } - auto* obj{new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}}; - type2value.insert({std::type_index(typeid(T)), static_cast(obj)}); - return *obj; - } else if constexpr (std::is_same_v) { - if (ctx.empty_value.bool_v == nullptr) { - ctx.empty_value.bool_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; - } - return *reinterpret_cast(ctx.empty_value.bool_v); - } else if constexpr (std::is_same_v) { - if (ctx.empty_value.int64_v == nullptr) { - ctx.empty_value.int64_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; - } - return *reinterpret_cast(ctx.empty_value.int64_v); - } else if constexpr (std::is_same_v) { - if (ctx.empty_value.double_v == nullptr) { - ctx.empty_value.double_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; - } - return *reinterpret_cast(ctx.empty_value.double_v); - } else if constexpr (std::is_same_v) { - if (ctx.empty_value.string_v == nullptr) { - ctx.empty_value.string_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; - } - return *reinterpret_cast(ctx.empty_value.string_v); - } else if constexpr (std::is_same_v) { - if (ctx.empty_value.mixed_v == nullptr) { - ctx.empty_value.mixed_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; - } - return *reinterpret_cast(ctx.empty_value.mixed_v); - } else if constexpr (std::is_same_v>) { - if (ctx.empty_value.array_v == nullptr) { - ctx.empty_value.array_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; - } - return *reinterpret_cast(ctx.empty_value.array_v); - } else { - static_assert(dependent_false_v, "Unsupported type provided!"); + + using type2value_t = kphp::stl::unordered_map; + if (ctx.empty_values == nullptr) { + auto* raw_mem{RuntimeAllocator::get().alloc_script_memory(sizeof(type2value_t))}; + php_assert(raw_mem); + ctx.empty_values = new (raw_mem) type2value_t{}; + reinterpret_cast(ctx.empty_values)->reserve(6); // bool, int64_t, double, string, mixed, array + } + + auto* type2value{reinterpret_cast(ctx.empty_values)}; + const auto it{type2value->find(std::type_index(typeid(T)))}; + if (it != type2value->end()) { + *reinterpret_cast(it->second) = T{}; + return *reinterpret_cast(it->second); } + + auto* raw_mem{RuntimeAllocator::get().alloc_script_memory(sizeof(T))}; + php_assert(raw_mem); + return *reinterpret_cast(type2value->insert({std::type_index(typeid(T)), new (raw_mem) T{}}).first->second); } inline void mixed::reset_empty_values() noexcept { - auto& ctx{RuntimeContext::get()}; - ctx.empty_value.objects.clear(); - ctx.empty_value.bool_v = nullptr; - ctx.empty_value.int64_v = nullptr; - ctx.empty_value.double_v = nullptr; - ctx.empty_value.string_v = nullptr; - ctx.empty_value.mixed_v = nullptr; - ctx.empty_value.array_v = nullptr; + RuntimeContext::get().empty_values = nullptr; } template From 6fcf4a90aba797a6982c24811d625c0b039006e5 Mon Sep 17 00:00:00 2001 From: Petr Shumilov Date: Mon, 13 Jul 2026 16:15:54 +0300 Subject: [PATCH 3/7] Improve performance Signed-off-by: Petr Shumilov --- common/type_traits/dependent_false.h | 17 ++++ runtime-common/core/core-context.h | 10 ++- .../core/core-types/definition/mixed.inl | 81 +++++++++++++++---- 3 files changed, 90 insertions(+), 18 deletions(-) create mode 100644 common/type_traits/dependent_false.h diff --git a/common/type_traits/dependent_false.h b/common/type_traits/dependent_false.h new file mode 100644 index 0000000000..00174a5934 --- /dev/null +++ b/common/type_traits/dependent_false.h @@ -0,0 +1,17 @@ +// Compiler for PHP (aka KPHP) +// Copyright (c) 2020 LLC «V Kontakte» +// Distributed under the GPL v3 License, see LICENSE.notice.txt + +#pragma once + +#include + +namespace vk { + +template +struct dependent_false : std::false_type {}; + +template +inline constexpr bool dependent_false_v = dependent_false::value; + +} // namespace vk diff --git a/runtime-common/core/core-context.h b/runtime-common/core/core-context.h index 5baab45526..8e40f9b683 100644 --- a/runtime-common/core/core-context.h +++ b/runtime-common/core/core-context.h @@ -17,7 +17,15 @@ struct RuntimeContext final : vk::not_copyable { int32_t show_migration_php8_warning{}; int32_t php_disable_warnings{}; uint32_t empty_obj_count{}; - void* empty_values{nullptr}; + struct { + void* bool_v{}; + void* int64_v{}; + void* double_v{}; + void* string_v{}; + void* mixed_v{}; + void* array_v{}; + void* objects{}; + } empty_value; string_buffer_lib_context sb_lib_context{}; string_buffer static_SB{}; diff --git a/runtime-common/core/core-types/definition/mixed.inl b/runtime-common/core/core-types/definition/mixed.inl index 4de7129a27..3665bd548c 100644 --- a/runtime-common/core/core-types/definition/mixed.inl +++ b/runtime-common/core/core-types/definition/mixed.inl @@ -9,6 +9,7 @@ #include "common/algorithms/find.h" #include "common/smart_ptrs/intrusive_ptr.h" +#include "common/type_traits/dependent_false.h" #include "runtime-common/core/allocator/script-allocator.h" #include "runtime-common/core/class-instance/refcountable-php-classes.h" @@ -185,29 +186,75 @@ T& mixed::empty_value() noexcept { static_assert(vk::is_type_in_list>{} || is_type_acceptable_for_mixed::value, "unsupported type"); auto& ctx{RuntimeContext::get()}; + if constexpr (std::is_same_v) { + if (ctx.empty_value.bool_v == nullptr) { + ctx.empty_value.bool_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; + } + *reinterpret_cast(ctx.empty_value.bool_v) = T{}; + return *reinterpret_cast(ctx.empty_value.bool_v); + } else if constexpr (std::is_same_v) { + if (ctx.empty_value.int64_v == nullptr) { + ctx.empty_value.int64_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; + } + *reinterpret_cast(ctx.empty_value.int64_v) = T{}; + return *reinterpret_cast(ctx.empty_value.int64_v); + } else if constexpr (std::is_same_v) { + if (ctx.empty_value.double_v == nullptr) { + ctx.empty_value.double_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; + } + *reinterpret_cast(ctx.empty_value.double_v) = T{}; + return *reinterpret_cast(ctx.empty_value.double_v); + } else if constexpr (std::is_same_v) { + if (ctx.empty_value.string_v == nullptr) { + ctx.empty_value.string_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; + } + *reinterpret_cast(ctx.empty_value.string_v) = T{}; + return *reinterpret_cast(ctx.empty_value.string_v); + } else if constexpr (std::is_same_v) { + if (ctx.empty_value.mixed_v == nullptr) { + ctx.empty_value.mixed_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; + } + *reinterpret_cast(ctx.empty_value.mixed_v) = T{}; + return *reinterpret_cast(ctx.empty_value.mixed_v); + } else if constexpr (std::is_same_v>) { + if (ctx.empty_value.array_v == nullptr) { + ctx.empty_value.array_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; + } + *reinterpret_cast(ctx.empty_value.array_v) = T{}; + return *reinterpret_cast(ctx.empty_value.array_v); + } else if constexpr (is_type_acceptable_for_mixed::value) { + using type2value_t = kphp::stl::unordered_map; + if (ctx.empty_value.objects == nullptr) { + auto* raw_mem{RuntimeAllocator::get().alloc_script_memory(sizeof(type2value_t))}; + php_assert(raw_mem); + ctx.empty_value.objects = new (raw_mem) type2value_t{}; + } - using type2value_t = kphp::stl::unordered_map; - if (ctx.empty_values == nullptr) { - auto* raw_mem{RuntimeAllocator::get().alloc_script_memory(sizeof(type2value_t))}; - php_assert(raw_mem); - ctx.empty_values = new (raw_mem) type2value_t{}; - reinterpret_cast(ctx.empty_values)->reserve(6); // bool, int64_t, double, string, mixed, array - } + auto* type2value{reinterpret_cast(ctx.empty_value.objects)}; + const auto type_id{std::type_index{typeid(T)}}; + const auto it{type2value->find(type_id)}; + if (it != type2value->end()) { + *reinterpret_cast(it->second) = T{}; + return *reinterpret_cast(it->second); + } - auto* type2value{reinterpret_cast(ctx.empty_values)}; - const auto it{type2value->find(std::type_index(typeid(T)))}; - if (it != type2value->end()) { - *reinterpret_cast(it->second) = T{}; - return *reinterpret_cast(it->second); + auto* raw_mem{RuntimeAllocator::get().alloc_script_memory(sizeof(T))}; + php_assert(raw_mem); + return *reinterpret_cast(type2value->insert({type_id, new (raw_mem) T{}}).first->second); + } else { + static_assert(vk::dependent_false_v, "Unsupported type provided"); } - - auto* raw_mem{RuntimeAllocator::get().alloc_script_memory(sizeof(T))}; - php_assert(raw_mem); - return *reinterpret_cast(type2value->insert({std::type_index(typeid(T)), new (raw_mem) T{}}).first->second); } inline void mixed::reset_empty_values() noexcept { - RuntimeContext::get().empty_values = nullptr; + auto& ctx{RuntimeContext::get()}; + ctx.empty_value.bool_v = nullptr; + ctx.empty_value.int64_v = nullptr; + ctx.empty_value.double_v = nullptr; + ctx.empty_value.string_v = nullptr; + ctx.empty_value.mixed_v = nullptr; + ctx.empty_value.array_v = nullptr; + ctx.empty_value.objects = nullptr; } template From cb8e53e2d76bc62ba8ce18ca7d3c2e70e4423c74 Mon Sep 17 00:00:00 2001 From: Petr Shumilov Date: Mon, 13 Jul 2026 16:39:12 +0300 Subject: [PATCH 4/7] Remove useless type trait Signed-off-by: Petr Shumilov --- common/type_traits/dependent_false.h | 17 ----------------- .../core/core-types/definition/mixed.inl | 5 +---- 2 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 common/type_traits/dependent_false.h diff --git a/common/type_traits/dependent_false.h b/common/type_traits/dependent_false.h deleted file mode 100644 index 00174a5934..0000000000 --- a/common/type_traits/dependent_false.h +++ /dev/null @@ -1,17 +0,0 @@ -// Compiler for PHP (aka KPHP) -// Copyright (c) 2020 LLC «V Kontakte» -// Distributed under the GPL v3 License, see LICENSE.notice.txt - -#pragma once - -#include - -namespace vk { - -template -struct dependent_false : std::false_type {}; - -template -inline constexpr bool dependent_false_v = dependent_false::value; - -} // namespace vk diff --git a/runtime-common/core/core-types/definition/mixed.inl b/runtime-common/core/core-types/definition/mixed.inl index 3665bd548c..6743bf9199 100644 --- a/runtime-common/core/core-types/definition/mixed.inl +++ b/runtime-common/core/core-types/definition/mixed.inl @@ -9,7 +9,6 @@ #include "common/algorithms/find.h" #include "common/smart_ptrs/intrusive_ptr.h" -#include "common/type_traits/dependent_false.h" #include "runtime-common/core/allocator/script-allocator.h" #include "runtime-common/core/class-instance/refcountable-php-classes.h" @@ -222,7 +221,7 @@ T& mixed::empty_value() noexcept { } *reinterpret_cast(ctx.empty_value.array_v) = T{}; return *reinterpret_cast(ctx.empty_value.array_v); - } else if constexpr (is_type_acceptable_for_mixed::value) { + } else { using type2value_t = kphp::stl::unordered_map; if (ctx.empty_value.objects == nullptr) { auto* raw_mem{RuntimeAllocator::get().alloc_script_memory(sizeof(type2value_t))}; @@ -241,8 +240,6 @@ T& mixed::empty_value() noexcept { auto* raw_mem{RuntimeAllocator::get().alloc_script_memory(sizeof(T))}; php_assert(raw_mem); return *reinterpret_cast(type2value->insert({type_id, new (raw_mem) T{}}).first->second); - } else { - static_assert(vk::dependent_false_v, "Unsupported type provided"); } } From f13867c791433992df2e0098688bb45ac1180ea7 Mon Sep 17 00:00:00 2001 From: Petr Shumilov Date: Mon, 13 Jul 2026 16:55:23 +0300 Subject: [PATCH 5/7] Fix code style Signed-off-by: Petr Shumilov --- runtime-common/core/core-types/definition/mixed.inl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/runtime-common/core/core-types/definition/mixed.inl b/runtime-common/core/core-types/definition/mixed.inl index 6743bf9199..94439d1902 100644 --- a/runtime-common/core/core-types/definition/mixed.inl +++ b/runtime-common/core/core-types/definition/mixed.inl @@ -232,14 +232,14 @@ T& mixed::empty_value() noexcept { auto* type2value{reinterpret_cast(ctx.empty_value.objects)}; const auto type_id{std::type_index{typeid(T)}}; const auto it{type2value->find(type_id)}; - if (it != type2value->end()) { - *reinterpret_cast(it->second) = T{}; - return *reinterpret_cast(it->second); + if (it == type2value->end()) { + auto* raw_mem{RuntimeAllocator::get().alloc_script_memory(sizeof(T))}; + php_assert(raw_mem); + return *reinterpret_cast(type2value->insert({type_id, new (raw_mem) T{}}).first->second); } - auto* raw_mem{RuntimeAllocator::get().alloc_script_memory(sizeof(T))}; - php_assert(raw_mem); - return *reinterpret_cast(type2value->insert({type_id, new (raw_mem) T{}}).first->second); + *reinterpret_cast(it->second) = T{}; + return *reinterpret_cast(it->second); } } From a043efb21a93c412d8c6fc145424a56e6e754aa1 Mon Sep 17 00:00:00 2001 From: Petr Shumilov Date: Mon, 13 Jul 2026 17:47:03 +0300 Subject: [PATCH 6/7] Add test Signed-off-by: Petr Shumilov --- .../001_set_value_for_empty_value.php | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tests/phpt/mixed/primitive/001_set_value_for_empty_value.php diff --git a/tests/phpt/mixed/primitive/001_set_value_for_empty_value.php b/tests/phpt/mixed/primitive/001_set_value_for_empty_value.php new file mode 100644 index 0000000000..86473bbbd5 --- /dev/null +++ b/tests/phpt/mixed/primitive/001_set_value_for_empty_value.php @@ -0,0 +1,43 @@ +@ok + $v) { + // ($arr[$i]['j']) -- recv + ($arr[$i]['j'])['k'] = true; + } +} + +$try_to_set_value_if_recv_is_string = function () { + /** @var mixed[] $arr */ + $arr = ["foo"]; + + foreach ($arr as $i => $v) { + // ($arr[$i]['j']) -- recv + ($arr[$i]['j'])['k'] = true; + } +}; + +class C{} + +$try_to_set_value_if_recv_is_object = function() { + /** @var mixed[] $arr */ + $arr = [to_mixed(new C())]; + + foreach ($arr as $i => $v) { + // ($arr[$i]['j']) -- recv + ($arr[$i]['j'])['k'] = true; + } +}; + + + +try_to_set_value_if_recv_is_int(); +#ifndef KPHP +$try_to_set_value_if_recv_is_string = function (){}; +$try_to_set_value_if_recv_is_object = function (){}; +#endif +$try_to_set_value_if_recv_is_string(); +$try_to_set_value_if_recv_is_object(); From 47e9636d49741a664612e3260bc64a093ba1f643 Mon Sep 17 00:00:00 2001 From: Petr Shumilov Date: Mon, 13 Jul 2026 19:53:02 +0300 Subject: [PATCH 7/7] Fix code style Signed-off-by: Petr Shumilov --- runtime-common/core/core-context.h | 18 +++--- .../core/core-types/definition/mixed.inl | 62 +++++++------------ 2 files changed, 35 insertions(+), 45 deletions(-) diff --git a/runtime-common/core/core-context.h b/runtime-common/core/core-context.h index 8e40f9b683..eefc924655 100644 --- a/runtime-common/core/core-context.h +++ b/runtime-common/core/core-context.h @@ -9,6 +9,10 @@ #include "common/mixin/not_copyable.h" +#include "runtime-common/core/allocator/script-allocator.h" +#include "runtime-common/core/runtime-core.h" +#include "runtime-common/core/std/containers.h" + #ifndef INCLUDED_FROM_KPHP_CORE #error "this file must be included only from runtime-core.h" #endif @@ -18,13 +22,13 @@ struct RuntimeContext final : vk::not_copyable { int32_t php_disable_warnings{}; uint32_t empty_obj_count{}; struct { - void* bool_v{}; - void* int64_v{}; - void* double_v{}; - void* string_v{}; - void* mixed_v{}; - void* array_v{}; - void* objects{}; + bool* bool_v{}; + int64_t* int64_v{}; + double* double_v{}; + string* string_v{}; + mixed* mixed_v{}; + array* array_v{}; + kphp::stl::unordered_map* objects{}; } empty_value; string_buffer_lib_context sb_lib_context{}; diff --git a/runtime-common/core/core-types/definition/mixed.inl b/runtime-common/core/core-types/definition/mixed.inl index 94439d1902..6fa50d2978 100644 --- a/runtime-common/core/core-types/definition/mixed.inl +++ b/runtime-common/core/core-types/definition/mixed.inl @@ -5,7 +5,7 @@ #pragma once #include -#include +#include #include "common/algorithms/find.h" #include "common/smart_ptrs/intrusive_ptr.h" @@ -183,59 +183,45 @@ inline void swap(mixed& lhs, mixed& rhs) { template T& mixed::empty_value() noexcept { static_assert(vk::is_type_in_list>{} || is_type_acceptable_for_mixed::value, "unsupported type"); - auto& ctx{RuntimeContext::get()}; - if constexpr (std::is_same_v) { - if (ctx.empty_value.bool_v == nullptr) { - ctx.empty_value.bool_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; + + const auto init_empty_value{[](T*& v) noexcept -> T& { + if (v == nullptr) { + auto* raw_mem{RuntimeAllocator::get().alloc_script_memory(sizeof(T))}; + php_assert(raw_mem); + v = new (raw_mem) T{}; } - *reinterpret_cast(ctx.empty_value.bool_v) = T{}; - return *reinterpret_cast(ctx.empty_value.bool_v); + *reinterpret_cast(v) = T{}; + return *reinterpret_cast(v); + }}; + + if constexpr (std::is_same_v) { + return init_empty_value(ctx.empty_value.bool_v); } else if constexpr (std::is_same_v) { - if (ctx.empty_value.int64_v == nullptr) { - ctx.empty_value.int64_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; - } - *reinterpret_cast(ctx.empty_value.int64_v) = T{}; - return *reinterpret_cast(ctx.empty_value.int64_v); + return init_empty_value(ctx.empty_value.int64_v); } else if constexpr (std::is_same_v) { - if (ctx.empty_value.double_v == nullptr) { - ctx.empty_value.double_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; - } - *reinterpret_cast(ctx.empty_value.double_v) = T{}; - return *reinterpret_cast(ctx.empty_value.double_v); + return init_empty_value(ctx.empty_value.double_v); } else if constexpr (std::is_same_v) { - if (ctx.empty_value.string_v == nullptr) { - ctx.empty_value.string_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; - } - *reinterpret_cast(ctx.empty_value.string_v) = T{}; - return *reinterpret_cast(ctx.empty_value.string_v); + return init_empty_value(ctx.empty_value.string_v); } else if constexpr (std::is_same_v) { - if (ctx.empty_value.mixed_v == nullptr) { - ctx.empty_value.mixed_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; - } - *reinterpret_cast(ctx.empty_value.mixed_v) = T{}; - return *reinterpret_cast(ctx.empty_value.mixed_v); + return init_empty_value(ctx.empty_value.mixed_v); } else if constexpr (std::is_same_v>) { - if (ctx.empty_value.array_v == nullptr) { - ctx.empty_value.array_v = new (RuntimeAllocator::get().alloc_script_memory(sizeof(T))) T{}; - } - *reinterpret_cast(ctx.empty_value.array_v) = T{}; - return *reinterpret_cast(ctx.empty_value.array_v); + return init_empty_value(ctx.empty_value.array_v); } else { - using type2value_t = kphp::stl::unordered_map; + using type2value_t = kphp::stl::unordered_map; if (ctx.empty_value.objects == nullptr) { auto* raw_mem{RuntimeAllocator::get().alloc_script_memory(sizeof(type2value_t))}; php_assert(raw_mem); ctx.empty_value.objects = new (raw_mem) type2value_t{}; } - auto* type2value{reinterpret_cast(ctx.empty_value.objects)}; - const auto type_id{std::type_index{typeid(T)}}; - const auto it{type2value->find(type_id)}; - if (it == type2value->end()) { + static const char dummy = 0; + const void* type_id{&dummy}; + const auto it{ctx.empty_value.objects->find(type_id)}; + if (it == ctx.empty_value.objects->end()) { auto* raw_mem{RuntimeAllocator::get().alloc_script_memory(sizeof(T))}; php_assert(raw_mem); - return *reinterpret_cast(type2value->insert({type_id, new (raw_mem) T{}}).first->second); + return *reinterpret_cast(ctx.empty_value.objects->insert({type_id, new (raw_mem) T{}}).first->second); } *reinterpret_cast(it->second) = T{};