Skip to content

Commit 67b5d8f

Browse files
committed
Don't reverse class order during preloading
We don't guarantee any particular order, but this reduces test failures under --preload that are sensitive to class order. Add some ZEND_HASH_FOREACH_*_FROM macros to allow skipping the persistent classes while iterating in forward direction.
1 parent d836046 commit 67b5d8f

File tree

2 files changed

+34
-27
lines changed

2 files changed

+34
-27
lines changed

Zend/zend_hash.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -958,17 +958,19 @@ static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht,
958958
#define zend_hash_get_current_data_ptr(ht) \
959959
zend_hash_get_current_data_ptr_ex(ht, &(ht)->nInternalPointer)
960960

961-
#define ZEND_HASH_FOREACH(_ht, indirect) do { \
961+
#define ZEND_HASH_FOREACH_FROM(_ht, indirect, _from) do { \
962962
HashTable *__ht = (_ht); \
963-
Bucket *_p = __ht->arData; \
964-
Bucket *_end = _p + __ht->nNumUsed; \
963+
Bucket *_p = __ht->arData + (_from); \
964+
Bucket *_end = __ht->arData + __ht->nNumUsed; \
965965
for (; _p != _end; _p++) { \
966966
zval *_z = &_p->val; \
967967
if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
968968
_z = Z_INDIRECT_P(_z); \
969969
} \
970970
if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
971971

972+
#define ZEND_HASH_FOREACH(_ht, indirect) ZEND_HASH_FOREACH_FROM(_ht, indirect, 0)
973+
972974
#define ZEND_HASH_REVERSE_FOREACH(_ht, indirect) do { \
973975
HashTable *__ht = (_ht); \
974976
uint32_t _idx = __ht->nNumUsed; \
@@ -1011,6 +1013,10 @@ static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht,
10111013
ZEND_HASH_FOREACH(ht, 0); \
10121014
_bucket = _p;
10131015

1016+
#define ZEND_HASH_FOREACH_BUCKET_FROM(ht, _bucket, _from) \
1017+
ZEND_HASH_FOREACH_FROM(ht, 0, _from); \
1018+
_bucket = _p;
1019+
10141020
#define ZEND_HASH_REVERSE_FOREACH_BUCKET(ht, _bucket) \
10151021
ZEND_HASH_REVERSE_FOREACH(ht, 0); \
10161022
_bucket = _p;
@@ -1080,6 +1086,11 @@ static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht,
10801086
_key = _p->key; \
10811087
_val = _z;
10821088

1089+
#define ZEND_HASH_FOREACH_STR_KEY_VAL_FROM(ht, _key, _val, _from) \
1090+
ZEND_HASH_FOREACH_FROM(ht, 0, _from); \
1091+
_key = _p->key; \
1092+
_val = _z;
1093+
10831094
#define ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(ht, _key, _val) \
10841095
ZEND_HASH_REVERSE_FOREACH(ht, 0); \
10851096
_key = _p->key; \

ext/opcache/ZendAccelerator.c

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3564,32 +3564,28 @@ static void preload_move_user_classes(HashTable *src, HashTable *dst)
35643564

35653565
src->pDestructor = NULL;
35663566
zend_hash_extend(dst, dst->nNumUsed + src->nNumUsed, 0);
3567-
ZEND_HASH_REVERSE_FOREACH_BUCKET(src, p) {
3567+
ZEND_HASH_FOREACH_BUCKET_FROM(src, p, EG(persistent_classes_count)) {
35683568
zend_class_entry *ce = Z_PTR(p->val);
3569-
3570-
if (EXPECTED(ce->type == ZEND_USER_CLASS)) {
3571-
if (ce->info.user.filename != filename) {
3572-
filename = ce->info.user.filename;
3573-
if (filename) {
3574-
if (!(copy = zend_hash_exists(preload_scripts, filename))) {
3575-
size_t eval_len = preload_try_strip_filename(filename);
3576-
if (eval_len) {
3577-
copy = zend_hash_str_exists(preload_scripts, ZSTR_VAL(filename), eval_len);
3578-
}
3569+
ZEND_ASSERT(ce->type == ZEND_USER_CLASS);
3570+
if (ce->info.user.filename != filename) {
3571+
filename = ce->info.user.filename;
3572+
if (filename) {
3573+
if (!(copy = zend_hash_exists(preload_scripts, filename))) {
3574+
size_t eval_len = preload_try_strip_filename(filename);
3575+
if (eval_len) {
3576+
copy = zend_hash_str_exists(preload_scripts, ZSTR_VAL(filename), eval_len);
35793577
}
3580-
} else {
3581-
copy = 0;
35823578
}
3583-
}
3584-
if (copy) {
3585-
_zend_hash_append(dst, p->key, &p->val);
35863579
} else {
3587-
orig_dtor(&p->val);
3580+
copy = 0;
35883581
}
3589-
zend_hash_del_bucket(src, p);
3582+
}
3583+
if (copy) {
3584+
_zend_hash_append(dst, p->key, &p->val);
35903585
} else {
3591-
break;
3586+
orig_dtor(&p->val);
35923587
}
3588+
zend_hash_del_bucket(src, p);
35933589
} ZEND_HASH_FOREACH_END();
35943590
src->pDestructor = orig_dtor;
35953591
}
@@ -3844,11 +3840,10 @@ static void preload_link(void)
38443840
do {
38453841
changed = 0;
38463842

3847-
ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
3843+
ZEND_HASH_FOREACH_STR_KEY_VAL_FROM(EG(class_table), key, zv, EG(persistent_classes_count)) {
38483844
ce = Z_PTR_P(zv);
3849-
if (ce->type == ZEND_INTERNAL_CLASS) {
3850-
break;
3851-
}
3845+
ZEND_ASSERT(ce->type != ZEND_INTERNAL_CLASS);
3846+
38523847
if ((ce->ce_flags & (ZEND_ACC_TOP_LEVEL|ZEND_ACC_ANON_CLASS))
38533848
&& !(ce->ce_flags & ZEND_ACC_LINKED)) {
38543849
zend_string *lcname = zend_string_tolower(ce->name);
@@ -3967,7 +3962,8 @@ static void preload_link(void)
39673962
} while (changed);
39683963

39693964
/* Warn for classes that could not be linked. */
3970-
ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
3965+
ZEND_HASH_FOREACH_STR_KEY_VAL_FROM(
3966+
EG(class_table), key, zv, EG(persistent_classes_count)) {
39713967
ce = Z_PTR_P(zv);
39723968
if (ce->type == ZEND_INTERNAL_CLASS) {
39733969
break;

0 commit comments

Comments
 (0)