Skip to content

Commit 816b69e

Browse files
committed
[Proposal] Reduce the minimum size for packed arrays from 8 to 2
Continue to require that associative arrays have a minimum size of 8 and are powers of 8. This can reduce the memory usage of some applications by ~16% in applications that heavily use small arrays. Stop requiring that packed arrays have a size that is a power of 2. There's no reason to for packed arrays, since php isn't doing any hash lookups with bit operations. Add a helper to create an associative array with a minimum size. This may help with clarity/avoiding unnecessary size recalculations. (performance impact may be negligible) https://nikic.github.io/2014/12/22/PHPs-new-hashtable-implementation.html gives some background information on the `HashTable` implementation on master. This is a followup to #4753 (comment) (I didn't see any other PRs mentioning HT_MIN_SIZE)
1 parent e40da26 commit 816b69e

22 files changed

+108
-48
lines changed

Zend/zend_API.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3271,7 +3271,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_nam
32713271
if (zend_is_callable_ex(callable, NULL, 0, callable_name, &fcc, NULL)) {
32723272
if (Z_TYPE_P(callable) == IS_STRING && fcc.calling_scope) {
32733273
zval_ptr_dtor_str(callable);
3274-
array_init(callable);
3274+
array_init_size(callable, 2);
32753275
add_next_index_str(callable, zend_string_copy(fcc.calling_scope->name));
32763276
add_next_index_str(callable, zend_string_copy(fcc.function_handler->common.function_name));
32773277
}

Zend/zend_API.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,10 @@ ZEND_API const char *zend_get_type_by_const(int type);
376376
#define DLEXPORT
377377
#endif
378378

379-
#define array_init(arg) ZVAL_ARR((arg), zend_new_array(0))
380-
#define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size))
379+
#define array_init(arg) ZVAL_ARR((arg), zend_new_array(0))
380+
#define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size))
381+
#define array_init_assoc(arg) ZVAL_ARR((arg), zend_new_array_assoc(0))
382+
#define array_init_assoc_size(arg, size) ZVAL_ARR((arg), zend_new_array_assoc(size))
381383
ZEND_API int object_init(zval *arg);
382384
ZEND_API int object_init_ex(zval *arg, zend_class_entry *ce);
383385
ZEND_API int object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties);

Zend/zend_ast.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ static int zend_ast_add_unpacked_element(zval *result, zval *expr) {
451451
HashTable *ht = Z_ARRVAL_P(expr);
452452
zval *val;
453453
zend_string *key;
454-
454+
455455
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) {
456456
if (key) {
457457
zend_throw_error(NULL, "Cannot unpack array with string keys");
@@ -661,13 +661,15 @@ ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_c
661661
{
662662
uint32_t i;
663663
zend_ast_list *list = zend_ast_get_list(ast);
664+
uint32_t n_children = list->children;
664665

665-
if (!list->children) {
666+
if (!n_children) {
666667
ZVAL_EMPTY_ARRAY(result);
667668
break;
668669
}
669-
array_init(result);
670-
for (i = 0; i < list->children; i++) {
670+
/** Usually, there won't be an AST_UNPACK or duplicate keys. Assume that's the initial capacity. */
671+
array_init_size(result, n_children);
672+
for (i = 0; i < n_children; i++) {
671673
zend_ast *elem = list->child[i];
672674
if (elem->kind == ZEND_AST_UNPACK) {
673675
if (UNEXPECTED(zend_ast_evaluate(&op1, elem->child[0], scope) != SUCCESS)) {

Zend/zend_builtin_functions.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ ZEND_FUNCTION(gc_status)
280280

281281
zend_gc_get_status(&status);
282282

283-
array_init_size(return_value, 3);
283+
array_init_assoc_size(return_value, 4);
284284

285285
add_assoc_long_ex(return_value, "runs", sizeof("runs")-1, (long)status.runs);
286286
add_assoc_long_ex(return_value, "collected", sizeof("collected")-1, (long)status.collected);

Zend/zend_execute.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2101,7 +2101,7 @@ static zend_always_inline void zend_fetch_dimension_address(zval *result, zval *
21012101
return;
21022102
}
21032103
}
2104-
array_init(container);
2104+
array_init(container); /* TODO benchmark and check if array_init_assoc is faster */
21052105
goto fetch_from_array;
21062106
} else {
21072107
goto return_null;

Zend/zend_hash.c

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,18 @@ static zend_always_inline void zend_hash_real_init_mixed_ex(HashTable *ht)
144144
uint32_t nSize = ht->nTableSize;
145145

146146
if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) {
147+
if (nSize < HT_MIN_SIZE_UNPACKED) {
148+
nSize = HT_MIN_SIZE_UNPACKED;
149+
ht->nTableSize = HT_MIN_SIZE_UNPACKED;
150+
}
147151
data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), 1);
148-
} else if (EXPECTED(nSize == HT_MIN_SIZE)) {
149-
data = emalloc(HT_SIZE_EX(HT_MIN_SIZE, HT_SIZE_TO_MASK(HT_MIN_SIZE)));
150-
ht->nTableMask = HT_SIZE_TO_MASK(HT_MIN_SIZE);
152+
} else if (EXPECTED(nSize <= HT_MIN_SIZE_UNPACKED)) {
153+
if (nSize < HT_MIN_SIZE_UNPACKED) {
154+
nSize = HT_MIN_SIZE_UNPACKED;
155+
ht->nTableSize = HT_MIN_SIZE_UNPACKED;
156+
}
157+
data = emalloc(HT_SIZE_EX(HT_MIN_SIZE_UNPACKED, HT_SIZE_TO_MASK(HT_MIN_SIZE_UNPACKED)));
158+
ht->nTableMask = HT_SIZE_TO_MASK(HT_MIN_SIZE_UNPACKED);
151159
HT_SET_DATA_ADDR(ht, data);
152160
/* Don't overwrite iterator count. */
153161
ht->u.v.flags = HASH_FLAG_STATIC_KEYS;
@@ -210,6 +218,7 @@ static zend_always_inline void zend_hash_real_init_ex(HashTable *ht, int packed)
210218
static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
211219
{HT_INVALID_IDX, HT_INVALID_IDX};
212220

221+
/* XXX: Is MIN_SIZE_UNPACKED the best choice vs this (8 vs 2)? Haven't benchmarked it. */
213222
ZEND_API const HashTable zend_empty_array = {
214223
.gc.refcount = 2,
215224
.gc.u.type_info = IS_ARRAY | (GC_IMMUTABLE << GC_FLAGS_SHIFT),
@@ -218,7 +227,7 @@ ZEND_API const HashTable zend_empty_array = {
218227
.arData = (Bucket*)&uninitialized_bucket[2],
219228
.nNumUsed = 0,
220229
.nNumOfElements = 0,
221-
.nTableSize = HT_MIN_SIZE,
230+
.nTableSize = HT_MIN_SIZE_UNPACKED,
222231
.nInternalPointer = 0,
223232
.nNextFreeElement = 0,
224233
.pDestructor = ZVAL_PTR_DTOR
@@ -236,7 +245,8 @@ static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize
236245
ht->nInternalPointer = 0;
237246
ht->nNextFreeElement = ZEND_LONG_MIN;
238247
ht->pDestructor = pDestructor;
239-
ht->nTableSize = zend_hash_check_size(nSize);
248+
/* TODO: Decide on the best way to specify the size of a packed table exactly? This is a first attempt*/
249+
ht->nTableSize = (nSize <= HT_MIN_SIZE_UNPACKED ? (nSize < HT_MIN_SIZE ? HT_MIN_SIZE : nSize) : zend_hash_check_size(nSize));
240250
}
241251

242252
ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent)
@@ -251,17 +261,32 @@ ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void)
251261
return ht;
252262
}
253263

264+
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_assoc_0(void)
265+
{
266+
HashTable *ht = emalloc(sizeof(HashTable));
267+
_zend_hash_init_int(ht, HT_MIN_SIZE_UNPACKED, ZVAL_PTR_DTOR, 0);
268+
return ht;
269+
}
270+
254271
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize)
255272
{
256273
HashTable *ht = emalloc(sizeof(HashTable));
257274
_zend_hash_init_int(ht, nSize, ZVAL_PTR_DTOR, 0);
258275
return ht;
259276
}
260277

278+
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_assoc(uint32_t nSize)
279+
{
280+
HashTable *ht = emalloc(sizeof(HashTable));
281+
_zend_hash_init_int(ht, nSize < HT_MIN_SIZE_UNPACKED ? HT_MIN_SIZE_UNPACKED : nSize, ZVAL_PTR_DTOR, 0);
282+
return ht;
283+
}
284+
261285
ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2)
262286
{
263287
Bucket *p;
264288
HashTable *ht = emalloc(sizeof(HashTable));
289+
/* XXX: Currently, HT_MIN_SIZE == 2. will need to adjust all calls like this if HT_MIN_SIZE goes below 2 */
265290
_zend_hash_init_int(ht, HT_MIN_SIZE, ZVAL_PTR_DTOR, 0);
266291
ht->nNumUsed = ht->nNumOfElements = ht->nNextFreeElement = 2;
267292
zend_hash_real_init_packed_ex(ht);
@@ -317,11 +342,18 @@ ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht)
317342
void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
318343
Bucket *old_buckets = ht->arData;
319344
uint32_t nSize = ht->nTableSize;
345+
if (nSize < HT_MIN_SIZE_UNPACKED) {
346+
nSize = HT_MIN_SIZE_UNPACKED;
347+
ht->nTableSize = HT_MIN_SIZE_UNPACKED;
348+
} else if (nSize & (nSize - 1)) {
349+
nSize = zend_hash_check_size(nSize);
350+
ht->nTableSize = nSize;
351+
}
320352

321353
HT_ASSERT_RC1(ht);
322354
HT_FLAGS(ht) &= ~HASH_FLAG_PACKED;
323355
new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
324-
ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize);
356+
ht->nTableMask = HT_SIZE_TO_MASK(nSize);
325357
HT_SET_DATA_ADDR(ht, new_data);
326358
memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
327359
pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
@@ -1155,14 +1187,14 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht)
11551187

11561188
if (ht->nNumUsed > ht->nNumOfElements + (ht->nNumOfElements >> 5)) { /* additional term is there to amortize the cost of compaction */
11571189
zend_hash_rehash(ht);
1158-
} else if (ht->nTableSize < HT_MAX_SIZE) { /* Let's double the table size */
1190+
} else if (EXPECTED(ht->nTableSize < HT_MAX_SIZE)) { /* Let's double the table size */
11591191
void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
1160-
uint32_t nSize = ht->nTableSize + ht->nTableSize;
1192+
uint32_t nSize = zend_hash_check_size(ht->nTableSize + ht->nTableSize);
11611193
Bucket *old_buckets = ht->arData;
11621194

11631195
ht->nTableSize = nSize;
11641196
new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
1165-
ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize);
1197+
ht->nTableMask = HT_SIZE_TO_MASK(nSize);
11661198
HT_SET_DATA_ADDR(ht, new_data);
11671199
memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
11681200
pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);

Zend/zend_hash.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,13 +290,27 @@ ZEND_API void ZEND_FASTCALL zend_hash_rehash(HashTable *ht);
290290
: \
291291
_zend_new_array((size)) \
292292
)
293+
# define zend_new_array_assoc(size) \
294+
(__builtin_constant_p(size) ? \
295+
((((uint32_t)(size)) <= HT_MIN_SIZE_UNPACKED) ? \
296+
_zend_new_array_assoc_0() \
297+
: \
298+
_zend_new_array_assoc((size)) \
299+
) \
300+
: \
301+
_zend_new_array_assoc((size)) \
302+
)
293303
#else
294304
# define zend_new_array(size) \
295305
_zend_new_array(size)
306+
# define zend_new_array_assoc(size) \
307+
_zend_new_array_assoc(size)
296308
#endif
297309

298310
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void);
311+
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_assoc_0(void);
299312
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size);
313+
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_assoc(uint32_t size);
300314
ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2);
301315
ZEND_API uint32_t zend_array_count(HashTable *ht);
302316
ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source);

Zend/zend_operators.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ ZEND_API void ZEND_FASTCALL convert_to_array(zval *op) /* {{{ */
633633
} else {
634634
zval_ptr_dtor(op);
635635
/*ZVAL_EMPTY_ARRAY(op);*/
636-
array_init(op);
636+
array_init_assoc(op);
637637
}
638638
}
639639
break;

Zend/zend_types.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,8 @@ struct _zend_array {
302302
#define HT_INVALID_IDX ((uint32_t) -1)
303303

304304
#define HT_MIN_MASK ((uint32_t) -2)
305-
#define HT_MIN_SIZE 8
305+
#define HT_MIN_SIZE 2
306+
#define HT_MIN_SIZE_UNPACKED 8
306307

307308
#if SIZEOF_SIZE_T == 4
308309
# define HT_MAX_SIZE 0x04000000 /* small enough to avoid overflow checks */
@@ -330,7 +331,7 @@ struct _zend_array {
330331
HT_HASH_EX((ht)->arData, idx)
331332

332333
#define HT_SIZE_TO_MASK(nTableSize) \
333-
((uint32_t)(-((nTableSize) + (nTableSize))))
334+
(uint32_t)(-(zend_hash_check_size((nTableSize) + (nTableSize))))
334335
#define HT_HASH_SIZE(nTableMask) \
335336
(((size_t)(uint32_t)-(int32_t)(nTableMask)) * sizeof(uint32_t))
336337
#define HT_DATA_SIZE(nTableSize) \
@@ -347,7 +348,15 @@ struct _zend_array {
347348
size_t size = HT_HASH_SIZE((ht)->nTableMask); \
348349
__m128i xmm0 = _mm_setzero_si128(); \
349350
xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \
350-
ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \
351+
if (size < 64) { \
352+
ZEND_ASSERT(size == 16 || size == 32); \
353+
_mm_storeu_si128((__m128i*)p, xmm0); \
354+
if (size >= 32) { \
355+
_mm_storeu_si128((__m128i*)(p+16), xmm0); \
356+
} \
357+
break; \
358+
} \
359+
ZEND_ASSERT(((size & 0x3f) == 0)); \
351360
do { \
352361
_mm_storeu_si128((__m128i*)p, xmm0); \
353362
_mm_storeu_si128((__m128i*)(p+16), xmm0); \

Zend/zend_vm_def.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,7 +1567,7 @@ ZEND_VM_HELPER(zend_pre_dec_helper, VAR|CV, ANY)
15671567

15681568
SAVE_OPLINE();
15691569
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) {
1570-
ZVAL_NULL(var_ptr);
1570+
ZVAL_NULL(var_ptr);
15711571
ZVAL_UNDEFINED_OP1();
15721572
}
15731573

@@ -2323,7 +2323,7 @@ ZEND_VM_C_LABEL(fetch_obj_is_fast_copy):
23232323
}
23242324

23252325
retval = zobj->handlers->read_property(zobj, name, BP_VAR_IS, cache_slot, EX_VAR(opline->result.var));
2326-
2326+
23272327
if (OP2_TYPE != IS_CONST) {
23282328
zend_tmp_string_release(tmp_name);
23292329
}
@@ -5669,10 +5669,10 @@ ZEND_VM_HANDLER(147, ZEND_ADD_ARRAY_UNPACK, ANY, ANY)
56695669
{
56705670
USE_OPLINE
56715671
zval *op1;
5672-
5672+
56735673
SAVE_OPLINE();
56745674
op1 = GET_OP1_ZVAL_PTR(BP_VAR_R);
5675-
5675+
56765676
ZEND_VM_C_LABEL(add_unpack_again):
56775677
if (EXPECTED(Z_TYPE_P(op1) == IS_ARRAY)) {
56785678
HashTable *ht = Z_ARRVAL_P(op1);
@@ -5713,11 +5713,11 @@ ZEND_VM_C_LABEL(add_unpack_again):
57135713
}
57145714
HANDLE_EXCEPTION();
57155715
}
5716-
5716+
57175717
if (iter->funcs->rewind) {
57185718
iter->funcs->rewind(iter);
57195719
}
5720-
5720+
57215721
for (; iter->funcs->valid(iter) == SUCCESS; ) {
57225722
zval *val;
57235723

@@ -5766,7 +5766,7 @@ ZEND_VM_C_LABEL(add_unpack_again):
57665766
} else {
57675767
zend_throw_error(NULL, "Only arrays and Traversables can be unpacked");
57685768
}
5769-
5769+
57705770
FREE_OP1();
57715771
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
57725772
}
@@ -5871,7 +5871,7 @@ ZEND_VM_COLD_CONST_HANDLER(51, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE)
58715871
}
58725872
Z_OBJ_P(result)->properties = ht;
58735873
} else if (Z_TYPE_P(expr) != IS_NULL) {
5874-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
5874+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
58755875
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
58765876
if (OP1_TYPE == IS_CONST) {
58775877
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);

Zend/zend_vm_execute.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3989,7 +3989,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_H
39893989
}
39903990
Z_OBJ_P(result)->properties = ht;
39913991
} else if (Z_TYPE_P(expr) != IS_NULL) {
3992-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
3992+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
39933993
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
39943994
if (IS_CONST == IS_CONST) {
39953995
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);
@@ -18066,7 +18066,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPC
1806618066
}
1806718067
Z_OBJ_P(result)->properties = ht;
1806818068
} else if (Z_TYPE_P(expr) != IS_NULL) {
18069-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
18069+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
1807018070
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
1807118071
if (IS_TMP_VAR == IS_CONST) {
1807218072
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);
@@ -21058,7 +21058,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPC
2105821058
}
2105921059
Z_OBJ_P(result)->properties = ht;
2106021060
} else if (Z_TYPE_P(expr) != IS_NULL) {
21061-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
21061+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
2106221062
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
2106321063
if (IS_VAR == IS_CONST) {
2106421064
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);
@@ -37754,7 +37754,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCO
3775437754
}
3775537755
Z_OBJ_P(result)->properties = ht;
3775637756
} else if (Z_TYPE_P(expr) != IS_NULL) {
37757-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
37757+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
3775837758
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
3775937759
if (IS_CV == IS_CONST) {
3776037760
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);

ext/json/json_parser.y

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ static int php_json_parser_array_append(php_json_parser *parser, zval *array, zv
230230
static int php_json_parser_object_create(php_json_parser *parser, zval *object)
231231
{
232232
if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) {
233-
array_init(object);
233+
array_init_assoc(object);
234234
return SUCCESS;
235235
} else {
236236
return object_init(object);

ext/opcache/zend_persist.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ static void zend_hash_persist(HashTable *ht)
115115
void *data = HT_GET_DATA_ADDR(ht);
116116
data = zend_shared_memdup_free(data, HT_USED_SIZE(ht));
117117
HT_SET_DATA_ADDR(ht, data);
118-
} else if (ht->nNumUsed > HT_MIN_SIZE && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) {
118+
} else if (ht->nNumUsed > HT_MIN_SIZE_UNPACKED && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) {
119+
/* TODO any special considerations for this? */
119120
/* compact table */
120121
void *old_data = HT_GET_DATA_ADDR(ht);
121122
Bucket *old_buckets = ht->arData;

ext/opcache/zend_persist_calc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ static void zend_hash_persist_calc(HashTable *ht)
6161
return;
6262
}
6363

64-
if (!(HT_FLAGS(ht) & HASH_FLAG_PACKED) && ht->nNumUsed > HT_MIN_SIZE && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) {
64+
if (!(HT_FLAGS(ht) & HASH_FLAG_PACKED) && ht->nNumUsed > HT_MIN_SIZE_UNPACKED && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) {
6565
/* compact table */
6666
uint32_t hash_size;
6767

0 commit comments

Comments
 (0)