]> granicus.if.org Git - php/commitdiff
Completely hide GC implementation details into zend_gc.c
authorDmitry Stogov <dmitry@zend.com>
Mon, 26 Feb 2018 09:49:58 +0000 (12:49 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 27 Feb 2018 18:08:26 +0000 (21:08 +0300)
Zend/zend.c
Zend/zend_builtin_functions.c
Zend/zend_execute_API.c
Zend/zend_gc.c
Zend/zend_gc.h
Zend/zend_hash.c
Zend/zend_types.h

index efe51b7b471aa3502189a46d6ef86a5bea1ef111..a714f04786ec3c032fadad16f03a95a8a79faa8f 100644 (file)
@@ -101,16 +101,35 @@ static ZEND_INI_MH(OnUpdateErrorReporting) /* {{{ */
 
 static ZEND_INI_MH(OnUpdateGCEnabled) /* {{{ */
 {
-       OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
-
-       if (GC_G(gc_enabled)) {
-               gc_init();
+       zend_bool val;
+
+       if (ZSTR_LEN(new_value) == 2 && strcasecmp("on", ZSTR_VAL(new_value)) == 0) {
+               val = 1;
+       } else if (ZSTR_LEN(new_value) == 3 && strcasecmp("yes", ZSTR_VAL(new_value)) == 0) {
+               val = 1;
+       }else if (ZSTR_LEN(new_value) == 4 && strcasecmp("true", ZSTR_VAL(new_value)) == 0) {
+               val = 1;
+       } else {
+               val = (zend_bool) atoi(ZSTR_VAL(new_value));
        }
 
+       gc_set_enabled(val);
+
        return SUCCESS;
 }
 /* }}} */
 
+static ZEND_INI_DISP(zend_gc_enabled_displayer_cb) /* {{{ */
+{
+       if (gc_enabled()) {
+               ZEND_PUTS("On");
+       } else {
+               ZEND_PUTS("Off");
+       }
+}
+/* }}} */
+
+
 static ZEND_INI_MH(OnUpdateScriptEncoding) /* {{{ */
 {
        if (!CG(multibyte)) {
@@ -154,7 +173,7 @@ static ZEND_INI_MH(OnUpdateAssertions) /* {{{ */
 ZEND_INI_BEGIN()
        ZEND_INI_ENTRY("error_reporting",                               NULL,           ZEND_INI_ALL,           OnUpdateErrorReporting)
        STD_ZEND_INI_ENTRY("zend.assertions",                           "1",    ZEND_INI_ALL,       OnUpdateAssertions,           assertions,   zend_executor_globals,  executor_globals)
-       STD_ZEND_INI_BOOLEAN("zend.enable_gc",                          "1",    ZEND_INI_ALL,           OnUpdateGCEnabled,      gc_enabled,     zend_gc_globals,        gc_globals)
+       ZEND_INI_ENTRY3_EX("zend.enable_gc",                            "1",    ZEND_INI_ALL,           OnUpdateGCEnabled, NULL, NULL, NULL, zend_gc_enabled_displayer_cb)
        STD_ZEND_INI_BOOLEAN("zend.multibyte", "0", ZEND_INI_PERDIR, OnUpdateBool, multibyte,      zend_compiler_globals, compiler_globals)
        ZEND_INI_ENTRY("zend.script_encoding",                  NULL,           ZEND_INI_ALL,           OnUpdateScriptEncoding)
        STD_ZEND_INI_BOOLEAN("zend.detect_unicode",                     "1",    ZEND_INI_ALL,           OnUpdateBool, detect_unicode, zend_compiler_globals, compiler_globals)
index bd35d90627c93ab367090e1b22e8b008329dc979..37121663b438aa54fe2fa517be596eea67cecf49 100644 (file)
@@ -361,7 +361,7 @@ ZEND_FUNCTION(gc_collect_cycles)
    Returns status of the circular reference collector */
 ZEND_FUNCTION(gc_enabled)
 {
-       RETURN_BOOL(GC_G(gc_enabled));
+       RETURN_BOOL(gc_enabled());
 }
 /* }}} */
 
index f66bd663045a8152b0f78ab500f0f8047c4287db..7b012005f0bb729909646348a16397c285012310 100644 (file)
@@ -302,7 +302,7 @@ void shutdown_executor(void) /* {{{ */
                zend_hash_graceful_reverse_destroy(&EG(symbol_table));
 
 #if ZEND_DEBUG
-               if (GC_G(gc_enabled) && !CG(unclean_shutdown)) {
+               if (gc_enabled() && !CG(unclean_shutdown)) {
                        gc_collect_cycles();
                }
 #endif
index 39ed6a96a980d0198ebdf0232909580fd0c4c697..eb7f0ab41458574c6729a6f6683e15cc6b844b1e 100644 (file)
 #include "zend.h"
 #include "zend_API.h"
 
+#ifndef GC_BENCH
+# define GC_BENCH 0
+#endif
+
+#ifndef ZEND_GC_DEBUG
+# define ZEND_GC_DEBUG 0
+#endif
+
+#define GC_COLOR  0xc000
+
+#define GC_BLACK  0x0000 /* must be zero */
+#define GC_WHITE  0x8000
+#define GC_GREY   0x4000
+#define GC_PURPLE 0xc000
+
+#define GC_ADDRESS(v) \
+       ((v) & ~GC_COLOR)
+#define GC_INFO_GET_COLOR(v) \
+       (((zend_uintptr_t)(v)) & GC_COLOR)
+#define GC_INFO_SET_ADDRESS(v, a) \
+       do {(v) = ((v) & GC_COLOR) | (a);} while (0)
+#define GC_INFO_SET_COLOR(v, c) \
+       do {(v) = ((v) & ~GC_COLOR) | (c);} while (0)
+#define GC_INFO_SET_BLACK(v) \
+       do {(v) = (v) & ~GC_COLOR;} while (0)
+#define GC_INFO_SET_PURPLE(v) \
+       do {(v) = (v) | GC_COLOR;} while (0)
+
 /* one (0) is reserved */
 #define GC_ROOT_BUFFER_MAX_ENTRIES 10001
 
 #define GC_HAS_DESTRUCTORS  (1<<0)
 
-#ifndef ZEND_GC_DEBUG
-# define ZEND_GC_DEBUG 0
+#define GC_NUM_ADDITIONAL_ENTRIES \
+       ((4096 - ZEND_MM_OVERHEAD - sizeof(void*) * 2) / sizeof(gc_root_buffer))
+
+ZEND_API int (*gc_collect_cycles)(void);
+
+typedef struct _gc_root_buffer {
+       zend_refcounted          *ref;
+       struct _gc_root_buffer   *next;     /* double-linked list               */
+       struct _gc_root_buffer   *prev;
+       uint32_t                 refcount;
+} gc_root_buffer;
+
+typedef struct _gc_additional_bufer gc_additional_buffer;
+
+struct _gc_additional_bufer {
+       uint32_t              used;
+       gc_additional_buffer *next;
+       gc_root_buffer        buf[GC_NUM_ADDITIONAL_ENTRIES];
+};
+
+typedef struct _zend_gc_globals {
+       zend_bool         gc_enabled;
+       zend_bool         gc_active;
+       zend_bool         gc_full;
+
+       gc_root_buffer   *buf;                          /* preallocated arrays of buffers   */
+       gc_root_buffer    roots;                        /* list of possible roots of cycles */
+       gc_root_buffer   *unused;                       /* list of unused buffers           */
+       gc_root_buffer   *first_unused;         /* pointer to first unused buffer   */
+       gc_root_buffer   *last_unused;          /* pointer to last unused buffer    */
+
+       gc_root_buffer    to_free;                      /* list to free                     */
+       gc_root_buffer   *next_to_free;
+
+       uint32_t gc_runs;
+       uint32_t collected;
+
+#if GC_BENCH
+       uint32_t root_buf_length;
+       uint32_t root_buf_peak;
+       uint32_t zval_possible_root;
+       uint32_t zval_buffered;
+       uint32_t zval_remove_from_buffer;
+       uint32_t zval_marked_grey;
 #endif
 
+       gc_additional_buffer *additional_buffer;
+
+} zend_gc_globals;
+
 #ifdef ZTS
-ZEND_API int gc_globals_id;
+static int gc_globals_id;
+#define GC_G(v) ZEND_TSRMG(gc_globals_id, zend_gc_globals *, v)
 #else
-ZEND_API zend_gc_globals gc_globals;
+#define GC_G(v) (gc_globals.v)
+static zend_gc_globals gc_globals;
 #endif
 
-ZEND_API int (*gc_collect_cycles)(void);
+#if GC_BENCH
+# define GC_BENCH_INC(counter) GC_G(counter)++
+# define GC_BENCH_DEC(counter) GC_G(counter)--
+# define GC_BENCH_PEAK(peak, counter) do {             \
+               if (GC_G(counter) > GC_G(peak)) {               \
+                       GC_G(peak) = GC_G(counter);                     \
+               }                                                                               \
+       } while (0)
+#else
+# define GC_BENCH_INC(counter)
+# define GC_BENCH_DEC(counter)
+# define GC_BENCH_PEAK(peak, counter)
+#endif
 
 #if ZEND_GC_DEBUG > 1
 # define GC_TRACE(format, ...) fprintf(stderr, format "\n", ##__VA_ARGS__);
@@ -249,13 +337,21 @@ ZEND_API void gc_reset(void)
        GC_G(additional_buffer) = NULL;
 }
 
-ZEND_API void gc_init(void)
+ZEND_API zend_bool gc_set_enabled(zend_bool enable)
 {
-       if (GC_G(buf) == NULL && GC_G(gc_enabled)) {
+       zend_bool old_enabled = GC_G(gc_enabled);
+       GC_G(gc_enabled) = enable;
+       if (enable && !old_enabled && GC_G(buf) == NULL) {
                GC_G(buf) = (gc_root_buffer*) malloc(sizeof(gc_root_buffer) * GC_ROOT_BUFFER_MAX_ENTRIES);
                GC_G(last_unused) = &GC_G(buf)[GC_ROOT_BUFFER_MAX_ENTRIES];
                gc_reset();
        }
+       return old_enabled;
+}
+
+ZEND_API zend_bool gc_enabled(void)
+{
+       return GC_G(gc_enabled);
 }
 
 ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref)
index f0bc5610cdbbd419a4db329d6a5e093b78f545de..f045026ccfd235c7c46bbadd19d3cdb203fcf079 100644 (file)
 #ifndef ZEND_GC_H
 #define ZEND_GC_H
 
-#ifndef GC_BENCH
-# define GC_BENCH 0
-#endif
-
-#if GC_BENCH
-# define GC_BENCH_INC(counter) GC_G(counter)++
-# define GC_BENCH_DEC(counter) GC_G(counter)--
-# define GC_BENCH_PEAK(peak, counter) do {             \
-               if (GC_G(counter) > GC_G(peak)) {               \
-                       GC_G(peak) = GC_G(counter);                     \
-               }                                                                               \
-       } while (0)
-#else
-# define GC_BENCH_INC(counter)
-# define GC_BENCH_DEC(counter)
-# define GC_BENCH_PEAK(peak, counter)
-#endif
-
-#define GC_COLOR  0xc000
-
-#define GC_BLACK  0x0000
-#define GC_WHITE  0x8000
-#define GC_GREY   0x4000
-#define GC_PURPLE 0xc000
-
-#define GC_ADDRESS(v) \
-       ((v) & ~GC_COLOR)
-#define GC_INFO_GET_COLOR(v) \
-       (((zend_uintptr_t)(v)) & GC_COLOR)
-#define GC_INFO_SET_ADDRESS(v, a) \
-       do {(v) = ((v) & GC_COLOR) | (a);} while (0)
-#define GC_INFO_SET_COLOR(v, c) \
-       do {(v) = ((v) & ~GC_COLOR) | (c);} while (0)
-#define GC_INFO_SET_BLACK(v) \
-       do {(v) = (v) & ~GC_COLOR;} while (0)
-#define GC_INFO_SET_PURPLE(v) \
-       do {(v) = (v) | GC_COLOR;} while (0)
-
-typedef struct _gc_root_buffer {
-       zend_refcounted          *ref;
-       struct _gc_root_buffer   *next;     /* double-linked list               */
-       struct _gc_root_buffer   *prev;
-       uint32_t                 refcount;
-} gc_root_buffer;
-
-#define GC_NUM_ADDITIONAL_ENTRIES \
-       ((4096 - ZEND_MM_OVERHEAD - sizeof(void*) * 2) / sizeof(gc_root_buffer))
-
-typedef struct _gc_additional_bufer gc_additional_buffer;
-
-struct _gc_additional_bufer {
-       uint32_t              used;
-       gc_additional_buffer *next;
-       gc_root_buffer        buf[GC_NUM_ADDITIONAL_ENTRIES];
-};
-
-typedef struct _zend_gc_globals {
-       zend_bool         gc_enabled;
-       zend_bool         gc_active;
-       zend_bool         gc_full;
-
-       gc_root_buffer   *buf;                          /* preallocated arrays of buffers   */
-       gc_root_buffer    roots;                        /* list of possible roots of cycles */
-       gc_root_buffer   *unused;                       /* list of unused buffers           */
-       gc_root_buffer   *first_unused;         /* pointer to first unused buffer   */
-       gc_root_buffer   *last_unused;          /* pointer to last unused buffer    */
-
-       gc_root_buffer    to_free;                      /* list to free                     */
-       gc_root_buffer   *next_to_free;
-
-       uint32_t gc_runs;
-       uint32_t collected;
-
-#if GC_BENCH
-       uint32_t root_buf_length;
-       uint32_t root_buf_peak;
-       uint32_t zval_possible_root;
-       uint32_t zval_buffered;
-       uint32_t zval_remove_from_buffer;
-       uint32_t zval_marked_grey;
-#endif
-
-       gc_additional_buffer *additional_buffer;
-
-} zend_gc_globals;
-
-#ifdef ZTS
-BEGIN_EXTERN_C()
-ZEND_API extern int gc_globals_id;
-END_EXTERN_C()
-#define GC_G(v) ZEND_TSRMG(gc_globals_id, zend_gc_globals *, v)
-#else
-#define GC_G(v) (gc_globals.v)
-extern ZEND_API zend_gc_globals gc_globals;
-#endif
-
 BEGIN_EXTERN_C()
 ZEND_API extern int (*gc_collect_cycles)(void);
 
@@ -125,8 +29,9 @@ ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref);
 ZEND_API void ZEND_FASTCALL gc_remove_from_buffer(zend_refcounted *ref);
 ZEND_API void gc_globals_ctor(void);
 ZEND_API void gc_globals_dtor(void);
-ZEND_API void gc_init(void);
 ZEND_API void gc_reset(void);
+ZEND_API zend_bool gc_set_enabled(zend_bool enable);
+ZEND_API zend_bool gc_enabled(void);
 
 /* The default implementation of the gc_collect_cycles callback. */
 ZEND_API int  zend_gc_collect_cycles(void);
@@ -134,7 +39,7 @@ END_EXTERN_C()
 
 #define GC_REMOVE_FROM_BUFFER(p) do { \
                zend_refcounted *_p = (zend_refcounted*)(p); \
-               if (GC_ADDRESS(GC_INFO(_p))) { \
+               if (GC_INFO(_p)) { \
                        gc_remove_from_buffer(_p); \
                } \
        } while (0)
index b4a0d00b724d42178b73181a3fd928f801414e6c..a33818edefe126d1e155fc944b139e8b6d2996f0 100644 (file)
@@ -1363,7 +1363,7 @@ ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
 
        /* break possible cycles */
        GC_REMOVE_FROM_BUFFER(ht);
-       GC_TYPE_INFO(ht) = IS_NULL | (GC_WHITE << 16);
+       GC_TYPE_INFO(ht) = IS_NULL /*???| (GC_WHITE << 16)*/;
 
        if (ht->nNumUsed) {
                /* In some rare cases destructors of regular arrays may be changed */
index 1f8845a85793017950c79c2b3a8cfc0b47575095..e5ea3687649dd517da8cc4ca4978b63f2e5d22ac 100644 (file)
@@ -210,7 +210,7 @@ typedef struct _zend_refcounted_h {
                        ZEND_ENDIAN_LOHI_3(
                                zend_uchar    type,
                                zend_uchar    flags,    /* used for strings & objects */
-                               uint16_t      gc_info)  /* keeps GC root number (or 0) and color */
+                               uint16_t      gc_info)  /* keeps GC information, must be initialized by 0 */
                } v;
                uint32_t type_info;
        } u;