From 80356e4e741baf0ebc1410cad746aa5ab4812517 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 18 Feb 2023 21:19:41 +0100 Subject: [PATCH 1/8] zend_compiler, ...: use `uint8_t` instead of `zend_uchar` `zend_uchar` suggests that the value is an ASCII character, but here, it's about very small integers. This is misleading, so let's use a C99 integer instead. On all architectures currently supported by PHP, `zend_uchar` and `uint8_t` are identical. This change is only about code readability. From 0883b72cca0a8012d6d1fbb46d7691ac1f29cb64 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 13 Jan 2023 19:22:53 +0100 Subject: [PATCH 2/8] Zend/zend_types.h: move `zend_rc_debug` to `zend_rc_debug.h` `zend_rc_debug` is not a type and does not really belong in `zend_types.h`; this allows using `ZEND_RC_MOD_CHECK()` without including the huge `zend_types.h` header and allows decoupling circular header dependencies. --- Zend/zend.c | 4 ---- Zend/zend_API.c | 1 + Zend/zend_rc_debug.c | 21 ++++++++++++++++ Zend/zend_rc_debug.h | 53 +++++++++++++++++++++++++++++++++++++++++ Zend/zend_string.c | 1 + Zend/zend_types.h | 19 +-------------- configure.ac | 1 + main/main.c | 1 + main/php.h | 1 + main/php_ini.c | 1 + sapi/fpm/fpm/fpm_main.c | 1 + 11 files changed, 82 insertions(+), 22 deletions(-) create mode 100644 Zend/zend_rc_debug.c create mode 100644 Zend/zend_rc_debug.h diff --git a/Zend/zend.c b/Zend/zend.c index 2e37bdb285271..9bfd9178f52b2 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -94,10 +94,6 @@ void (*zend_on_timeout)(int seconds); static void (*zend_message_dispatcher_p)(zend_long message, const void *data); static zval *(*zend_get_configuration_directive_p)(zend_string *name); -#if ZEND_RC_DEBUG -ZEND_API bool zend_rc_debug = 0; -#endif - static ZEND_INI_MH(OnUpdateErrorReporting) /* {{{ */ { if (!new_value) { diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 2f5f2a751ae3c..9ebabbf652698 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -32,6 +32,7 @@ #include "zend_ini.h" #include "zend_enum.h" #include "zend_observer.h" +#include "zend_rc_debug.h" #include diff --git a/Zend/zend_rc_debug.c b/Zend/zend_rc_debug.c new file mode 100644 index 0000000000000..190fcde74c216 --- /dev/null +++ b/Zend/zend_rc_debug.c @@ -0,0 +1,21 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ +*/ + +#include "zend_rc_debug.h" + +#if ZEND_RC_DEBUG +ZEND_API bool zend_rc_debug = false; +#endif diff --git a/Zend/zend_rc_debug.h b/Zend/zend_rc_debug.h new file mode 100644 index 0000000000000..df033d36fa84f --- /dev/null +++ b/Zend/zend_rc_debug.h @@ -0,0 +1,53 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_RC_DEBUG_H +#define ZEND_RC_DEBUG_H + +#ifndef ZEND_RC_DEBUG +# define ZEND_RC_DEBUG 0 +#endif + +#if ZEND_RC_DEBUG + +#ifdef PHP_WIN32 +# include "zend_config.w32.h" +#else +# include "zend_config.h" +#endif + +#include +#include + +extern ZEND_API bool zend_rc_debug; + +/* The GC_PERSISTENT flag is reused for IS_OBJ_WEAKLY_REFERENCED on objects. + * Skip checks for OBJECT/NULL type to avoid interpreting the flag incorrectly. */ +# define ZEND_RC_MOD_CHECK(p) do { \ + if (zend_rc_debug) { \ + uint8_t type = zval_gc_type((p)->u.type_info); \ + if (type != IS_OBJECT && type != IS_NULL) { \ + ZEND_ASSERT(!(zval_gc_flags((p)->u.type_info) & GC_IMMUTABLE)); \ + ZEND_ASSERT((zval_gc_flags((p)->u.type_info) & (GC_PERSISTENT|GC_PERSISTENT_LOCAL)) != GC_PERSISTENT); \ + } \ + } \ + } while (0) +#else +# define ZEND_RC_MOD_CHECK(p) \ + do { } while (0) +#endif + +#endif /* ZEND_RC_DEBUG_H */ diff --git a/Zend/zend_string.c b/Zend/zend_string.c index d65101e778c14..ddb8ff1bb84fe 100644 --- a/Zend/zend_string.c +++ b/Zend/zend_string.c @@ -18,6 +18,7 @@ #include "zend.h" #include "zend_globals.h" +#include "zend_rc_debug.h" #ifdef HAVE_VALGRIND # include "valgrind/callgrind.h" diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 7ba5f8625c1b2..034ea96f0c09e 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -24,6 +24,7 @@ #include "zend_portability.h" #include "zend_long.h" +#include "zend_rc_debug.h" #include "zend_result.h" #include @@ -1161,29 +1162,11 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { #define Z_TRY_ADDREF(z) Z_TRY_ADDREF_P(&(z)) #define Z_TRY_DELREF(z) Z_TRY_DELREF_P(&(z)) -#ifndef ZEND_RC_DEBUG -# define ZEND_RC_DEBUG 0 -#endif - #if ZEND_RC_DEBUG -extern ZEND_API bool zend_rc_debug; -/* The GC_PERSISTENT flag is reused for IS_OBJ_WEAKLY_REFERENCED on objects. - * Skip checks for OBJECT/NULL type to avoid interpreting the flag incorrectly. */ -# define ZEND_RC_MOD_CHECK(p) do { \ - if (zend_rc_debug) { \ - uint8_t type = zval_gc_type((p)->u.type_info); \ - if (type != IS_OBJECT && type != IS_NULL) { \ - ZEND_ASSERT(!(zval_gc_flags((p)->u.type_info) & GC_IMMUTABLE)); \ - ZEND_ASSERT((zval_gc_flags((p)->u.type_info) & (GC_PERSISTENT|GC_PERSISTENT_LOCAL)) != GC_PERSISTENT); \ - } \ - } \ - } while (0) # define GC_MAKE_PERSISTENT_LOCAL(p) do { \ GC_ADD_FLAGS(p, GC_PERSISTENT_LOCAL); \ } while (0) #else -# define ZEND_RC_MOD_CHECK(p) \ - do { } while (0) # define GC_MAKE_PERSISTENT_LOCAL(p) \ do { } while (0) #endif diff --git a/configure.ac b/configure.ac index 3970d6d77bd38..3ac52ef98a552 100644 --- a/configure.ac +++ b/configure.ac @@ -1722,6 +1722,7 @@ PHP_ADD_SOURCES(Zend, \ zend_virtual_cwd.c zend_ast.c zend_objects.c zend_object_handlers.c zend_objects_API.c \ zend_default_classes.c zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_gdb.c \ zend_observer.c zend_system_id.c zend_enum.c zend_fibers.c zend_atomic.c \ + zend_rc_debug.c \ Optimizer/zend_optimizer.c \ Optimizer/pass1.c \ Optimizer/pass3.c \ diff --git a/main/main.c b/main/main.c index c0a71b2afa9bd..8e09f4cd4c0b2 100644 --- a/main/main.c +++ b/main/main.c @@ -71,6 +71,7 @@ #include "zend_ini.h" #include "zend_dtrace.h" #include "zend_observer.h" +#include "zend_rc_debug.h" #include "zend_system_id.h" #include "php_content_types.h" diff --git a/main/php.h b/main/php.h index 3385fb799927e..c3d139059c48f 100644 --- a/main/php.h +++ b/main/php.h @@ -29,6 +29,7 @@ #include "php_version.h" #include "zend.h" +#include "zend_rc_debug.h" #include "zend_sort.h" #include "php_compat.h" diff --git a/main/php_ini.c b/main/php_ini.c index 82420fd0bc600..68304f42c5da4 100644 --- a/main/php_ini.c +++ b/main/php_ini.c @@ -22,6 +22,7 @@ #include "ext/standard/dl.h" #include "zend_extensions.h" #include "zend_highlight.h" +#include "zend_rc_debug.h" #include "SAPI.h" #include "php_main.h" #include "php_scandir.h" diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c index 5ba629b395fcb..5f47dd8efcc22 100644 --- a/sapi/fpm/fpm/fpm_main.c +++ b/sapi/fpm/fpm/fpm_main.c @@ -27,6 +27,7 @@ #include "php.h" #include "zend_ini_scanner.h" #include "zend_globals.h" +#include "zend_rc_debug.h" #include "zend_stream.h" #include "SAPI.h" From 913c9c922fcb2a9cbbd8bd43ebbd0f8fbdc71b1d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 13 Jan 2023 19:30:42 +0100 Subject: [PATCH 3/8] Zend/zend_rc_debug: convert `ZEND_RC_MOD_CHECK()` to function This allows using `ZEND_RC_MOD_CHECK()` without including any additional headers. Performance is not relevant here because this is a debug-only feature. The `zend_refcounted_h` forward declaration is necessary to break a circular header dependency. --- Zend/zend_rc_debug.c | 21 +++++++++++++++++++++ Zend/zend_rc_debug.h | 21 ++++++++++----------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/Zend/zend_rc_debug.c b/Zend/zend_rc_debug.c index 190fcde74c216..3efd60c0f665d 100644 --- a/Zend/zend_rc_debug.c +++ b/Zend/zend_rc_debug.c @@ -17,5 +17,26 @@ #include "zend_rc_debug.h" #if ZEND_RC_DEBUG + +#include "zend_types.h" + ZEND_API bool zend_rc_debug = false; + +ZEND_API void ZEND_RC_MOD_CHECK(const zend_refcounted_h *p) +{ + if (!zend_rc_debug) { + return; + } + + uint8_t type = zval_gc_type(p->u.type_info); + + /* Skip checks for OBJECT/NULL type to avoid interpreting the flag incorrectly. */ + if (type != IS_OBJECT && type != IS_NULL) { + ZEND_ASSERT(!(zval_gc_flags(p->u.type_info) & GC_IMMUTABLE)); + + /* The GC_PERSISTENT flag is reused for IS_OBJ_WEAKLY_REFERENCED on objects. */ + ZEND_ASSERT((zval_gc_flags(p->u.type_info) & (GC_PERSISTENT|GC_PERSISTENT_LOCAL)) != GC_PERSISTENT); + } +} + #endif diff --git a/Zend/zend_rc_debug.h b/Zend/zend_rc_debug.h index df033d36fa84f..345b67b1f9380 100644 --- a/Zend/zend_rc_debug.h +++ b/Zend/zend_rc_debug.h @@ -32,19 +32,18 @@ #include #include +#include "zend_portability.h" + +typedef struct _zend_refcounted_h zend_refcounted_h; + extern ZEND_API bool zend_rc_debug; -/* The GC_PERSISTENT flag is reused for IS_OBJ_WEAKLY_REFERENCED on objects. - * Skip checks for OBJECT/NULL type to avoid interpreting the flag incorrectly. */ -# define ZEND_RC_MOD_CHECK(p) do { \ - if (zend_rc_debug) { \ - uint8_t type = zval_gc_type((p)->u.type_info); \ - if (type != IS_OBJECT && type != IS_NULL) { \ - ZEND_ASSERT(!(zval_gc_flags((p)->u.type_info) & GC_IMMUTABLE)); \ - ZEND_ASSERT((zval_gc_flags((p)->u.type_info) & (GC_PERSISTENT|GC_PERSISTENT_LOCAL)) != GC_PERSISTENT); \ - } \ - } \ - } while (0) +BEGIN_EXTERN_C() + +ZEND_API void ZEND_RC_MOD_CHECK(const zend_refcounted_h *p); + +END_EXTERN_C() + #else # define ZEND_RC_MOD_CHECK(p) \ do { } while (0) From 365fd6f0b1237b07c93ca826780b6518a616522a Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 21 Feb 2023 20:33:32 +0100 Subject: [PATCH 4/8] Zend/zend_types.h: move `IS_*` to `zend_type_code.h` More decoupling of circular header dependencies. --- Zend/zend.h | 1 + Zend/zend_API.h | 2 +- Zend/zend_execute.h | 1 + Zend/zend_hash.h | 1 + Zend/zend_type_code.h | 58 +++++++++++++++++++++++++++++++++++++++++++ Zend/zend_types.h | 39 +---------------------------- 6 files changed, 63 insertions(+), 39 deletions(-) create mode 100644 Zend/zend_type_code.h diff --git a/Zend/zend.h b/Zend/zend.h index 3eaf62ace1157..a0c0fc2126d3b 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -39,6 +39,7 @@ #include "zend_smart_str_public.h" #include "zend_smart_string_public.h" #include "zend_signal.h" +#include "zend_type_code.h" #define zend_sprintf sprintf diff --git a/Zend/zend_API.h b/Zend/zend_API.h index ca33e96656bca..ab58f7db72d49 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -28,7 +28,7 @@ #include "zend_variables.h" #include "zend_execute.h" #include "zend_type_info.h" - +#include "zend_type_code.h" BEGIN_EXTERN_C() diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 2370c3045fc67..db6bdaff86f63 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -24,6 +24,7 @@ #include "zend_compile.h" #include "zend_hash.h" #include "zend_operators.h" +#include "zend_type_code.h" #include "zend_variables.h" #include diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index d9210d073182f..dfcf9c0c8b508 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -23,6 +23,7 @@ #include "zend.h" #include "zend_sort.h" +#include "zend_type_code.h" #define HASH_KEY_IS_STRING 1 #define HASH_KEY_IS_LONG 2 diff --git a/Zend/zend_type_code.h b/Zend/zend_type_code.h new file mode 100644 index 0000000000000..d0a14fc821bab --- /dev/null +++ b/Zend/zend_type_code.h @@ -0,0 +1,58 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_TYPE_CODE_H +#define ZEND_TYPE_CODE_H + +/* Regular data types: Must be in sync with zend_variables.c. */ +#define IS_UNDEF 0 +#define IS_NULL 1 +#define IS_FALSE 2 +#define IS_TRUE 3 +#define IS_LONG 4 +#define IS_DOUBLE 5 +#define IS_STRING 6 +#define IS_ARRAY 7 +#define IS_OBJECT 8 +#define IS_RESOURCE 9 +#define IS_REFERENCE 10 +#define IS_CONSTANT_AST 11 /* Constant expressions */ + +/* Fake types used only for type hinting. + * These are allowed to overlap with the types below. */ +#define IS_CALLABLE 12 +#define IS_ITERABLE 13 +#define IS_VOID 14 +#define IS_STATIC 15 +#define IS_MIXED 16 +#define IS_NEVER 17 + +/* internal types */ +#define IS_INDIRECT 12 +#define IS_PTR 13 +#define IS_ALIAS_PTR 14 +#define _IS_ERROR 15 + +/* used for casts */ +#define _IS_BOOL 18 +#define _IS_NUMBER 19 + +#define ZEND_SAME_FAKE_TYPE(faketype, realtype) ( \ + (faketype) == (realtype) \ + || ((faketype) == _IS_BOOL && ((realtype) == IS_TRUE || (realtype) == IS_FALSE)) \ +) + +#endif /* ZEND_TYPE_CODE_H */ diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 034ea96f0c09e..d8a3fc0edf0da 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -26,6 +26,7 @@ #include "zend_long.h" #include "zend_rc_debug.h" #include "zend_result.h" +#include "zend_type_code.h" #include #include @@ -538,48 +539,10 @@ struct _zend_ast_ref { /*zend_ast ast; zend_ast follows the zend_ast_ref structure */ }; -/* Regular data types: Must be in sync with zend_variables.c. */ -#define IS_UNDEF 0 -#define IS_NULL 1 -#define IS_FALSE 2 -#define IS_TRUE 3 -#define IS_LONG 4 -#define IS_DOUBLE 5 -#define IS_STRING 6 -#define IS_ARRAY 7 -#define IS_OBJECT 8 -#define IS_RESOURCE 9 -#define IS_REFERENCE 10 -#define IS_CONSTANT_AST 11 /* Constant expressions */ - -/* Fake types used only for type hinting. - * These are allowed to overlap with the types below. */ -#define IS_CALLABLE 12 -#define IS_ITERABLE 13 -#define IS_VOID 14 -#define IS_STATIC 15 -#define IS_MIXED 16 -#define IS_NEVER 17 - -/* internal types */ -#define IS_INDIRECT 12 -#define IS_PTR 13 -#define IS_ALIAS_PTR 14 -#define _IS_ERROR 15 - -/* used for casts */ -#define _IS_BOOL 18 -#define _IS_NUMBER 19 - static zend_always_inline uint8_t zval_get_type(const zval* pz) { return pz->u1.v.type; } -#define ZEND_SAME_FAKE_TYPE(faketype, realtype) ( \ - (faketype) == (realtype) \ - || ((faketype) == _IS_BOOL && ((realtype) == IS_TRUE || (realtype) == IS_FALSE)) \ -) - /* we should never set just Z_TYPE, we should set Z_TYPE_INFO */ #define Z_TYPE(zval) zval_get_type(&(zval)) #define Z_TYPE_P(zval_p) Z_TYPE(*(zval_p)) From a849b016b2f62039e47ba2e5d8a5c0d61ca01bc3 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 21 Feb 2023 20:37:22 +0100 Subject: [PATCH 5/8] Zend/zend_type_code.h: convert to `enum` --- Zend/zend_type_code.h | 60 ++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/Zend/zend_type_code.h b/Zend/zend_type_code.h index d0a14fc821bab..6ed86ab76313b 100644 --- a/Zend/zend_type_code.h +++ b/Zend/zend_type_code.h @@ -17,38 +17,40 @@ #ifndef ZEND_TYPE_CODE_H #define ZEND_TYPE_CODE_H -/* Regular data types: Must be in sync with zend_variables.c. */ -#define IS_UNDEF 0 -#define IS_NULL 1 -#define IS_FALSE 2 -#define IS_TRUE 3 -#define IS_LONG 4 -#define IS_DOUBLE 5 -#define IS_STRING 6 -#define IS_ARRAY 7 -#define IS_OBJECT 8 -#define IS_RESOURCE 9 -#define IS_REFERENCE 10 -#define IS_CONSTANT_AST 11 /* Constant expressions */ +enum { + /* Regular data types: Must be in sync with zend_variables.c. */ + IS_UNDEF = 0, + IS_NULL = 1, + IS_FALSE = 2, + IS_TRUE = 3, + IS_LONG = 4, + IS_DOUBLE = 5, + IS_STRING = 6, + IS_ARRAY = 7, + IS_OBJECT = 8, + IS_RESOURCE = 9, + IS_REFERENCE = 10, + IS_CONSTANT_AST = 11, /* Constant expressions */ -/* Fake types used only for type hinting. - * These are allowed to overlap with the types below. */ -#define IS_CALLABLE 12 -#define IS_ITERABLE 13 -#define IS_VOID 14 -#define IS_STATIC 15 -#define IS_MIXED 16 -#define IS_NEVER 17 + /* Fake types used only for type hinting. + * These are allowed to overlap with the types below. */ + IS_CALLABLE = 12, + IS_ITERABLE = 13, + IS_VOID = 14, + IS_STATIC = 15, + IS_MIXED = 16, + IS_NEVER = 17, -/* internal types */ -#define IS_INDIRECT 12 -#define IS_PTR 13 -#define IS_ALIAS_PTR 14 -#define _IS_ERROR 15 + /* internal types */ + IS_INDIRECT = 12, + IS_PTR = 13, + IS_ALIAS_PTR = 14, + _IS_ERROR = 15, -/* used for casts */ -#define _IS_BOOL 18 -#define _IS_NUMBER 19 + /* used for casts */ + _IS_BOOL = 18, + _IS_NUMBER = 19, +}; #define ZEND_SAME_FAKE_TYPE(faketype, realtype) ( \ (faketype) == (realtype) \ From e4c4d1d37193841a1ab4caa164d575767baef7ea Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 13 Jan 2023 18:17:53 +0100 Subject: [PATCH 6/8] Zend/zend_types.h: move `zend_refcounted` to `zend_refcounted.h` This is necessary for splitting `zend_types.h` further. --- Zend/zend_refcounted.h | 137 +++++++++++++++++++++++++++++++++++++++++ Zend/zend_types.h | 95 +--------------------------- 2 files changed, 138 insertions(+), 94 deletions(-) create mode 100644 Zend/zend_refcounted.h diff --git a/Zend/zend_refcounted.h b/Zend/zend_refcounted.h new file mode 100644 index 0000000000000..e4ffc99568530 --- /dev/null +++ b/Zend/zend_refcounted.h @@ -0,0 +1,137 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_REFCOUNTED_H +#define ZEND_REFCOUNTED_H + +#include "zend_portability.h" +#include "zend_rc_debug.h" +#include "zend_type_code.h" + +#include + +#define GC_TYPE_MASK 0x0000000f +#define GC_FLAGS_MASK 0x000003f0 +#define GC_INFO_MASK 0xfffffc00 +#define GC_FLAGS_SHIFT 0 +#define GC_INFO_SHIFT 10 + +/* zval_gc_flags(zval.value->gc.u.type_info) (common flags) */ +#define GC_NOT_COLLECTABLE (1<<4) +#define GC_PROTECTED (1<<5) /* used for recursion detection */ +#define GC_IMMUTABLE (1<<6) /* can't be changed in place */ +#define GC_PERSISTENT (1<<7) /* allocated using malloc */ +#define GC_PERSISTENT_LOCAL (1<<8) /* persistent, but thread-local */ + +#define GC_TYPE_INFO(p) (p)->gc.u.type_info +#define GC_TYPE(p) zval_gc_type(GC_TYPE_INFO(p)) +#define GC_FLAGS(p) zval_gc_flags(GC_TYPE_INFO(p)) +#define GC_INFO(p) zval_gc_info(GC_TYPE_INFO(p)) + +#define GC_ADD_FLAGS(p, flags) do { \ + GC_TYPE_INFO(p) |= (flags) << GC_FLAGS_SHIFT; \ + } while (0) +#define GC_DEL_FLAGS(p, flags) do { \ + GC_TYPE_INFO(p) &= ~((flags) << GC_FLAGS_SHIFT); \ + } while (0) + +#define GC_REFCOUNT(p) zend_gc_refcount(&(p)->gc) +#define GC_SET_REFCOUNT(p, rc) zend_gc_set_refcount(&(p)->gc, rc) +#define GC_ADDREF(p) zend_gc_addref(&(p)->gc) +#define GC_DELREF(p) zend_gc_delref(&(p)->gc) +#define GC_ADDREF_EX(p, rc) zend_gc_addref_ex(&(p)->gc, rc) +#define GC_DELREF_EX(p, rc) zend_gc_delref_ex(&(p)->gc, rc) +#define GC_TRY_ADDREF(p) zend_gc_try_addref(&(p)->gc) +#define GC_TRY_DELREF(p) zend_gc_try_delref(&(p)->gc) + +#define GC_NULL (IS_NULL | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT)) +#define GC_STRING (IS_STRING | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT)) +#define GC_ARRAY IS_ARRAY +#define GC_OBJECT IS_OBJECT +#define GC_RESOURCE (IS_RESOURCE | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT)) +#define GC_REFERENCE (IS_REFERENCE | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT)) +#define GC_CONSTANT_AST (IS_CONSTANT_AST | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT)) + +typedef struct _zend_refcounted_h { + uint32_t refcount; /* reference counter 32-bit */ + union { + uint32_t type_info; + } u; +} zend_refcounted_h; + +typedef struct _zend_refcounted { + zend_refcounted_h gc; +} zend_refcounted; + +static zend_always_inline uint8_t zval_gc_type(uint32_t gc_type_info) { + return (gc_type_info & GC_TYPE_MASK); +} + +static zend_always_inline uint32_t zval_gc_flags(uint32_t gc_type_info) { + return (gc_type_info >> GC_FLAGS_SHIFT) & (GC_FLAGS_MASK >> GC_FLAGS_SHIFT); +} + +static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { + return (gc_type_info >> GC_INFO_SHIFT); +} + +static zend_always_inline uint32_t zend_gc_refcount(const zend_refcounted_h *p) { + return p->refcount; +} + +static zend_always_inline uint32_t zend_gc_set_refcount(zend_refcounted_h *p, uint32_t rc) { + p->refcount = rc; + return p->refcount; +} + +static zend_always_inline uint32_t zend_gc_addref(zend_refcounted_h *p) { + ZEND_RC_MOD_CHECK(p); + return ++(p->refcount); +} + +static zend_always_inline void zend_gc_try_addref(zend_refcounted_h *p) { + if (!(p->u.type_info & GC_IMMUTABLE)) { + ZEND_RC_MOD_CHECK(p); + ++p->refcount; + } +} + +static zend_always_inline void zend_gc_try_delref(zend_refcounted_h *p) { + if (!(p->u.type_info & GC_IMMUTABLE)) { + ZEND_RC_MOD_CHECK(p); + --p->refcount; + } +} + +static zend_always_inline uint32_t zend_gc_delref(zend_refcounted_h *p) { + ZEND_ASSERT(p->refcount > 0); + ZEND_RC_MOD_CHECK(p); + return --(p->refcount); +} + +static zend_always_inline uint32_t zend_gc_addref_ex(zend_refcounted_h *p, uint32_t rc) { + ZEND_RC_MOD_CHECK(p); + p->refcount += rc; + return p->refcount; +} + +static zend_always_inline uint32_t zend_gc_delref_ex(zend_refcounted_h *p, uint32_t rc) { + ZEND_RC_MOD_CHECK(p); + p->refcount -= rc; + return p->refcount; +} + +#endif /* ZEND_REFCOUNTED_H */ diff --git a/Zend/zend_types.h b/Zend/zend_types.h index d8a3fc0edf0da..f1525b78a2a9a 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -25,6 +25,7 @@ #include "zend_portability.h" #include "zend_long.h" #include "zend_rc_debug.h" +#include "zend_refcounted.h" #include "zend_result.h" #include "zend_type_code.h" @@ -83,7 +84,6 @@ typedef struct _zend_execute_data zend_execute_data; typedef struct _zval_struct zval; -typedef struct _zend_refcounted zend_refcounted; typedef struct _zend_string zend_string; typedef struct _zend_array zend_array; typedef struct _zend_object zend_object; @@ -333,17 +333,6 @@ struct _zval_struct { } u2; }; -typedef struct _zend_refcounted_h { - uint32_t refcount; /* reference counter 32-bit */ - union { - uint32_t type_info; - } u; -} zend_refcounted_h; - -struct _zend_refcounted { - zend_refcounted_h gc; -}; - struct _zend_string { zend_refcounted_h gc; zend_ulong h; /* hash value */ @@ -588,33 +577,12 @@ static zend_always_inline uint8_t zval_get_type(const zval* pz) { #define Z_TYPE_FLAGS_SHIFT 8 -#define GC_REFCOUNT(p) zend_gc_refcount(&(p)->gc) -#define GC_SET_REFCOUNT(p, rc) zend_gc_set_refcount(&(p)->gc, rc) -#define GC_ADDREF(p) zend_gc_addref(&(p)->gc) -#define GC_DELREF(p) zend_gc_delref(&(p)->gc) -#define GC_ADDREF_EX(p, rc) zend_gc_addref_ex(&(p)->gc, rc) -#define GC_DELREF_EX(p, rc) zend_gc_delref_ex(&(p)->gc, rc) -#define GC_TRY_ADDREF(p) zend_gc_try_addref(&(p)->gc) -#define GC_TRY_DELREF(p) zend_gc_try_delref(&(p)->gc) - #define GC_TYPE_MASK 0x0000000f #define GC_FLAGS_MASK 0x000003f0 #define GC_INFO_MASK 0xfffffc00 #define GC_FLAGS_SHIFT 0 #define GC_INFO_SHIFT 10 -static zend_always_inline uint8_t zval_gc_type(uint32_t gc_type_info) { - return (gc_type_info & GC_TYPE_MASK); -} - -static zend_always_inline uint32_t zval_gc_flags(uint32_t gc_type_info) { - return (gc_type_info >> GC_FLAGS_SHIFT) & (GC_FLAGS_MASK >> GC_FLAGS_SHIFT); -} - -static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { - return (gc_type_info >> GC_INFO_SHIFT); -} - #define GC_TYPE_INFO(p) (p)->gc.u.type_info #define GC_TYPE(p) zval_gc_type(GC_TYPE_INFO(p)) #define GC_FLAGS(p) zval_gc_flags(GC_TYPE_INFO(p)) @@ -638,21 +606,6 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { #define Z_GC_TYPE_INFO(zval) GC_TYPE_INFO(Z_COUNTED(zval)) #define Z_GC_TYPE_INFO_P(zval_p) Z_GC_TYPE_INFO(*(zval_p)) -/* zval_gc_flags(zval.value->gc.u.type_info) (common flags) */ -#define GC_NOT_COLLECTABLE (1<<4) -#define GC_PROTECTED (1<<5) /* used for recursion detection */ -#define GC_IMMUTABLE (1<<6) /* can't be changed in place */ -#define GC_PERSISTENT (1<<7) /* allocated using malloc */ -#define GC_PERSISTENT_LOCAL (1<<8) /* persistent, but thread-local */ - -#define GC_NULL (IS_NULL | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT)) -#define GC_STRING (IS_STRING | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT)) -#define GC_ARRAY IS_ARRAY -#define GC_OBJECT IS_OBJECT -#define GC_RESOURCE (IS_RESOURCE | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT)) -#define GC_REFERENCE (IS_REFERENCE | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT)) -#define GC_CONSTANT_AST (IS_CONSTANT_AST | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT)) - /* zval.u1.v.type_flags */ #define IS_TYPE_REFCOUNTED (1<<0) #define IS_TYPE_COLLECTABLE (1<<1) @@ -1134,52 +1087,6 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { do { } while (0) #endif -static zend_always_inline uint32_t zend_gc_refcount(const zend_refcounted_h *p) { - return p->refcount; -} - -static zend_always_inline uint32_t zend_gc_set_refcount(zend_refcounted_h *p, uint32_t rc) { - p->refcount = rc; - return p->refcount; -} - -static zend_always_inline uint32_t zend_gc_addref(zend_refcounted_h *p) { - ZEND_RC_MOD_CHECK(p); - return ++(p->refcount); -} - -static zend_always_inline void zend_gc_try_addref(zend_refcounted_h *p) { - if (!(p->u.type_info & GC_IMMUTABLE)) { - ZEND_RC_MOD_CHECK(p); - ++p->refcount; - } -} - -static zend_always_inline void zend_gc_try_delref(zend_refcounted_h *p) { - if (!(p->u.type_info & GC_IMMUTABLE)) { - ZEND_RC_MOD_CHECK(p); - --p->refcount; - } -} - -static zend_always_inline uint32_t zend_gc_delref(zend_refcounted_h *p) { - ZEND_ASSERT(p->refcount > 0); - ZEND_RC_MOD_CHECK(p); - return --(p->refcount); -} - -static zend_always_inline uint32_t zend_gc_addref_ex(zend_refcounted_h *p, uint32_t rc) { - ZEND_RC_MOD_CHECK(p); - p->refcount += rc; - return p->refcount; -} - -static zend_always_inline uint32_t zend_gc_delref_ex(zend_refcounted_h *p, uint32_t rc) { - ZEND_RC_MOD_CHECK(p); - p->refcount -= rc; - return p->refcount; -} - static zend_always_inline uint32_t zval_refcount_p(const zval* pz) { #if ZEND_DEBUG ZEND_ASSERT(Z_REFCOUNTED_P(pz) || Z_TYPE_P(pz) == IS_ARRAY); From a8614d99ff193aa0618cacf50488d9558fab8872 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 13 Jan 2023 18:42:49 +0100 Subject: [PATCH 7/8] Zend/zend_types.h: move `zend_uchar.h` to `zend_char.h` Prepare to fix the cyclic header dependency from `zend_string.h`. --- Zend/zend_API.h | 1 + Zend/zend_char.h | 22 ++++++++++++++++++++++ Zend/zend_string.h | 1 + Zend/zend_types.h | 2 -- 4 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 Zend/zend_char.h diff --git a/Zend/zend_API.h b/Zend/zend_API.h index ab58f7db72d49..8341febd6ac7a 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -22,6 +22,7 @@ #ifndef ZEND_API_H #define ZEND_API_H +#include "zend_char.h" #include "zend_modules.h" #include "zend_list.h" #include "zend_operators.h" diff --git a/Zend/zend_char.h b/Zend/zend_char.h new file mode 100644 index 0000000000000..0a4af72baa1ff --- /dev/null +++ b/Zend/zend_char.h @@ -0,0 +1,22 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_CHAR_H +#define ZEND_CHAR_H + +typedef unsigned char zend_uchar; + +#endif /* ZEND_CHAR_H */ diff --git a/Zend/zend_string.h b/Zend/zend_string.h index 3eca7343a008b..fdfa87e3333a7 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -20,6 +20,7 @@ #define ZEND_STRING_H #include "zend.h" +#include "zend_char.h" BEGIN_EXTERN_C() diff --git a/Zend/zend_types.h b/Zend/zend_types.h index f1525b78a2a9a..a4f859cb45d68 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -53,8 +53,6 @@ # define ZEND_ENDIAN_LOHI_C_4(a, b, c, d) a, b, c, d #endif -typedef unsigned char zend_uchar; - #ifdef ZEND_ENABLE_ZVAL_LONG64 # ifdef ZEND_WIN32 # define ZEND_SIZE_MAX _UI64_MAX From adee720a68940dc14233efb08e5aff8b4914c875 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 13 Jan 2023 19:44:00 +0100 Subject: [PATCH 8/8] Zend/zend_types.h: move `zend_string` to `zend_string.h` It is now possible to include only `zend_string.h` without `zend_types.h`. --- Zend/zend_alloc.h | 2 +- Zend/zend_string.c | 1 + Zend/zend_string.h | 20 +++++++++++++++++++- Zend/zend_types.h | 14 -------------- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h index 95581cf2814c1..30fea71e2efaf 100644 --- a/Zend/zend_alloc.h +++ b/Zend/zend_alloc.h @@ -21,12 +21,12 @@ #ifndef ZEND_ALLOC_H #define ZEND_ALLOC_H +#include "zend_portability.h" #include "zend_result.h" #include #include "../TSRM/TSRM.h" -#include "zend.h" #ifndef ZEND_MM_ALIGNMENT # error "ZEND_MM_ALIGNMENT was not defined during configure" diff --git a/Zend/zend_string.c b/Zend/zend_string.c index ddb8ff1bb84fe..a0f379556d05e 100644 --- a/Zend/zend_string.c +++ b/Zend/zend_string.c @@ -16,6 +16,7 @@ +----------------------------------------------------------------------+ */ +#include "zend_string.h" #include "zend.h" #include "zend_globals.h" #include "zend_rc_debug.h" diff --git a/Zend/zend_string.h b/Zend/zend_string.h index fdfa87e3333a7..cc4f0751bec63 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -19,8 +19,26 @@ #ifndef ZEND_STRING_H #define ZEND_STRING_H -#include "zend.h" +#include "zend_alloc.h" #include "zend_char.h" +#include "zend_portability.h" +#include "zend_refcounted.h" + +/* string flags (zval.value->gc.u.flags) */ +#define IS_STR_CLASS_NAME_MAP_PTR GC_PROTECTED /* refcount is a map_ptr offset of class_entry */ +#define IS_STR_INTERNED GC_IMMUTABLE /* interned string */ +#define IS_STR_PERSISTENT GC_PERSISTENT /* allocated using malloc */ +#define IS_STR_PERMANENT (1<<8) /* relives request boundary */ +#define IS_STR_VALID_UTF8 (1<<9) /* valid UTF-8 according to PCRE */ + +typedef struct _zend_string zend_string; + +struct _zend_string { + zend_refcounted_h gc; + zend_ulong h; /* hash value */ + size_t len; + char val[1]; +}; BEGIN_EXTERN_C() diff --git a/Zend/zend_types.h b/Zend/zend_types.h index a4f859cb45d68..3d900226e54e5 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -331,13 +331,6 @@ struct _zval_struct { } u2; }; -struct _zend_string { - zend_refcounted_h gc; - zend_ulong h; /* hash value */ - size_t len; - char val[1]; -}; - typedef struct _Bucket { zval val; zend_ulong h; /* hash value (or numeric index) */ @@ -627,13 +620,6 @@ static zend_always_inline uint8_t zval_get_type(const zval* pz) { #define IS_CONSTANT_AST_EX (IS_CONSTANT_AST | (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT)) -/* string flags (zval.value->gc.u.flags) */ -#define IS_STR_CLASS_NAME_MAP_PTR GC_PROTECTED /* refcount is a map_ptr offset of class_entry */ -#define IS_STR_INTERNED GC_IMMUTABLE /* interned string */ -#define IS_STR_PERSISTENT GC_PERSISTENT /* allocated using malloc */ -#define IS_STR_PERMANENT (1<<8) /* relives request boundary */ -#define IS_STR_VALID_UTF8 (1<<9) /* valid UTF-8 according to PCRE */ - /* array flags */ #define IS_ARRAY_IMMUTABLE GC_IMMUTABLE #define IS_ARRAY_PERSISTENT GC_PERSISTENT