Skip to content

Commit abbf793

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 21d326a commit abbf793

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
@@ -3257,7 +3257,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_nam
32573257
if (zend_is_callable_ex(callable, NULL, 0, callable_name, &fcc, NULL)) {
32583258
if (Z_TYPE_P(callable) == IS_STRING && fcc.calling_scope) {
32593259
zval_ptr_dtor_str(callable);
3260-
array_init(callable);
3260+
array_init_size(callable, 2);
32613261
add_next_index_str(callable, zend_string_copy(fcc.calling_scope->name));
32623262
add_next_index_str(callable, zend_string_copy(fcc.function_handler->common.function_name));
32633263
}

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
@@ -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
@@ -2210,7 +2210,7 @@ static zend_always_inline void zend_fetch_dimension_address(zval *result, zval *
22102210
return;
22112211
}
22122212
}
2213-
array_init(container);
2213+
array_init(container); /* TODO benchmark and check if array_init_assoc is faster */
22142214
goto fetch_from_array;
22152215
} else {
22162216
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
@@ -398,7 +398,8 @@ struct _zend_array {
398398
#define HT_INVALID_IDX ((uint32_t) -1)
399399

400400
#define HT_MIN_MASK ((uint32_t) -2)
401-
#define HT_MIN_SIZE 8
401+
#define HT_MIN_SIZE 2
402+
#define HT_MIN_SIZE_UNPACKED 8
402403

403404
#if SIZEOF_SIZE_T == 4
404405
# define HT_MAX_SIZE 0x04000000 /* small enough to avoid overflow checks */
@@ -426,7 +427,7 @@ struct _zend_array {
426427
HT_HASH_EX((ht)->arData, idx)
427428

428429
#define HT_SIZE_TO_MASK(nTableSize) \
429-
((uint32_t)(-((nTableSize) + (nTableSize))))
430+
(uint32_t)(-(zend_hash_check_size((nTableSize) + (nTableSize))))
430431
#define HT_HASH_SIZE(nTableMask) \
431432
(((size_t)(uint32_t)-(int32_t)(nTableMask)) * sizeof(uint32_t))
432433
#define HT_DATA_SIZE(nTableSize) \
@@ -443,7 +444,15 @@ struct _zend_array {
443444
size_t size = HT_HASH_SIZE((ht)->nTableMask); \
444445
__m128i xmm0 = _mm_setzero_si128(); \
445446
xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \
446-
ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \
447+
if (size < 64) { \
448+
ZEND_ASSERT(size == 16 || size == 32); \
449+
_mm_storeu_si128((__m128i*)p, xmm0); \
450+
if (size >= 32) { \
451+
_mm_storeu_si128((__m128i*)(p+16), xmm0); \
452+
} \
453+
break; \
454+
} \
455+
ZEND_ASSERT(((size & 0x3f) == 0)); \
447456
do { \
448457
_mm_storeu_si128((__m128i*)p, xmm0); \
449458
_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
@@ -5745,7 +5745,7 @@ ZEND_VM_COLD_CONST_HANDLER(51, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE)
57455745
}
57465746
Z_OBJ_P(result)->properties = ht;
57475747
} else if (Z_TYPE_P(expr) != IS_NULL) {
5748-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
5748+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
57495749
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
57505750
if (OP1_TYPE == IS_CONST) {
57515751
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
@@ -3913,7 +3913,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_H
39133913
}
39143914
Z_OBJ_P(result)->properties = ht;
39153915
} else if (Z_TYPE_P(expr) != IS_NULL) {
3916-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
3916+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
39173917
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
39183918
if (IS_CONST == IS_CONST) {
39193919
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);
@@ -17503,7 +17503,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPC
1750317503
}
1750417504
Z_OBJ_P(result)->properties = ht;
1750517505
} else if (Z_TYPE_P(expr) != IS_NULL) {
17506-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
17506+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
1750717507
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
1750817508
if (IS_TMP_VAR == IS_CONST) {
1750917509
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);
@@ -20150,7 +20150,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPC
2015020150
}
2015120151
Z_OBJ_P(result)->properties = ht;
2015220152
} else if (Z_TYPE_P(expr) != IS_NULL) {
20153-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
20153+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
2015420154
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
2015520155
if (IS_VAR == IS_CONST) {
2015620156
if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr);
@@ -35912,7 +35912,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCO
3591235912
}
3591335913
Z_OBJ_P(result)->properties = ht;
3591435914
} else if (Z_TYPE_P(expr) != IS_NULL) {
35915-
Z_OBJ_P(result)->properties = ht = zend_new_array(1);
35915+
Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1);
3591635916
expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr);
3591735917
if (IS_CV == IS_CONST) {
3591835918
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
@@ -2593,9 +2593,9 @@ PHP_FUNCTION(compact)
25932593
or multiple string names, rather than a combination of both.
25942594
So quickly guess a minimum result size based on that */
25952595
if (num_args && Z_TYPE(args[0]) == IS_ARRAY) {
2596-
array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
2596+
array_init_assoc_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0])));
25972597
} else {
2598-
array_init_size(return_value, num_args);
2598+
array_init_assoc_size(return_value, num_args);
25992599
}
26002600

26012601
for (i = 0; i < num_args; i++) {
@@ -2686,7 +2686,7 @@ PHP_FUNCTION(array_fill_keys)
26862686
ZEND_PARSE_PARAMETERS_END();
26872687

26882688
/* Initialize return array */
2689-
array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys)));
2689+
array_init_assoc_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys)));
26902690

26912691
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), entry) {
26922692
ZVAL_DEREF(entry);

ext/standard/basic_functions.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2748,7 +2748,7 @@ PHP_FUNCTION(time_nanosleep)
27482748
if (!nanosleep(&php_req, &php_rem)) {
27492749
RETURN_TRUE;
27502750
} else if (errno == EINTR) {
2751-
array_init(return_value);
2751+
array_init_size(return_value, 2);
27522752
add_assoc_long_ex(return_value, "seconds", sizeof("seconds")-1, php_rem.tv_sec);
27532753
add_assoc_long_ex(return_value, "nanoseconds", sizeof("nanoseconds")-1, php_rem.tv_nsec);
27542754
return;
@@ -3015,7 +3015,7 @@ PHP_FUNCTION(error_get_last)
30153015
}
30163016

30173017
if (PG(last_error_message)) {
3018-
array_init(return_value);
3018+
array_init_size(return_value, 4);
30193019
add_assoc_long_ex(return_value, "type", sizeof("type")-1, PG(last_error_type));
30203020
add_assoc_string_ex(return_value, "message", sizeof("message")-1, PG(last_error_message));
30213021
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
@@ -1536,7 +1536,7 @@ PHP_NAMED_FUNCTION(php_if_fstat)
15361536
RETURN_FALSE;
15371537
}
15381538

1539-
array_init(return_value);
1539+
array_init_size(return_value, 26);
15401540

15411541
ZVAL_LONG(&stat_dev, stat_ssb.sb.st_dev);
15421542
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
@@ -633,7 +633,7 @@ PHPAPI int php_sscanf_internal( char *string, char *format,
633633
zval tmp;
634634

635635
/* allocate an array for return */
636-
array_init(return_value);
636+
array_init_size(return_value, totalVars);
637637

638638
for (i = 0; i < totalVars; i++) {
639639
ZVAL_NULL(&tmp);

0 commit comments

Comments
 (0)