Skip to content

Commit 3db5c6d

Browse files
committed
GC optimization for primitive arrays
PoC for GH-19608
1 parent b27d919 commit 3db5c6d

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

Zend/zend_gc.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,9 @@ static void gc_scan_black(zend_refcounted *ref, gc_stack *stack)
983983
handle_ht:
984984
n = ht->nNumUsed;
985985
zv = ht->arPacked;
986+
if (GC_FLAGS(ht) & GC_NOT_COLLECTABLE) {
987+
goto next;
988+
}
986989
if (HT_IS_PACKED(ht)) {
987990
goto handle_zvals;
988991
}
@@ -1041,7 +1044,7 @@ static void gc_scan_black(zend_refcounted *ref, gc_stack *stack)
10411044
* counts and mark visited nodes grey. See MarkGray() in Bacon & Rajan. */
10421045
static void gc_mark_grey(zend_refcounted *ref, gc_stack *stack)
10431046
{
1044-
HashTable *ht;
1047+
HashTable *ht, *zvals_ht = NULL;
10451048
Bucket *p;
10461049
zval *zv;
10471050
uint32_t n;
@@ -1129,9 +1132,11 @@ static void gc_mark_grey(zend_refcounted *ref, gc_stack *stack)
11291132
goto handle_ht;
11301133
}
11311134
}
1132-
handle_zvals:
1135+
handle_zvals:;
1136+
bool is_primitive = true;
11331137
for (; n != 0; n--) {
11341138
if (Z_COLLECTABLE_P(zv)) {
1139+
is_primitive = false;
11351140
ref = Z_COUNTED_P(zv);
11361141
GC_DELREF(ref);
11371142
if (!GC_REF_CHECK_COLOR(ref, GC_GREY)) {
@@ -1148,29 +1153,40 @@ static void gc_mark_grey(zend_refcounted *ref, gc_stack *stack)
11481153
}
11491154
zv++;
11501155
}
1156+
zvals_ht = NULL;
11511157
goto tail_call;
11521158
}
11531159
}
11541160
zv++;
11551161
}
1162+
if (is_primitive && zvals_ht) {
1163+
GC_ADD_FLAGS(zvals_ht, GC_NOT_COLLECTABLE);
1164+
}
1165+
zvals_ht = NULL;
11561166
}
11571167
} else if (GC_TYPE(ref) == IS_ARRAY) {
11581168
ZEND_ASSERT(((zend_array*)ref) != &EG(symbol_table));
11591169
ht = (zend_array*)ref;
11601170
handle_ht:
11611171
n = ht->nNumUsed;
1172+
if (GC_FLAGS(ht) & GC_NOT_COLLECTABLE) {
1173+
goto next;
1174+
}
11621175
if (HT_IS_PACKED(ht)) {
11631176
zv = ht->arPacked;
1177+
zvals_ht = ht;
11641178
goto handle_zvals;
11651179
}
11661180

1181+
bool is_primitive = true;
11671182
p = ht->arData;
11681183
for (; n != 0; n--) {
11691184
zv = &p->val;
11701185
if (Z_TYPE_P(zv) == IS_INDIRECT) {
11711186
zv = Z_INDIRECT_P(zv);
11721187
}
11731188
if (Z_COLLECTABLE_P(zv)) {
1189+
is_primitive = false;
11741190
ref = Z_COUNTED_P(zv);
11751191
GC_DELREF(ref);
11761192
if (!GC_REF_CHECK_COLOR(ref, GC_GREY)) {
@@ -1196,6 +1212,9 @@ static void gc_mark_grey(zend_refcounted *ref, gc_stack *stack)
11961212
}
11971213
p++;
11981214
}
1215+
if (is_primitive) {
1216+
GC_ADD_FLAGS(ht, GC_NOT_COLLECTABLE);
1217+
}
11991218
} else if (GC_TYPE(ref) == IS_REFERENCE) {
12001219
if (Z_COLLECTABLE(((zend_reference*)ref)->val)) {
12011220
ref = Z_COUNTED(((zend_reference*)ref)->val);
@@ -1378,6 +1397,9 @@ static void gc_scan(zend_refcounted *ref, gc_stack *stack)
13781397

13791398
handle_ht:
13801399
n = ht->nNumUsed;
1400+
if (GC_FLAGS(ht) & GC_NOT_COLLECTABLE) {
1401+
goto next;
1402+
}
13811403
if (HT_IS_PACKED(ht)) {
13821404
zv = ht->arPacked;
13831405
goto handle_zvals;
@@ -1623,6 +1645,9 @@ static int gc_collect_white(zend_refcounted *ref, uint32_t *flags, gc_stack *sta
16231645

16241646
handle_ht:
16251647
n = ht->nNumUsed;
1648+
if (GC_FLAGS(ht) & GC_NOT_COLLECTABLE) {
1649+
goto next;
1650+
}
16261651
if (HT_IS_PACKED(ht)) {
16271652
zv = ht->arPacked;
16281653
goto handle_zvals;
@@ -1811,6 +1836,9 @@ static int gc_remove_nested_data_from_buffer(zend_refcounted *ref, gc_root_buffe
18111836

18121837
handle_ht:
18131838
n = ht->nNumUsed;
1839+
if (GC_FLAGS(ht) & GC_NOT_COLLECTABLE) {
1840+
goto next;
1841+
}
18141842
if (HT_IS_PACKED(ht)) {
18151843
zv = ht->arPacked;
18161844
goto handle_zvals;

Zend/zend_hash.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,7 @@ static zend_always_inline zval *_zend_hash_add_or_update_i(HashTable *ht, zend_s
885885
nIndex = h | ht->nTableMask;
886886
Z_NEXT(p->val) = HT_HASH_EX(arData, nIndex);
887887
HT_HASH_EX(arData, nIndex) = HT_IDX_TO_HASH(idx);
888+
GC_DEL_FLAGS(ht, GC_NOT_COLLECTABLE);
888889
if (flag & HASH_LOOKUP) {
889890
ZVAL_NULL(&p->val);
890891
} else {
@@ -970,6 +971,7 @@ static zend_always_inline zval *_zend_hash_str_add_or_update_i(HashTable *ht, co
970971
nIndex = h | ht->nTableMask;
971972
Z_NEXT(p->val) = HT_HASH(ht, nIndex);
972973
HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
974+
GC_DEL_FLAGS(ht, GC_NOT_COLLECTABLE);
973975

974976
return &p->val;
975977
}
@@ -1172,6 +1174,7 @@ static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht,
11721174
p = ht->arData + idx;
11731175
Z_NEXT(p->val) = HT_HASH(ht, nIndex);
11741176
HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
1177+
GC_DEL_FLAGS(ht, GC_NOT_COLLECTABLE);
11751178
if ((zend_long)h >= ht->nNextFreeElement) {
11761179
ht->nNextFreeElement = (zend_long)h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
11771180
}

Zend/zend_hash.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1638,6 +1638,7 @@ static zend_always_inline zval *_zend_hash_append_ex(HashTable *ht, zend_string
16381638
nIndex = (uint32_t)p->h | ht->nTableMask;
16391639
Z_NEXT(p->val) = HT_HASH(ht, nIndex);
16401640
HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
1641+
GC_DEL_FLAGS(ht, GC_NOT_COLLECTABLE);
16411642
ht->nNumOfElements++;
16421643
return &p->val;
16431644
}
@@ -1664,6 +1665,7 @@ static zend_always_inline zval *_zend_hash_append_ptr_ex(HashTable *ht, zend_str
16641665
nIndex = (uint32_t)p->h | ht->nTableMask;
16651666
Z_NEXT(p->val) = HT_HASH(ht, nIndex);
16661667
HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
1668+
GC_DEL_FLAGS(ht, GC_NOT_COLLECTABLE);
16671669
ht->nNumOfElements++;
16681670
return &p->val;
16691671
}
@@ -1690,6 +1692,7 @@ static zend_always_inline void _zend_hash_append_ind(HashTable *ht, zend_string
16901692
nIndex = (uint32_t)p->h | ht->nTableMask;
16911693
Z_NEXT(p->val) = HT_HASH(ht, nIndex);
16921694
HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
1695+
GC_DEL_FLAGS(ht, GC_NOT_COLLECTABLE);
16931696
ht->nNumOfElements++;
16941697
}
16951698

0 commit comments

Comments
 (0)