Skip to content

Commit 407d804

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 6ee6097 commit 407d804

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
@@ -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
@@ -399,8 +399,10 @@ ZEND_API const char *zend_get_type_by_const(int type);
399399
#define DLEXPORT
400400
#endif
401401

402-
#define array_init(arg) ZVAL_ARR((arg), zend_new_array(0))
403-
#define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size))
402+
#define array_init(arg) ZVAL_ARR((arg), zend_new_array(0))
403+
#define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size))
404+
#define array_init_assoc(arg) ZVAL_ARR((arg), zend_new_array_assoc(0))
405+
#define array_init_assoc_size(arg, size) ZVAL_ARR((arg), zend_new_array_assoc(size))
404406
ZEND_API int object_init(zval *arg);
405407
ZEND_API int object_init_ex(zval *arg, zend_class_entry *ce);
406408
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
@@ -660,13 +660,15 @@ ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_c
660660
{
661661
uint32_t i;
662662
zend_ast_list *list = zend_ast_get_list(ast);
663+
uint32_t n_children = list->children;
663664

664-
if (!list->children) {
665+
if (!n_children) {
665666
ZVAL_EMPTY_ARRAY(result);
666667
break;
667668
}
668-
array_init(result);
669-
for (i = 0; i < list->children; i++) {
669+
/** Usually, there won't be an AST_UNPACK or duplicate keys. Assume that's the initial capacity. */
670+
array_init_size(result, n_children);
671+
for (i = 0; i < n_children; i++) {
670672
zend_ast *elem = list->child[i];
671673
if (elem->kind == ZEND_AST_UNPACK) {
672674
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
@@ -266,7 +266,7 @@ ZEND_FUNCTION(gc_status)
266266

267267
zend_gc_get_status(&status);
268268

269-
array_init_size(return_value, 3);
269+
array_init_assoc_size(return_value, 4);
270270

271271
add_assoc_long_ex(return_value, "runs", sizeof("runs")-1, (long)status.runs);
272272
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
@@ -2208,7 +2208,7 @@ static zend_always_inline void zend_fetch_dimension_address(zval *result, zval *
22082208
return;
22092209
}
22102210
}
2211-
array_init(container);
2211+
array_init(container); /* TODO benchmark and check if array_init_assoc is faster */
22122212
goto fetch_from_array;
22132213
} else {
22142214
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
@@ -393,7 +393,8 @@ struct _zend_array {
393393
#define HT_INVALID_IDX ((uint32_t) -1)
394394

395395
#define HT_MIN_MASK ((uint32_t) -2)
396-
#define HT_MIN_SIZE 8
396+
#define HT_MIN_SIZE 2
397+
#define HT_MIN_SIZE_UNPACKED 8
397398

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

423424
#define HT_SIZE_TO_MASK(nTableSize) \
424-
((uint32_t)(-((nTableSize) + (nTableSize))))
425+
(uint32_t)(-(zend_hash_check_size((nTableSize) + (nTableSize))))
425426
#define HT_HASH_SIZE(nTableMask) \
426427
(((size_t)(uint32_t)-(int32_t)(nTableMask)) * sizeof(uint32_t))
427428
#define HT_DATA_SIZE(nTableSize) \
@@ -438,7 +439,15 @@ struct _zend_array {
438439
size_t size = HT_HASH_SIZE((ht)->nTableMask); \
439440
__m128i xmm0 = _mm_setzero_si128(); \
440441
xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \
441-
ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \
442+
if (size < 64) { \
443+
ZEND_ASSERT(size == 16 || size == 32); \
444+
_mm_storeu_si128((__m128i*)p, xmm0); \
445+
if (size >= 32) { \
446+
_mm_storeu_si128((__m128i*)(p+16), xmm0); \
447+
} \
448+
break; \
449+
} \
450+
ZEND_ASSERT(((size & 0x3f) == 0)); \
442451
do { \
443452
_mm_storeu_si128((__m128i*)p, xmm0); \
444453
_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
@@ -5803,7 +5803,7 @@ ZEND_VM_COLD_CONST_HANDLER(51, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE)
58035803
}
58045804
Z_OBJ_P(result)->properties = ht;
58055805
} else if (Z_TYPE_P(expr) != IS_NULL) {
5806-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
5806+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
58075807
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
58085808
if (OP1_TYPE == IS_CONST) {
58095809
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
@@ -3955,7 +3955,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_H
39553955
}
39563956
Z_OBJ_P(result)->properties = ht;
39573957
} else if (Z_TYPE_P(expr) != IS_NULL) {
3958-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
3958+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
39593959
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
39603960
if (IS_CONST == IS_CONST) {
39613961
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);
@@ -17616,7 +17616,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPC
1761617616
}
1761717617
Z_OBJ_P(result)->properties = ht;
1761817618
} else if (Z_TYPE_P(expr) != IS_NULL) {
17619-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
17619+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
1762017620
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
1762117621
if (IS_TMP_VAR == IS_CONST) {
1762217622
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);
@@ -20274,7 +20274,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPC
2027420274
}
2027520275
Z_OBJ_P(result)->properties = ht;
2027620276
} else if (Z_TYPE_P(expr) != IS_NULL) {
20277-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
20277+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
2027820278
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
2027920279
if (IS_VAR == IS_CONST) {
2028020280
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);
@@ -36202,7 +36202,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCO
3620236202
}
3620336203
Z_OBJ_P(result)->properties = ht;
3620436204
} else if (Z_TYPE_P(expr) != IS_NULL) {
36205-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
36205+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
3620636206
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
3620736207
if (IS_CV == IS_CONST) {
3620836208
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
@@ -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

ext/standard/array.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2598,9 +2598,9 @@ PHP_FUNCTION(compact)
25982598
or multiple string names, rather than a combination of both.
25992599
So quickly guess a minimum result size based on that */
26002600
if (num_args && Z_TYPE(args[0]) == IS_ARRAY) {
2601-
array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
2601+
array_init_assoc_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
26022602
} else {
2603-
array_init_size(return_value, num_args);
2603+
array_init_assoc_size(return_value, num_args);
26042604
}
26052605

26062606
for (i = 0; i < num_args; i++) {
@@ -2691,7 +2691,7 @@ PHP_FUNCTION(array_fill_keys)
26912691
ZEND_PARSE_PARAMETERS_END();
26922692

26932693
/* Initialize return array */
2694-
array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys)));
2694+
array_init_assoc_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys)));
26952695

26962696
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), entry) {
26972697
ZVAL_DEREF(entry);

ext/standard/basic_functions.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1998,7 +1998,7 @@ PHP_FUNCTION(time_nanosleep)
19981998
if (!nanosleep(&php_req, &php_rem)) {
19991999
RETURN_TRUE;
20002000
} else if (errno == EINTR) {
2001-
array_init(return_value);
2001+
array_init_size(return_value, 2);
20022002
add_assoc_long_ex(return_value, "seconds", sizeof("seconds")-1, php_rem.tv_sec);
20032003
add_assoc_long_ex(return_value, "nanoseconds", sizeof("nanoseconds")-1, php_rem.tv_nsec);
20042004
return;
@@ -2239,7 +2239,7 @@ PHP_FUNCTION(error_get_last)
22392239
ZEND_PARSE_PARAMETERS_NONE();
22402240

22412241
if (PG(last_error_message)) {
2242-
array_init(return_value);
2242+
array_init_size(return_value, 4);
22432243
add_assoc_long_ex(return_value, "type", sizeof("type")-1, PG(last_error_type));
22442244
add_assoc_string_ex(return_value, "message", sizeof("message")-1, PG(last_error_message));
22452245
add_assoc_string_ex(return_value, "file", sizeof("file")-1, PG(last_error_file)?PG(last_error_file):"-");

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
@@ -579,7 +579,7 @@ PHP_FUNCTION(scandir)
579579
RETURN_FALSE;
580580
}
581581

582-
array_init(return_value);
582+
array_init_size(return_value, n);
583583

584584
for (i = 0; i < n; i++) {
585585
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
@@ -1534,7 +1534,7 @@ PHP_NAMED_FUNCTION(php_if_fstat)
15341534
RETURN_FALSE;
15351535
}
15361536

1537-
array_init(return_value);
1537+
array_init_size(return_value, 26);
15381538

15391539
ZVAL_LONG(&stat_dev, stat_ssb.sb.st_dev);
15401540
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)