Last active
February 11, 2017 05:38
-
-
Save laruence/5c529dd63ed41b7f0621a5858fba662e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c | |
index a125c44..8f1255c 100644 | |
--- a/Zend/zend_gc.c | |
+++ b/Zend/zend_gc.c | |
@@ -75,26 +75,12 @@ | |
/* one (0) is reserved */ | |
#define GC_ROOT_BUFFER_MAX_ENTRIES 10001 | |
-#define GC_FAKE_BUFFER_FLAG 0x80 | |
-#define GC_TYPE_MASK 0x7f | |
- | |
#define GC_HAS_DESTRUCTORS (1<<0) | |
#ifndef ZEND_GC_DEBUG | |
# define ZEND_GC_DEBUG 0 | |
#endif | |
-#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]; | |
-}; | |
- | |
#ifdef ZTS | |
ZEND_API int gc_globals_id; | |
#else | |
@@ -168,8 +154,10 @@ static zend_always_inline void gc_remove_from_roots(gc_root_buffer *root) | |
{ | |
root->next->prev = root->prev; | |
root->prev->next = root->next; | |
- root->prev = GC_G(unused); | |
- GC_G(unused) = root; | |
+ if (EXPECTED(GC_ADDRESS(GC_INFO(root->ref)) < GC_ROOT_BUFFER_MAX_ENTRIES)) { | |
+ root->prev = GC_G(unused); | |
+ GC_G(unused) = root; | |
+ } | |
GC_BENCH_DEC(root_buf_length); | |
} | |
@@ -207,6 +195,7 @@ static void gc_globals_ctor_ex(zend_gc_globals *gc_globals) | |
gc_globals->zval_remove_from_buffer = 0; | |
gc_globals->zval_marked_grey = 0; | |
#endif | |
+ gc_globals->additional_buf = NULL; | |
} | |
ZEND_API void gc_globals_ctor(void) | |
@@ -326,22 +315,43 @@ ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref) | |
GC_BENCH_PEAK(root_buf_peak, root_buf_length); | |
} | |
+static zend_always_inline gc_root_buffer* gc_find_additional_buf(zend_refcounted *ref) | |
+{ | |
+ uint32_t i; | |
+ gc_additional_buffer *additional_buf = GC_G(additional_buf); | |
+ | |
+ /* We have to traverse the whole additional_buf list | |
+ * to find which root hold the ref */ | |
+ while (additional_buf) { | |
+ for (i = 0; i < additional_buf->used; i++) { | |
+ gc_root_buffer *root = additional_buf->buf + i; | |
+ if (root->ref == ref) { | |
+ return root; | |
+ } | |
+ } | |
+ additional_buf = additional_buf->next; | |
+ } | |
+ | |
+ ZEND_ASSERT(0); | |
+ return NULL; | |
+} | |
+ | |
ZEND_API void ZEND_FASTCALL gc_remove_from_buffer(zend_refcounted *ref) | |
{ | |
gc_root_buffer *root; | |
ZEND_ASSERT(GC_ADDRESS(GC_INFO(ref))); | |
- ZEND_ASSERT(GC_ADDRESS(GC_INFO(ref)) < GC_ROOT_BUFFER_MAX_ENTRIES); | |
- | |
GC_BENCH_INC(zval_remove_from_buffer); | |
- | |
- root = GC_G(buf) + GC_ADDRESS(GC_INFO(ref)); | |
- if (GC_REF_GET_COLOR(ref) != GC_BLACK) { | |
- GC_TRACE_SET_COLOR(ref, GC_PURPLE); | |
+ if (EXPECTED(GC_ADDRESS(GC_INFO(ref)) < GC_ROOT_BUFFER_MAX_ENTRIES)) { | |
+ root = GC_G(buf) + GC_ADDRESS(GC_INFO(ref)); | |
+ if (GC_REF_GET_COLOR(ref) != GC_BLACK) { | |
+ GC_TRACE_SET_COLOR(ref, GC_PURPLE); | |
+ } | |
+ } else { | |
+ root = gc_find_additional_buf(ref); | |
} | |
- GC_INFO(ref) = 0; | |
GC_REMOVE_FROM_ROOTS(root); | |
- | |
+ GC_INFO(ref) = 0; | |
/* updete next root that is going to be freed */ | |
if (GC_G(next_to_free) == root) { | |
GC_G(next_to_free) = root->next; | |
@@ -691,7 +701,7 @@ static void gc_scan_roots(void) | |
} | |
} | |
-static void gc_add_garbage(zend_refcounted *ref, gc_additional_buffer **additional_buffer) | |
+static void gc_add_garbage(zend_refcounted *ref) | |
{ | |
gc_root_buffer *buf = GC_G(unused); | |
@@ -717,22 +727,20 @@ static void gc_add_garbage(zend_refcounted *ref, gc_additional_buffer **addition | |
* set it's address to GC_ROOT_BUFFER_MAX_ENTRIES that have special | |
* meaning. | |
*/ | |
- if (!*additional_buffer || (*additional_buffer)->used == GC_NUM_ADDITIONAL_ENTRIES) { | |
+ if (!GC_G(additional_buf) || GC_G(additional_buf)->used == GC_NUM_ADDITIONAL_ENTRIES) { | |
gc_additional_buffer *new_buffer = emalloc(sizeof(gc_additional_buffer)); | |
new_buffer->used = 0; | |
- new_buffer->next = *additional_buffer; | |
- *additional_buffer = new_buffer; | |
+ new_buffer->next = GC_G(additional_buf); | |
+ GC_G(additional_buf) = new_buffer; | |
} | |
- buf = (*additional_buffer)->buf + (*additional_buffer)->used; | |
- (*additional_buffer)->used++; | |
+ buf = GC_G(additional_buf)->buf + GC_G(additional_buf)->used; | |
+ GC_G(additional_buf)->used++; | |
#if 1 | |
/* optimization: color is already GC_BLACK (0) */ | |
GC_INFO(ref) = GC_ROOT_BUFFER_MAX_ENTRIES; | |
#else | |
GC_REF_SET_ADDRESS(ref, GC_ROOT_BUFFER_MAX_ENTRIES); | |
#endif | |
- /* modify type to prevent indirect destruction */ | |
- GC_TYPE(ref) |= GC_FAKE_BUFFER_FLAG; | |
} | |
if (buf) { | |
buf->ref = ref; | |
@@ -743,7 +751,7 @@ static void gc_add_garbage(zend_refcounted *ref, gc_additional_buffer **addition | |
} | |
} | |
-static int gc_collect_white(zend_refcounted *ref, uint32_t *flags, gc_additional_buffer **additional_buffer) | |
+static int gc_collect_white(zend_refcounted *ref, uint32_t *flags) | |
{ | |
int count = 0; | |
HashTable *ht; | |
@@ -776,7 +784,7 @@ tail_call: | |
#else | |
if (!GC_ADDRESS(GC_INFO(ref))) { | |
#endif | |
- gc_add_garbage(ref, additional_buffer); | |
+ gc_add_garbage(ref); | |
} | |
if (obj->handlers->dtor_obj && | |
((obj->handlers->dtor_obj != zend_objects_destroy_object) || | |
@@ -800,7 +808,7 @@ tail_call: | |
if (Z_REFCOUNTED_P(zv)) { | |
ref = Z_COUNTED_P(zv); | |
GC_REFCOUNT(ref)++; | |
- count += gc_collect_white(ref, flags, additional_buffer); | |
+ count += gc_collect_white(ref, flags); | |
/* count non-refcounted for compatibility ??? */ | |
} else if (Z_TYPE_P(zv) != IS_UNDEF) { | |
count++; | |
@@ -822,7 +830,7 @@ tail_call: | |
#else | |
if (!GC_ADDRESS(GC_INFO(ref))) { | |
#endif | |
- gc_add_garbage(ref, additional_buffer); | |
+ gc_add_garbage(ref); | |
} | |
ht = (zend_array*)ref; | |
} else if (GC_TYPE(ref) == IS_REFERENCE) { | |
@@ -862,7 +870,7 @@ tail_call: | |
if (Z_REFCOUNTED_P(zv)) { | |
ref = Z_COUNTED_P(zv); | |
GC_REFCOUNT(ref)++; | |
- count += gc_collect_white(ref, flags, additional_buffer); | |
+ count += gc_collect_white(ref, flags); | |
/* count non-refcounted for compatibility ??? */ | |
} else if (Z_TYPE_P(zv) != IS_UNDEF) { | |
count++; | |
@@ -880,7 +888,7 @@ tail_call: | |
return count; | |
} | |
-static int gc_collect_roots(uint32_t *flags, gc_additional_buffer **additional_buffer) | |
+static int gc_collect_roots(uint32_t *flags) | |
{ | |
int count = 0; | |
gc_root_buffer *current = GC_G(roots).next; | |
@@ -889,8 +897,8 @@ static int gc_collect_roots(uint32_t *flags, gc_additional_buffer **additional_b | |
while (current != &GC_G(roots)) { | |
gc_root_buffer *next = current->next; | |
if (GC_REF_GET_COLOR(current->ref) == GC_BLACK) { | |
- GC_INFO(current->ref) = 0; /* reset GC_ADDRESS() and keep GC_BLACK */ | |
GC_REMOVE_FROM_ROOTS(current); | |
+ GC_INFO(current->ref) = 0; /* reset GC_ADDRESS() and keep GC_BLACK */ | |
} | |
current = next; | |
} | |
@@ -898,7 +906,7 @@ static int gc_collect_roots(uint32_t *flags, gc_additional_buffer **additional_b | |
current = GC_G(roots).next; | |
while (current != &GC_G(roots)) { | |
if (GC_REF_GET_COLOR(current->ref) == GC_WHITE) { | |
- count += gc_collect_white(current->ref, flags, additional_buffer); | |
+ count += gc_collect_white(current->ref, flags); | |
} | |
current = current->next; | |
} | |
@@ -934,12 +942,11 @@ static void gc_remove_nested_data_from_buffer(zend_refcounted *ref, gc_root_buff | |
tail_call: | |
if (root || | |
(GC_ADDRESS(GC_INFO(ref)) != 0 && | |
- GC_REF_GET_COLOR(ref) == GC_BLACK && | |
- GC_ADDRESS(GC_INFO(ref)) != GC_ROOT_BUFFER_MAX_ENTRIES)) { | |
+ GC_REF_GET_COLOR(ref) == GC_BLACK)) { | |
GC_TRACE_REF(ref, "removing from buffer"); | |
if (root) { | |
- GC_INFO(ref) = 0; | |
GC_REMOVE_FROM_ROOTS(root); | |
+ GC_INFO(ref) = 0; | |
root = NULL; | |
} else { | |
GC_REMOVE_FROM_BUFFER(ref); | |
@@ -1032,8 +1039,8 @@ ZEND_API int zend_gc_collect_cycles(void) | |
gc_root_buffer *current, *next, *orig_next_to_free; | |
zend_refcounted *p; | |
gc_root_buffer to_free; | |
+ gc_additional_buffer *additional_buf_snapshot; | |
uint32_t gc_flags = 0; | |
- gc_additional_buffer *additional_buffer; | |
#if ZEND_GC_DEBUG | |
zend_bool orig_gc_full; | |
#endif | |
@@ -1057,8 +1064,8 @@ ZEND_API int zend_gc_collect_cycles(void) | |
#endif | |
GC_TRACE("Collecting roots"); | |
- additional_buffer = NULL; | |
- count = gc_collect_roots(&gc_flags, &additional_buffer); | |
+ additional_buf_snapshot = GC_G(additional_buf); | |
+ count = gc_collect_roots(&gc_flags); | |
#if ZEND_GC_DEBUG | |
GC_G(gc_full) = orig_gc_full; | |
#endif | |
@@ -1102,7 +1109,7 @@ ZEND_API int zend_gc_collect_cycles(void) | |
while (current != &to_free) { | |
p = current->ref; | |
GC_G(next_to_free) = current->next; | |
- if ((GC_TYPE(p) & GC_TYPE_MASK) == IS_OBJECT) { | |
+ if (GC_TYPE(p) == IS_OBJECT) { | |
zend_object *obj = (zend_object*)p; | |
if (IS_OBJ_VALID(EG(objects_store).object_buckets[obj->handle]) && | |
@@ -1139,7 +1146,7 @@ ZEND_API int zend_gc_collect_cycles(void) | |
p = current->ref; | |
GC_G(next_to_free) = current->next; | |
GC_TRACE_REF(p, "destroying"); | |
- if ((GC_TYPE(p) & GC_TYPE_MASK) == IS_OBJECT) { | |
+ if (GC_TYPE(p) == IS_OBJECT) { | |
zend_object *obj = (zend_object*)p; | |
if (EG(objects_store).object_buckets && | |
@@ -1158,7 +1165,7 @@ ZEND_API int zend_gc_collect_cycles(void) | |
EG(objects_store).free_list_head = obj->handle; | |
p = current->ref = (zend_refcounted*)(((char*)obj) - obj->handlers->offset); | |
} | |
- } else if ((GC_TYPE(p) & GC_TYPE_MASK) == IS_ARRAY) { | |
+ } else if (GC_TYPE(p) == IS_ARRAY) { | |
zend_array *arr = (zend_array*)p; | |
GC_TYPE(arr) = IS_NULL; | |
@@ -1180,13 +1187,14 @@ ZEND_API int zend_gc_collect_cycles(void) | |
current = next; | |
} | |
- while (additional_buffer != NULL) { | |
- gc_additional_buffer *next = additional_buffer->next; | |
- efree(additional_buffer); | |
- additional_buffer = next; | |
+ while (GC_G(additional_buf) != additional_buf_snapshot) { | |
+ gc_additional_buffer *next = GC_G(additional_buf)->next; | |
+ efree(GC_G(additional_buf)); | |
+ GC_G(additional_buf) = next; | |
} | |
GC_TRACE("Collection finished"); | |
+ GC_G(additional_buf) = additional_buf_snapshot; | |
GC_G(collected) += count; | |
GC_G(next_to_free) = orig_next_to_free; | |
#if ZEND_GC_DEBUG | |
diff --git a/Zend/zend_gc.h b/Zend/zend_gc.h | |
index 8e3bc46..1c6aab9 100644 | |
--- a/Zend/zend_gc.h | |
+++ b/Zend/zend_gc.h | |
@@ -67,6 +67,15 @@ typedef struct _gc_root_buffer { | |
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_buffer { | |
+ uint32_t used; | |
+ struct _gc_additional_buffer *next; | |
+ gc_root_buffer buf[GC_NUM_ADDITIONAL_ENTRIES]; | |
+} gc_additional_buffer; | |
+ | |
typedef struct _zend_gc_globals { | |
zend_bool gc_enabled; | |
zend_bool gc_active; | |
@@ -92,7 +101,7 @@ typedef struct _zend_gc_globals { | |
uint32_t zval_remove_from_buffer; | |
uint32_t zval_marked_grey; | |
#endif | |
- | |
+ gc_additional_buffer *additional_buf; | |
} zend_gc_globals; | |
#ifdef ZTS |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment