Skip to content

Commit 751f0ef

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 271bc68 commit 751f0ef

22 files changed

+100
-40
lines changed

Zend/zend_API.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3299,7 +3299,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_nam
32993299
if (zend_is_callable_ex(callable, NULL, 0, callable_name, &fcc, NULL)) {
33003300
if (Z_TYPE_P(callable) == IS_STRING && fcc.calling_scope) {
33013301
zval_ptr_dtor_str(callable);
3302-
array_init(callable);
3302+
array_init_size(callable, 2);
33033303
add_next_index_str(callable, zend_string_copy(fcc.calling_scope->name));
33043304
add_next_index_str(callable, zend_string_copy(fcc.function_handler->common.function_name));
33053305
}

Zend/zend_API.h

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

419-
#define array_init(arg) ZVAL_ARR((arg), zend_new_array(0))
420-
#define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size))
419+
#define array_init(arg) ZVAL_ARR((arg), zend_new_array(0))
420+
#define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size))
421+
#define array_init_assoc(arg) ZVAL_ARR((arg), zend_new_array_assoc(0))
422+
#define array_init_assoc_size(arg, size) ZVAL_ARR((arg), zend_new_array_assoc(size))
421423
ZEND_API int object_init(zval *arg);
422424
ZEND_API int object_init_ex(zval *arg, zend_class_entry *ce);
423425
ZEND_API int object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties);

Zend/zend_ast.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -692,13 +692,15 @@ ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_c
692692
{
693693
uint32_t i;
694694
zend_ast_list *list = zend_ast_get_list(ast);
695+
uint32_t n_children = list->children;
695696

696-
if (!list->children) {
697+
if (!n_children) {
697698
ZVAL_EMPTY_ARRAY(result);
698699
break;
699700
}
700-
array_init(result);
701-
for (i = 0; i < list->children; i++) {
701+
/** Usually, there won't be an AST_UNPACK or duplicate keys. Assume that's the initial capacity. */
702+
array_init_size(result, n_children);
703+
for (i = 0; i < n_children; i++) {
702704
zend_ast *elem = list->child[i];
703705
if (elem->kind == ZEND_AST_UNPACK) {
704706
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
@@ -145,7 +145,7 @@ ZEND_FUNCTION(gc_status)
145145

146146
zend_gc_get_status(&status);
147147

148-
array_init_size(return_value, 3);
148+
array_init_assoc_size(return_value, 4);
149149

150150
add_assoc_long_ex(return_value, "runs", sizeof("runs")-1, (long)status.runs);
151151
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
@@ -2165,7 +2165,7 @@ static zend_always_inline void zend_fetch_dimension_address(zval *result, zval *
21652165
return;
21662166
}
21672167
}
2168-
array_init(container);
2168+
array_init(container); /* TODO benchmark and check if array_init_assoc is faster */
21692169
goto fetch_from_array;
21702170
} else {
21712171
goto return_null;

Zend/zend_hash.c

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

168168
if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) {
169+
if (nSize < HT_MIN_SIZE_UNPACKED) {
170+
nSize = HT_MIN_SIZE_UNPACKED;
171+
ht->nTableSize = HT_MIN_SIZE_UNPACKED;
172+
}
169173
data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), 1);
170-
} else if (EXPECTED(nSize == HT_MIN_SIZE)) {
171-
data = emalloc(HT_SIZE_EX(HT_MIN_SIZE, HT_SIZE_TO_MASK(HT_MIN_SIZE)));
172-
ht->nTableMask = HT_SIZE_TO_MASK(HT_MIN_SIZE);
174+
} else if (EXPECTED(nSize <= HT_MIN_SIZE_UNPACKED)) {
175+
if (nSize < HT_MIN_SIZE_UNPACKED) {
176+
nSize = HT_MIN_SIZE_UNPACKED;
177+
ht->nTableSize = HT_MIN_SIZE_UNPACKED;
178+
}
179+
data = emalloc(HT_SIZE_EX(HT_MIN_SIZE_UNPACKED, HT_SIZE_TO_MASK(HT_MIN_SIZE_UNPACKED)));
180+
ht->nTableMask = HT_SIZE_TO_MASK(HT_MIN_SIZE_UNPACKED);
173181
HT_SET_DATA_ADDR(ht, data);
174182
/* Don't overwrite iterator count. */
175183
ht->u.v.flags = HASH_FLAG_STATIC_KEYS;
@@ -232,6 +240,7 @@ static zend_always_inline void zend_hash_real_init_ex(HashTable *ht, int packed)
232240
static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
233241
{HT_INVALID_IDX, HT_INVALID_IDX};
234242

243+
/* XXX: Is MIN_SIZE_UNPACKED the best choice vs this (8 vs 2)? Haven't benchmarked it. */
235244
ZEND_API const HashTable zend_empty_array = {
236245
.gc.refcount = 2,
237246
.gc.u.type_info = IS_ARRAY | (GC_IMMUTABLE << GC_FLAGS_SHIFT),
@@ -240,7 +249,7 @@ ZEND_API const HashTable zend_empty_array = {
240249
.arData = (Bucket*)&uninitialized_bucket[2],
241250
.nNumUsed = 0,
242251
.nNumOfElements = 0,
243-
.nTableSize = HT_MIN_SIZE,
252+
.nTableSize = HT_MIN_SIZE_UNPACKED,
244253
.nInternalPointer = 0,
245254
.nNextFreeElement = 0,
246255
.pDestructor = ZVAL_PTR_DTOR
@@ -258,7 +267,8 @@ static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize
258267
ht->nInternalPointer = 0;
259268
ht->nNextFreeElement = ZEND_LONG_MIN;
260269
ht->pDestructor = pDestructor;
261-
ht->nTableSize = zend_hash_check_size(nSize);
270+
/* TODO: Decide on the best way to specify the size of a packed table exactly? This is a first attempt*/
271+
ht->nTableSize = (nSize <= HT_MIN_SIZE_UNPACKED ? (nSize < HT_MIN_SIZE ? HT_MIN_SIZE : nSize) : zend_hash_check_size(nSize));
262272
}
263273

264274
ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent)
@@ -273,17 +283,32 @@ ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void)
273283
return ht;
274284
}
275285

286+
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_assoc_0(void)
287+
{
288+
HashTable *ht = emalloc(sizeof(HashTable));
289+
_zend_hash_init_int(ht, HT_MIN_SIZE_UNPACKED, ZVAL_PTR_DTOR, 0);
290+
return ht;
291+
}
292+
276293
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize)
277294
{
278295
HashTable *ht = emalloc(sizeof(HashTable));
279296
_zend_hash_init_int(ht, nSize, ZVAL_PTR_DTOR, 0);
280297
return ht;
281298
}
282299

300+
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_assoc(uint32_t nSize)
301+
{
302+
HashTable *ht = emalloc(sizeof(HashTable));
303+
_zend_hash_init_int(ht, nSize < HT_MIN_SIZE_UNPACKED ? HT_MIN_SIZE_UNPACKED : nSize, ZVAL_PTR_DTOR, 0);
304+
return ht;
305+
}
306+
283307
ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2)
284308
{
285309
Bucket *p;
286310
HashTable *ht = emalloc(sizeof(HashTable));
311+
/* XXX: Currently, HT_MIN_SIZE == 2. will need to adjust all calls like this if HT_MIN_SIZE goes below 2 */
287312
_zend_hash_init_int(ht, HT_MIN_SIZE, ZVAL_PTR_DTOR, 0);
288313
ht->nNumUsed = ht->nNumOfElements = ht->nNextFreeElement = 2;
289314
zend_hash_real_init_packed_ex(ht);
@@ -339,11 +364,18 @@ ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht)
339364
void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
340365
Bucket *old_buckets = ht->arData;
341366
uint32_t nSize = ht->nTableSize;
367+
if (nSize < HT_MIN_SIZE_UNPACKED) {
368+
nSize = HT_MIN_SIZE_UNPACKED;
369+
ht->nTableSize = HT_MIN_SIZE_UNPACKED;
370+
} else if (nSize & (nSize - 1)) {
371+
nSize = zend_hash_check_size(nSize);
372+
ht->nTableSize = nSize;
373+
}
342374

343375
HT_ASSERT_RC1(ht);
344376
HT_FLAGS(ht) &= ~HASH_FLAG_PACKED;
345377
new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
346-
ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize);
378+
ht->nTableMask = HT_SIZE_TO_MASK(nSize);
347379
HT_SET_DATA_ADDR(ht, new_data);
348380
memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
349381
pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
@@ -1177,14 +1209,14 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht)
11771209

11781210
if (ht->nNumUsed > ht->nNumOfElements + (ht->nNumOfElements >> 5)) { /* additional term is there to amortize the cost of compaction */
11791211
zend_hash_rehash(ht);
1180-
} else if (ht->nTableSize < HT_MAX_SIZE) { /* Let's double the table size */
1212+
} else if (EXPECTED(ht->nTableSize < HT_MAX_SIZE)) { /* Let's double the table size */
11811213
void *new_data, *old_data = HT_GET_DATA_ADDR(ht);
1182-
uint32_t nSize = ht->nTableSize + ht->nTableSize;
1214+
uint32_t nSize = zend_hash_check_size(ht->nTableSize + ht->nTableSize);
11831215
Bucket *old_buckets = ht->arData;
11841216

11851217
ht->nTableSize = nSize;
11861218
new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT);
1187-
ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize);
1219+
ht->nTableMask = HT_SIZE_TO_MASK(nSize);
11881220
HT_SET_DATA_ADDR(ht, new_data);
11891221
memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed);
11901222
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
@@ -292,13 +292,27 @@ ZEND_API void ZEND_FASTCALL zend_hash_rehash(HashTable *ht);
292292
: \
293293
_zend_new_array((size)) \
294294
)
295+
# define zend_new_array_assoc(size) \
296+
(__builtin_constant_p(size) ? \
297+
((((uint32_t)(size)) <= HT_MIN_SIZE_UNPACKED) ? \
298+
_zend_new_array_assoc_0() \
299+
: \
300+
_zend_new_array_assoc((size)) \
301+
) \
302+
: \
303+
_zend_new_array_assoc((size)) \
304+
)
295305
#else
296306
# define zend_new_array(size) \
297307
_zend_new_array(size)
308+
# define zend_new_array_assoc(size) \
309+
_zend_new_array_assoc(size)
298310
#endif
299311

300312
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void);
313+
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_assoc_0(void);
301314
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size);
315+
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_assoc(uint32_t size);
302316
ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2);
303317
ZEND_API uint32_t zend_array_count(HashTable *ht);
304318
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
@@ -712,7 +712,7 @@ ZEND_API void ZEND_FASTCALL convert_to_array(zval *op) /* {{{ */
712712
} else {
713713
zval_ptr_dtor(op);
714714
/*ZVAL_EMPTY_ARRAY(op);*/
715-
array_init(op);
715+
array_init_assoc(op);
716716
}
717717
}
718718
break;

Zend/zend_types.h

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

396396
#define HT_MIN_MASK ((uint32_t) -2)
397-
#define HT_MIN_SIZE 8
397+
#define HT_MIN_SIZE 2
398+
#define HT_MIN_SIZE_UNPACKED 8
398399

399400
#if SIZEOF_SIZE_T == 4
400401
# define HT_MAX_SIZE 0x04000000 /* small enough to avoid overflow checks */
@@ -422,7 +423,7 @@ struct _zend_array {
422423
HT_HASH_EX((ht)->arData, idx)
423424

424425
#define HT_SIZE_TO_MASK(nTableSize) \
425-
((uint32_t)(-((nTableSize) + (nTableSize))))
426+
(uint32_t)(-(zend_hash_check_size((nTableSize) + (nTableSize))))
426427
#define HT_HASH_SIZE(nTableMask) \
427428
(((size_t)(uint32_t)-(int32_t)(nTableMask)) * sizeof(uint32_t))
428429
#define HT_DATA_SIZE(nTableSize) \
@@ -439,7 +440,15 @@ struct _zend_array {
439440
size_t size = HT_HASH_SIZE((ht)->nTableMask); \
440441
__m128i xmm0 = _mm_setzero_si128(); \
441442
xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \
442-
ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \
443+
if (size < 64) { \
444+
ZEND_ASSERT(size == 16 || size == 32); \
445+
_mm_storeu_si128((__m128i*)p, xmm0); \
446+
if (size >= 32) { \
447+
_mm_storeu_si128((__m128i*)(p+16), xmm0); \
448+
} \
449+
break; \
450+
} \
451+
ZEND_ASSERT(((size & 0x3f) == 0)); \
443452
do { \
444453
_mm_storeu_si128((__m128i*)p, xmm0); \
445454
_mm_storeu_si128((__m128i*)(p+16), xmm0); \

Zend/zend_vm_def.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5801,7 +5801,7 @@ ZEND_VM_COLD_CONST_HANDLER(51, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE)
58015801
}
58025802
Z_OBJ_P(result)->properties = ht;
58035803
} else if (Z_TYPE_P(expr) != IS_NULL) {
5804-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
5804+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
58055805
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
58065806
if (OP1_TYPE == IS_CONST) {
58075807
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
@@ -3966,7 +3966,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_H
39663966
}
39673967
Z_OBJ_P(result)->properties = ht;
39683968
} else if (Z_TYPE_P(expr) != IS_NULL) {
3969-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
3969+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
39703970
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
39713971
if (IS_CONST == IS_CONST) {
39723972
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);
@@ -17626,7 +17626,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPC
1762617626
}
1762717627
Z_OBJ_P(result)->properties = ht;
1762817628
} else if (Z_TYPE_P(expr) != IS_NULL) {
17629-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
17629+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
1763017630
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
1763117631
if (IS_TMP_VAR == IS_CONST) {
1763217632
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);
@@ -20284,7 +20284,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPC
2028420284
}
2028520285
Z_OBJ_P(result)->properties = ht;
2028620286
} else if (Z_TYPE_P(expr) != IS_NULL) {
20287-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
20287+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
2028820288
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
2028920289
if (IS_VAR == IS_CONST) {
2029020290
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);
@@ -36211,7 +36211,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCO
3621136211
}
3621236212
Z_OBJ_P(result)->properties = ht;
3621336213
} else if (Z_TYPE_P(expr) != IS_NULL) {
36214-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
36214+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
3621536215
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
3621636216
if (IS_CV == IS_CONST) {
3621736217
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
@@ -240,7 +240,7 @@ static int php_json_parser_array_append(php_json_parser *parser, zval *array, zv
240240
static int php_json_parser_object_create(php_json_parser *parser, zval *object)
241241
{
242242
if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) {
243-
array_init(object);
243+
array_init_assoc(object);
244244
return SUCCESS;
245245
} else {
246246
return object_init(object);

ext/opcache/zend_persist.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ static void zend_hash_persist(HashTable *ht)
117117
void *data = HT_GET_DATA_ADDR(ht);
118118
data = zend_shared_memdup_free(data, HT_USED_SIZE(ht));
119119
HT_SET_DATA_ADDR(ht, data);
120-
} else if (ht->nNumUsed > HT_MIN_SIZE && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) {
120+
} else if (ht->nNumUsed > HT_MIN_SIZE_UNPACKED && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) {
121+
/* TODO any special considerations for this? */
121122
/* compact table */
122123
void *old_data = HT_GET_DATA_ADDR(ht);
123124
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
@@ -62,7 +62,7 @@ static void zend_hash_persist_calc(HashTable *ht)
6262
return;
6363
}
6464

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

ext/standard/array.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2633,9 +2633,9 @@ PHP_FUNCTION(compact)
26332633
or multiple string names, rather than a combination of both.
26342634
So quickly guess a minimum result size based on that */
26352635
if (num_args && Z_TYPE(args[0]) == IS_ARRAY) {
2636-
array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
2636+
array_init_assoc_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
26372637
} else {
2638-
array_init_size(return_value, num_args);
2638+
array_init_assoc_size(return_value, num_args);
26392639
}
26402640

26412641
for (i = 0; i < num_args; i++) {
@@ -2726,7 +2726,7 @@ PHP_FUNCTION(array_fill_keys)
27262726
ZEND_PARSE_PARAMETERS_END();
27272727

27282728
/* Initialize return array */
2729-
array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys)));
2729+
array_init_assoc_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys)));
27302730

27312731
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), entry) {
27322732
ZVAL_DEREF(entry);

ext/standard/basic_functions.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,7 +1287,7 @@ PHP_FUNCTION(time_nanosleep)
12871287
if (!nanosleep(&php_req, &php_rem)) {
12881288
RETURN_TRUE;
12891289
} else if (errno == EINTR) {
1290-
array_init(return_value);
1290+
array_init_size(return_value, 2);
12911291
add_assoc_long_ex(return_value, "seconds", sizeof("seconds")-1, php_rem.tv_sec);
12921292
add_assoc_long_ex(return_value, "nanoseconds", sizeof("nanoseconds")-1, php_rem.tv_nsec);
12931293
return;
@@ -1528,7 +1528,7 @@ PHP_FUNCTION(error_get_last)
15281528
ZEND_PARSE_PARAMETERS_NONE();
15291529

15301530
if (PG(last_error_message)) {
1531-
array_init(return_value);
1531+
array_init_size(return_value, 4);
15321532
add_assoc_long_ex(return_value, "type", sizeof("type")-1, PG(last_error_type));
15331533
add_assoc_str_ex(return_value, "message", sizeof("message")-1,
15341534
zend_string_copy(PG(last_error_message)));

ext/standard/datetime.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ PHP_FUNCTION(strptime)
9090
RETURN_FALSE;
9191
}
9292

93-
array_init(return_value);
93+
array_init_size(return_value, 9);
9494
add_assoc_long(return_value, "tm_sec", parsed_time.tm_sec);
9595
add_assoc_long(return_value, "tm_min", parsed_time.tm_min);
9696
add_assoc_long(return_value, "tm_hour", parsed_time.tm_hour);

ext/standard/dir.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ PHP_FUNCTION(scandir)
572572
RETURN_FALSE;
573573
}
574574

575-
array_init(return_value);
575+
array_init_size(return_value, n);
576576

577577
for (i = 0; i < n; i++) {
578578
add_next_index_str(return_value, namelist[i]);

ext/standard/file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1531,7 +1531,7 @@ PHP_FUNCTION(fstat)
15311531
RETURN_FALSE;
15321532
}
15331533

1534-
array_init(return_value);
1534+
array_init_size(return_value, 26);
15351535

15361536
ZVAL_LONG(&stat_dev, stat_ssb.sb.st_dev);
15371537
ZVAL_LONG(&stat_ino, stat_ssb.sb.st_ino);

ext/standard/scanf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ PHPAPI int php_sscanf_internal( char *string, char *format,
625625
zval tmp;
626626

627627
/* allocate an array for return */
628-
array_init(return_value);
628+
array_init_size(return_value, totalVars);
629629

630630
for (i = 0; i < totalVars; i++) {
631631
ZVAL_NULL(&tmp);

0 commit comments

Comments
 (0)