From 549bcba9dc36aeae7b1cfdbbd06536628bbc6f38 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Wed, 18 Jul 2018 18:03:19 -0700 Subject: [PATCH 01/16] Reduce the minimum size for packed arrays from 8 to 2 There are probably ways this could be optimized. For now, I'm aiming to see if this will work correctly. --- Zend/zend_hash.c | 27 +++++++++++++++++++++------ Zend/zend_types.h | 3 ++- ext/opcache/zend_persist.c | 3 ++- ext/opcache/zend_persist_calc.c | 2 +- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 79a2f52d6c00e..e0c965c1d2267 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -144,10 +144,18 @@ static zend_always_inline void zend_hash_real_init_mixed_ex(HashTable *ht) uint32_t nSize = ht->nTableSize; if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) { + if (nSize < HT_MIN_SIZE_UNPACKED) { + nSize = HT_MIN_SIZE_UNPACKED; + ht->nTableSize = HT_MIN_SIZE_UNPACKED; + } data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), 1); - } else if (EXPECTED(nSize == HT_MIN_SIZE)) { - data = emalloc(HT_SIZE_EX(HT_MIN_SIZE, HT_SIZE_TO_MASK(HT_MIN_SIZE))); - ht->nTableMask = HT_SIZE_TO_MASK(HT_MIN_SIZE); + } else if (EXPECTED(nSize <= HT_MIN_SIZE_UNPACKED)) { + if (nSize < HT_MIN_SIZE_UNPACKED) { + nSize = HT_MIN_SIZE_UNPACKED; + ht->nTableSize = HT_MIN_SIZE_UNPACKED; + } + data = emalloc(HT_SIZE_EX(HT_MIN_SIZE_UNPACKED, HT_SIZE_TO_MASK(HT_MIN_SIZE_UNPACKED))); + ht->nTableMask = HT_SIZE_TO_MASK(HT_MIN_SIZE_UNPACKED); HT_SET_DATA_ADDR(ht, data); /* Don't overwrite iterator count. */ 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) static const uint32_t uninitialized_bucket[-HT_MIN_MASK] = {HT_INVALID_IDX, HT_INVALID_IDX}; +// XXX: Is MIN_SIZE_UNPACKED the best choice vs this (8 vs 2)? Haven't benchmarked it. ZEND_API const HashTable zend_empty_array = { .gc.refcount = 2, .gc.u.type_info = IS_ARRAY | (GC_IMMUTABLE << GC_FLAGS_SHIFT), @@ -218,7 +227,7 @@ ZEND_API const HashTable zend_empty_array = { .arData = (Bucket*)&uninitialized_bucket[2], .nNumUsed = 0, .nNumOfElements = 0, - .nTableSize = HT_MIN_SIZE, + .nTableSize = HT_MIN_SIZE_UNPACKED, .nInternalPointer = 0, .nNextFreeElement = 0, .pDestructor = ZVAL_PTR_DTOR @@ -244,6 +253,7 @@ ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_ _zend_hash_init_int(ht, nSize, pDestructor, persistent); } +// TODO should this be 2 or 8? also see zend_new_array ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void) { HashTable *ht = emalloc(sizeof(HashTable)); @@ -262,6 +272,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2) { Bucket *p; HashTable *ht = emalloc(sizeof(HashTable)); + // XXX will need to adjust all calls like this if HT_MIN_SIZE goes below 2 _zend_hash_init_int(ht, HT_MIN_SIZE, ZVAL_PTR_DTOR, 0); ht->nNumUsed = ht->nNumOfElements = ht->nNextFreeElement = 2; zend_hash_real_init_packed_ex(ht); @@ -317,11 +328,12 @@ ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht) void *new_data, *old_data = HT_GET_DATA_ADDR(ht); Bucket *old_buckets = ht->arData; uint32_t nSize = ht->nTableSize; + uint32_t nNewSize = nSize >= HT_MIN_SIZE_UNPACKED ? nSize : HT_MIN_SIZE_UNPACKED; HT_ASSERT_RC1(ht); HT_FLAGS(ht) &= ~HASH_FLAG_PACKED; - new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); - ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize); + new_data = pemalloc(HT_SIZE_EX(nNewSize, HT_SIZE_TO_MASK(nNewSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); + ht->nTableMask = HT_SIZE_TO_MASK(nNewSize); HT_SET_DATA_ADDR(ht, new_data); memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed); pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); @@ -1158,6 +1170,9 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) } else if (ht->nTableSize < HT_MAX_SIZE) { /* Let's double the table size */ void *new_data, *old_data = HT_GET_DATA_ADDR(ht); uint32_t nSize = ht->nTableSize + ht->nTableSize; + if (nSize < HT_MIN_SIZE_UNPACKED) { + nSize = HT_MIN_SIZE_UNPACKED; + } Bucket *old_buckets = ht->arData; ht->nTableSize = nSize; diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 8d2726a14c551..8bb1b7997c075 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -302,7 +302,8 @@ struct _zend_array { #define HT_INVALID_IDX ((uint32_t) -1) #define HT_MIN_MASK ((uint32_t) -2) -#define HT_MIN_SIZE 8 +#define HT_MIN_SIZE 2 +#define HT_MIN_SIZE_UNPACKED 8 #if SIZEOF_SIZE_T == 4 # define HT_MAX_SIZE 0x04000000 /* small enough to avoid overflow checks */ diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index a2fb94d7f6a3a..dd5342c6a7bf4 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -115,7 +115,8 @@ static void zend_hash_persist(HashTable *ht) void *data = HT_GET_DATA_ADDR(ht); data = zend_shared_memdup_free(data, HT_USED_SIZE(ht)); HT_SET_DATA_ADDR(ht, data); - } else if (ht->nNumUsed > HT_MIN_SIZE && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) { + } else if (ht->nNumUsed > HT_MIN_SIZE_UNPACKED && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) { + /* TODO any special considerations for this? */ /* compact table */ void *old_data = HT_GET_DATA_ADDR(ht); Bucket *old_buckets = ht->arData; diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index cc798b27de050..be55091b69555 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -61,7 +61,7 @@ static void zend_hash_persist_calc(HashTable *ht) return; } - if (!(HT_FLAGS(ht) & HASH_FLAG_PACKED) && ht->nNumUsed > HT_MIN_SIZE && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) { + if (!(HT_FLAGS(ht) & HASH_FLAG_PACKED) && ht->nNumUsed > HT_MIN_SIZE_UNPACKED && ht->nNumUsed < (uint32_t)(-(int32_t)ht->nTableMask) / 4) { /* compact table */ uint32_t hash_size; From 8fa81a174b929ed5a01411506eebd6d108661981 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sun, 29 Sep 2019 16:24:21 -0400 Subject: [PATCH 02/16] Add notes, be explicit about chosen sizes. (no change) Fix formatting --- Zend/zend_API.c | 2 +- Zend/zend_ast.c | 10 ++++++---- Zend/zend_builtin_functions.c | 2 +- Zend/zend_hash.c | 30 +++++++++++++++--------------- ext/standard/basic_functions.c | 4 ++-- ext/standard/datetime.c | 2 +- ext/standard/dir.c | 2 +- ext/standard/file.c | 2 +- ext/standard/scanf.c | 2 +- ext/standard/streamsfuncs.c | 2 +- ext/tokenizer/tokenizer.c | 2 +- 11 files changed, 31 insertions(+), 29 deletions(-) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index e3953acfcc56c..a5fb64c89e3d7 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -3271,7 +3271,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_nam if (zend_is_callable_ex(callable, NULL, 0, callable_name, &fcc, NULL)) { if (Z_TYPE_P(callable) == IS_STRING && fcc.calling_scope) { zval_ptr_dtor_str(callable); - array_init(callable); + array_init_size(callable, 2); add_next_index_str(callable, zend_string_copy(fcc.calling_scope->name)); add_next_index_str(callable, zend_string_copy(fcc.function_handler->common.function_name)); } diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 660e6d5b6f11d..aa1fea6676acb 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -451,7 +451,7 @@ static int zend_ast_add_unpacked_element(zval *result, zval *expr) { HashTable *ht = Z_ARRVAL_P(expr); zval *val; zend_string *key; - + ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) { if (key) { 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 { uint32_t i; zend_ast_list *list = zend_ast_get_list(ast); + uint32_t n_children = list->children; - if (!list->children) { + if (!n_children) { ZVAL_EMPTY_ARRAY(result); break; } - array_init(result); - for (i = 0; i < list->children; i++) { + /** Usually, there won't be an AST_UNPACK or duplicate keys. Assume that's the initial capacity. */ + array_init_size(result, n_children); + for (i = 0; i < n_children; i++) { zend_ast *elem = list->child[i]; if (elem->kind == ZEND_AST_UNPACK) { if (UNEXPECTED(zend_ast_evaluate(&op1, elem->child[0], scope) != SUCCESS)) { diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index f16bf1540f91e..1d73b99cc0898 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -280,7 +280,7 @@ ZEND_FUNCTION(gc_status) zend_gc_get_status(&status); - array_init_size(return_value, 3); + array_init_size(return_value, 4); add_assoc_long_ex(return_value, "runs", sizeof("runs")-1, (long)status.runs); add_assoc_long_ex(return_value, "collected", sizeof("collected")-1, (long)status.collected); diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index e0c965c1d2267..5619b164ba85e 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -144,16 +144,16 @@ static zend_always_inline void zend_hash_real_init_mixed_ex(HashTable *ht) uint32_t nSize = ht->nTableSize; if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) { - if (nSize < HT_MIN_SIZE_UNPACKED) { - nSize = HT_MIN_SIZE_UNPACKED; - ht->nTableSize = HT_MIN_SIZE_UNPACKED; - } + if (nSize < HT_MIN_SIZE_UNPACKED) { + nSize = HT_MIN_SIZE_UNPACKED; + ht->nTableSize = HT_MIN_SIZE_UNPACKED; + } data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), 1); } else if (EXPECTED(nSize <= HT_MIN_SIZE_UNPACKED)) { - if (nSize < HT_MIN_SIZE_UNPACKED) { - nSize = HT_MIN_SIZE_UNPACKED; - ht->nTableSize = HT_MIN_SIZE_UNPACKED; - } + if (nSize < HT_MIN_SIZE_UNPACKED) { + nSize = HT_MIN_SIZE_UNPACKED; + ht->nTableSize = HT_MIN_SIZE_UNPACKED; + } data = emalloc(HT_SIZE_EX(HT_MIN_SIZE_UNPACKED, HT_SIZE_TO_MASK(HT_MIN_SIZE_UNPACKED))); ht->nTableMask = HT_SIZE_TO_MASK(HT_MIN_SIZE_UNPACKED); HT_SET_DATA_ADDR(ht, data); @@ -218,7 +218,7 @@ static zend_always_inline void zend_hash_real_init_ex(HashTable *ht, int packed) static const uint32_t uninitialized_bucket[-HT_MIN_MASK] = {HT_INVALID_IDX, HT_INVALID_IDX}; -// XXX: Is MIN_SIZE_UNPACKED the best choice vs this (8 vs 2)? Haven't benchmarked it. +/* XXX: Is MIN_SIZE_UNPACKED the best choice vs this (8 vs 2)? Haven't benchmarked it. */ ZEND_API const HashTable zend_empty_array = { .gc.refcount = 2, .gc.u.type_info = IS_ARRAY | (GC_IMMUTABLE << GC_FLAGS_SHIFT), @@ -245,6 +245,7 @@ static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize ht->nInternalPointer = 0; ht->nNextFreeElement = ZEND_LONG_MIN; ht->pDestructor = pDestructor; + /* TODO: Add a way to specify the size of a packed table exactly? Currently, send_hash_check_size rounds up to the nearest power of 2. */ ht->nTableSize = zend_hash_check_size(nSize); } @@ -253,7 +254,6 @@ ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_ _zend_hash_init_int(ht, nSize, pDestructor, persistent); } -// TODO should this be 2 or 8? also see zend_new_array ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void) { HashTable *ht = emalloc(sizeof(HashTable)); @@ -272,7 +272,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2) { Bucket *p; HashTable *ht = emalloc(sizeof(HashTable)); - // XXX will need to adjust all calls like this if HT_MIN_SIZE goes below 2 + /* XXX: Currently, HT_MIN_SIZE == 2. will need to adjust all calls like this if HT_MIN_SIZE goes below 2 */ _zend_hash_init_int(ht, HT_MIN_SIZE, ZVAL_PTR_DTOR, 0); ht->nNumUsed = ht->nNumOfElements = ht->nNextFreeElement = 2; zend_hash_real_init_packed_ex(ht); @@ -328,7 +328,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht) void *new_data, *old_data = HT_GET_DATA_ADDR(ht); Bucket *old_buckets = ht->arData; uint32_t nSize = ht->nTableSize; - uint32_t nNewSize = nSize >= HT_MIN_SIZE_UNPACKED ? nSize : HT_MIN_SIZE_UNPACKED; + uint32_t nNewSize = nSize >= HT_MIN_SIZE_UNPACKED ? nSize : HT_MIN_SIZE_UNPACKED; HT_ASSERT_RC1(ht); HT_FLAGS(ht) &= ~HASH_FLAG_PACKED; @@ -1170,9 +1170,9 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) } else if (ht->nTableSize < HT_MAX_SIZE) { /* Let's double the table size */ void *new_data, *old_data = HT_GET_DATA_ADDR(ht); uint32_t nSize = ht->nTableSize + ht->nTableSize; - if (nSize < HT_MIN_SIZE_UNPACKED) { - nSize = HT_MIN_SIZE_UNPACKED; - } + if (nSize < HT_MIN_SIZE_UNPACKED) { + nSize = HT_MIN_SIZE_UNPACKED; + } Bucket *old_buckets = ht->arData; ht->nTableSize = nSize; diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index ff12fceb73f29..7b186811755a7 100755 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -3940,7 +3940,7 @@ PHP_FUNCTION(time_nanosleep) if (!nanosleep(&php_req, &php_rem)) { RETURN_TRUE; } else if (errno == EINTR) { - array_init(return_value); + array_init_size(return_value, 2); add_assoc_long_ex(return_value, "seconds", sizeof("seconds")-1, php_rem.tv_sec); add_assoc_long_ex(return_value, "nanoseconds", sizeof("nanoseconds")-1, php_rem.tv_nsec); return; @@ -4206,7 +4206,7 @@ PHP_FUNCTION(error_get_last) } if (PG(last_error_message)) { - array_init(return_value); + array_init_size(return_value, 4); add_assoc_long_ex(return_value, "type", sizeof("type")-1, PG(last_error_type)); add_assoc_string_ex(return_value, "message", sizeof("message")-1, PG(last_error_message)); add_assoc_string_ex(return_value, "file", sizeof("file")-1, PG(last_error_file)?PG(last_error_file):"-"); diff --git a/ext/standard/datetime.c b/ext/standard/datetime.c index ba70db4b06163..264b1a4f01cb4 100644 --- a/ext/standard/datetime.c +++ b/ext/standard/datetime.c @@ -90,7 +90,7 @@ PHP_FUNCTION(strptime) RETURN_FALSE; } - array_init(return_value); + array_init_size(return_value, 9); add_assoc_long(return_value, "tm_sec", parsed_time.tm_sec); add_assoc_long(return_value, "tm_min", parsed_time.tm_min); add_assoc_long(return_value, "tm_hour", parsed_time.tm_hour); diff --git a/ext/standard/dir.c b/ext/standard/dir.c index 2d03f43d71a05..0707bdd0e6c9f 100644 --- a/ext/standard/dir.c +++ b/ext/standard/dir.c @@ -584,7 +584,7 @@ PHP_FUNCTION(scandir) RETURN_FALSE; } - array_init(return_value); + array_init_size(return_value, n); for (i = 0; i < n; i++) { add_next_index_str(return_value, namelist[i]); diff --git a/ext/standard/file.c b/ext/standard/file.c index 8bb86ebe3a7ec..ae954e8830180 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -1536,7 +1536,7 @@ PHP_NAMED_FUNCTION(php_if_fstat) RETURN_FALSE; } - array_init(return_value); + array_init_size(return_value, 26); ZVAL_LONG(&stat_dev, stat_ssb.sb.st_dev); ZVAL_LONG(&stat_ino, stat_ssb.sb.st_ino); diff --git a/ext/standard/scanf.c b/ext/standard/scanf.c index 687d063111568..ea732278602dc 100644 --- a/ext/standard/scanf.c +++ b/ext/standard/scanf.c @@ -633,7 +633,7 @@ PHPAPI int php_sscanf_internal( char *string, char *format, zval tmp; /* allocate an array for return */ - array_init(return_value); + array_init_size(return_value, totalVars); for (i = 0; i < totalVars; i++) { ZVAL_NULL(&tmp); diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index fca3f8700c3e9..ffc63fa10f78e 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -68,7 +68,7 @@ PHP_FUNCTION(stream_socket_pair) RETURN_FALSE; } - array_init(return_value); + array_init_size(return_value, 2); s1 = php_stream_sock_open_from_socket(pair[0], 0); s2 = php_stream_sock_open_from_socket(pair[1], 0); diff --git a/ext/tokenizer/tokenizer.c b/ext/tokenizer/tokenizer.c index cf5be9422673d..86da4fbe8d864 100644 --- a/ext/tokenizer/tokenizer.c +++ b/ext/tokenizer/tokenizer.c @@ -96,7 +96,7 @@ static void add_token(zval *return_value, int token_type, unsigned char *text, size_t leng, int lineno) { if (token_type >= 256) { zval keyword; - array_init(&keyword); + array_init_size(&keyword, 3); add_next_index_long(&keyword, token_type); if (leng == 1) { add_next_index_str(&keyword, ZSTR_CHAR(text[0])); From 109e5f0067b3faf1fbfe55ce7a2532c79c921487 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Fri, 4 Oct 2019 09:54:34 -0400 Subject: [PATCH 03/16] Only round up when initial size is more than 8 --- Zend/zend_hash.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 5619b164ba85e..39837f4bda0d1 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -245,8 +245,8 @@ static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize ht->nInternalPointer = 0; ht->nNextFreeElement = ZEND_LONG_MIN; ht->pDestructor = pDestructor; - /* TODO: Add a way to specify the size of a packed table exactly? Currently, send_hash_check_size rounds up to the nearest power of 2. */ - ht->nTableSize = zend_hash_check_size(nSize); + /* TODO: Decide on the best way to specify the size of a packed table exactly? Currently, send_hash_check_size rounds up to the nearest power of 2. */ + ht->nTableSize = nSize <= HT_MIN_SIZE_UNPACKED ? nSize : zend_hash_check_size(nSize); } ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent) From 5bdb15738f5d2d724d69fe286a0b615df3220a39 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 5 Oct 2019 11:43:43 -0400 Subject: [PATCH 04/16] Nit: use EXPECTED --- Zend/zend_hash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 39837f4bda0d1..838b91cc9d0e0 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1167,7 +1167,7 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) if (ht->nNumUsed > ht->nNumOfElements + (ht->nNumOfElements >> 5)) { /* additional term is there to amortize the cost of compaction */ zend_hash_rehash(ht); - } else if (ht->nTableSize < HT_MAX_SIZE) { /* Let's double the table size */ + } else if (EXPECTED(ht->nTableSize < HT_MAX_SIZE)) { /* Let's double the table size */ void *new_data, *old_data = HT_GET_DATA_ADDR(ht); uint32_t nSize = ht->nTableSize + ht->nTableSize; if (nSize < HT_MIN_SIZE_UNPACKED) { From baa7ddaa77a73b98ba5373cbc8d4e5294e16ad63 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 5 Oct 2019 11:45:12 -0400 Subject: [PATCH 05/16] Debugging changes --- travis/compile.sh | 82 +++-------------------------------------------- 1 file changed, 4 insertions(+), 78 deletions(-) diff --git a/travis/compile.sh b/travis/compile.sh index e4706e0f96163..2031618fbd142 100755 --- a/travis/compile.sh +++ b/travis/compile.sh @@ -1,84 +1,10 @@ #!/bin/bash -if [[ "$ENABLE_ZTS" == 1 ]]; then - TS="--enable-zts"; -else - TS=""; -fi -if [[ "$ENABLE_DEBUG" == 1 ]]; then - DEBUG="--enable-debug"; -else - DEBUG=""; -fi - -if [[ -z "$CONFIG_LOG_FILE" ]]; then - CONFIG_QUIET="--quiet" - CONFIG_LOG_FILE="/dev/stdout" -else - CONFIG_QUIET="" -fi -if [[ -z "$MAKE_LOG_FILE" ]]; then - MAKE_QUIET="--quiet" - MAKE_LOG_FILE="/dev/stdout" -else - MAKE_QUIET="" -fi - -MAKE_JOBS=${MAKE_JOBS:-$(nproc)} - ./buildconf --force ./configure \ ---enable-option-checking=fatal \ ---prefix="$HOME"/php-install \ -$CONFIG_QUIET \ -$DEBUG \ -$TS \ ---enable-phpdbg \ ---enable-fpm \ ---with-pdo-mysql=mysqlnd \ ---with-mysqli=mysqlnd \ ---with-pgsql \ ---with-pdo-pgsql \ ---with-pdo-sqlite \ ---enable-intl \ ---without-pear \ ---enable-gd \ ---with-jpeg \ ---with-webp \ ---with-freetype \ ---with-xpm \ ---enable-exif \ ---with-zip \ ---with-zlib \ ---with-zlib-dir=/usr \ ---enable-soap \ ---enable-xmlreader \ ---with-xsl \ ---with-tidy \ ---with-xmlrpc \ ---enable-sysvsem \ ---enable-sysvshm \ ---enable-shmop \ ---enable-pcntl \ ---with-readline \ ---enable-mbstring \ ---with-curl \ ---with-gettext \ ---enable-sockets \ ---with-bz2 \ ---with-openssl \ ---with-gmp \ ---enable-bcmath \ ---enable-calendar \ ---enable-ftp \ ---with-pspell=/usr \ ---with-enchant=/usr \ ---with-kerberos \ ---enable-sysvmsg \ ---with-ffi \ ---enable-zend-test=shared \ ---enable-werror \ ---with-pear \ -> "$CONFIG_LOG_FILE" +--prefix="$HOME"/php-8.0.0-minsize-install \ +--enable-debug \ +--enable-zts \ +--disable-all make "-j${MAKE_JOBS}" $MAKE_QUIET > "$MAKE_LOG_FILE" make install >> "$MAKE_LOG_FILE" From 105c845de3db8baf7bfa6e673fde3587f19f4774 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 5 Oct 2019 12:04:19 -0400 Subject: [PATCH 06/16] WIP nTableMask requires powers of 2 --- Zend/zend_types.h | 2 +- travis/compile.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 8bb1b7997c075..89e452cf6104e 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -331,7 +331,7 @@ struct _zend_array { HT_HASH_EX((ht)->arData, idx) #define HT_SIZE_TO_MASK(nTableSize) \ - ((uint32_t)(-((nTableSize) + (nTableSize)))) + (nTableSize <= 8 ? ((uint32_t)(-16)) : (uint32_t)(-((nTableSize) + (nTableSize)))) #define HT_HASH_SIZE(nTableMask) \ (((size_t)(uint32_t)-(int32_t)(nTableMask)) * sizeof(uint32_t)) #define HT_DATA_SIZE(nTableSize) \ diff --git a/travis/compile.sh b/travis/compile.sh index 2031618fbd142..291892e4b7a21 100755 --- a/travis/compile.sh +++ b/travis/compile.sh @@ -6,5 +6,5 @@ --enable-zts \ --disable-all -make "-j${MAKE_JOBS}" $MAKE_QUIET > "$MAKE_LOG_FILE" -make install >> "$MAKE_LOG_FILE" +make "-j${MAKE_JOBS}" +make install From bc35a7581aa5e33024e7985b7a8eee144d8a7e6c Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 5 Oct 2019 12:11:30 -0400 Subject: [PATCH 07/16] Fix travis --- travis/compile.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis/compile.sh b/travis/compile.sh index 291892e4b7a21..0c6c46b55cbab 100755 --- a/travis/compile.sh +++ b/travis/compile.sh @@ -6,5 +6,5 @@ --enable-zts \ --disable-all -make "-j${MAKE_JOBS}" +make -j8 make install From 3d0cc77145abf682c6a45a16278a4f73dc3d0598 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 5 Oct 2019 12:34:30 -0400 Subject: [PATCH 08/16] Fix test failures --- Zend/zend_hash.c | 5 +---- Zend/zend_types.h | 12 ++++++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 838b91cc9d0e0..2d33b93a5d53a 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1169,10 +1169,7 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) zend_hash_rehash(ht); } else if (EXPECTED(ht->nTableSize < HT_MAX_SIZE)) { /* Let's double the table size */ void *new_data, *old_data = HT_GET_DATA_ADDR(ht); - uint32_t nSize = ht->nTableSize + ht->nTableSize; - if (nSize < HT_MIN_SIZE_UNPACKED) { - nSize = HT_MIN_SIZE_UNPACKED; - } + uint32_t nSize = zend_hash_check_size(ht->nTableSize + ht->nTableSize); Bucket *old_buckets = ht->arData; ht->nTableSize = nSize; diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 89e452cf6104e..88cf9a5c16c51 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -331,7 +331,7 @@ struct _zend_array { HT_HASH_EX((ht)->arData, idx) #define HT_SIZE_TO_MASK(nTableSize) \ - (nTableSize <= 8 ? ((uint32_t)(-16)) : (uint32_t)(-((nTableSize) + (nTableSize)))) + (uint32_t)(-(zend_hash_check_size((nTableSize) + (nTableSize)))) #define HT_HASH_SIZE(nTableMask) \ (((size_t)(uint32_t)-(int32_t)(nTableMask)) * sizeof(uint32_t)) #define HT_DATA_SIZE(nTableSize) \ @@ -348,7 +348,15 @@ struct _zend_array { size_t size = HT_HASH_SIZE((ht)->nTableMask); \ __m128i xmm0 = _mm_setzero_si128(); \ xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \ - ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \ + if (size < 64) { \ + ZEND_ASSERT(size == 16 || size == 32); \ + _mm_storeu_si128((__m128i*)p, xmm0); \ + if (size >= 32) { \ + _mm_storeu_si128((__m128i*)(p+16), xmm0); \ + } \ + break; \ + } \ + ZEND_ASSERT(((size & 0x3f) == 0)); \ do { \ _mm_storeu_si128((__m128i*)p, xmm0); \ _mm_storeu_si128((__m128i*)(p+16), xmm0); \ From ff47843b68376295497a4aac77c791b06214b296 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 5 Oct 2019 12:44:56 -0400 Subject: [PATCH 09/16] wip debug --- travis/compile.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/travis/compile.sh b/travis/compile.sh index 0c6c46b55cbab..3b507e08e37ff 100755 --- a/travis/compile.sh +++ b/travis/compile.sh @@ -3,6 +3,11 @@ ./configure \ --prefix="$HOME"/php-8.0.0-minsize-install \ --enable-debug \ +--enable-iconv \ +--enable-mbstring \ +--enable-tokenizer \ +--enable-json \ +--enable-filter \ --enable-zts \ --disable-all From 113c0ac8aade76b2741908aa13d2f29a3f088b63 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 5 Oct 2019 12:52:43 -0400 Subject: [PATCH 10/16] wip debug --- travis/compile.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/travis/compile.sh b/travis/compile.sh index 3b507e08e37ff..52300c336106c 100755 --- a/travis/compile.sh +++ b/travis/compile.sh @@ -1,14 +1,17 @@ #!/bin/bash +export CFLAGS="-O3" ./buildconf --force ./configure \ ---prefix="$HOME"/php-8.0.0-minsize-install \ ---enable-debug \ +--prefix="$HOME"/php-8.0.0-minsize-nts-install \ --enable-iconv \ --enable-mbstring \ +--enable-dom \ +--enable-simplexml \ +--with-libxml \ +--enable-opcache \ --enable-tokenizer \ --enable-json \ --enable-filter \ ---enable-zts \ --disable-all make -j8 From 10a96e320ac1cc8c382f773c9fd7a75e2b8eb33b Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 5 Oct 2019 13:25:33 -0400 Subject: [PATCH 11/16] WIP add a helper to create array with min packed size This is optional but helps avoid unnecessary reallocations. --- Zend/zend_API.h | 6 ++- Zend/zend_builtin_functions.c | 2 +- Zend/zend_execute.c | 2 +- Zend/zend_hash.c | 16 +++++- Zend/zend_hash.h | 14 ++++++ Zend/zend_operators.c | 2 +- Zend/zend_vm_def.h | 16 +++--- Zend/zend_vm_execute.h | 8 +-- ext/standard/array.c | 6 +-- travis/compile.sh | 92 ++++++++++++++++++++++++++++++----- 10 files changed, 130 insertions(+), 34 deletions(-) diff --git a/Zend/zend_API.h b/Zend/zend_API.h index acc6bb9cf3718..1cf27232e708a 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -376,8 +376,10 @@ ZEND_API const char *zend_get_type_by_const(int type); #define DLEXPORT #endif -#define array_init(arg) ZVAL_ARR((arg), zend_new_array(0)) -#define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size)) +#define array_init(arg) ZVAL_ARR((arg), zend_new_array(0)) +#define array_init_size(arg, size) ZVAL_ARR((arg), zend_new_array(size)) +#define array_init_assoc(arg) ZVAL_ARR((arg), zend_new_array_assoc(0)) +#define array_init_assoc_size(arg, size) ZVAL_ARR((arg), zend_new_array_assoc(size)) ZEND_API int object_init(zval *arg); ZEND_API int object_init_ex(zval *arg, zend_class_entry *ce); ZEND_API int object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties); diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 1d73b99cc0898..8e22419eac65f 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -280,7 +280,7 @@ ZEND_FUNCTION(gc_status) zend_gc_get_status(&status); - array_init_size(return_value, 4); + array_init_assoc_size(return_value, 4); add_assoc_long_ex(return_value, "runs", sizeof("runs")-1, (long)status.runs); add_assoc_long_ex(return_value, "collected", sizeof("collected")-1, (long)status.collected); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index afa8804c9bdf1..32d22a7994aad 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2101,7 +2101,7 @@ static zend_always_inline void zend_fetch_dimension_address(zval *result, zval * return; } } - array_init(container); + array_init(container); /* TODO benchmark and check if array_init_assoc is faster */ goto fetch_from_array; } else { goto return_null; diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 2d33b93a5d53a..dec5cde0fafc5 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -245,7 +245,7 @@ static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize ht->nInternalPointer = 0; ht->nNextFreeElement = ZEND_LONG_MIN; ht->pDestructor = pDestructor; - /* TODO: Decide on the best way to specify the size of a packed table exactly? Currently, send_hash_check_size rounds up to the nearest power of 2. */ + /* TODO: Decide on the best way to specify the size of a packed table exactly? This is a first attempt*/ ht->nTableSize = nSize <= HT_MIN_SIZE_UNPACKED ? nSize : zend_hash_check_size(nSize); } @@ -261,6 +261,13 @@ ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void) return ht; } +ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_assoc_0(void) +{ + HashTable *ht = emalloc(sizeof(HashTable)); + _zend_hash_init_int(ht, HT_MIN_SIZE_UNPACKED, ZVAL_PTR_DTOR, 0); + return ht; +} + ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize) { HashTable *ht = emalloc(sizeof(HashTable)); @@ -268,6 +275,13 @@ ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize) return ht; } +ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_assoc(uint32_t nSize) +{ + HashTable *ht = emalloc(sizeof(HashTable)); + _zend_hash_init_int(ht, nSize < HT_MIN_SIZE_UNPACKED ? HT_MIN_SIZE_UNPACKED : nSize, ZVAL_PTR_DTOR, 0); + return ht; +} + ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2) { Bucket *p; diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 7263c47a822fc..ab1ed37a2924f 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -290,13 +290,27 @@ ZEND_API void ZEND_FASTCALL zend_hash_rehash(HashTable *ht); : \ _zend_new_array((size)) \ ) +# define zend_new_array_assoc(size) \ + (__builtin_constant_p(size) ? \ + ((((uint32_t)(size)) <= HT_MIN_SIZE_UNPACKED) ? \ + _zend_new_array_assoc_0() \ + : \ + _zend_new_array_assoc((size)) \ + ) \ + : \ + _zend_new_array_assoc((size)) \ + ) #else # define zend_new_array(size) \ _zend_new_array(size) +# define zend_new_array_assoc(size) \ + _zend_new_array_assoc(size) #endif ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void); +ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_assoc_0(void); ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t size); +ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_assoc(uint32_t size); ZEND_API HashTable* ZEND_FASTCALL zend_new_pair(zval *val1, zval *val2); ZEND_API uint32_t zend_array_count(HashTable *ht); ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source); diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 7b4db44de8e2a..43024faa62816 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -633,7 +633,7 @@ ZEND_API void ZEND_FASTCALL convert_to_array(zval *op) /* {{{ */ } else { zval_ptr_dtor(op); /*ZVAL_EMPTY_ARRAY(op);*/ - array_init(op); + array_init_assoc(op); } } break; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 6fa82545e70b5..d4d6630f761d8 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1567,7 +1567,7 @@ ZEND_VM_HELPER(zend_pre_dec_helper, VAR|CV, ANY) SAVE_OPLINE(); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { - ZVAL_NULL(var_ptr); + ZVAL_NULL(var_ptr); ZVAL_UNDEFINED_OP1(); } @@ -2323,7 +2323,7 @@ ZEND_VM_C_LABEL(fetch_obj_is_fast_copy): } retval = zobj->handlers->read_property(zobj, name, BP_VAR_IS, cache_slot, EX_VAR(opline->result.var)); - + if (OP2_TYPE != IS_CONST) { zend_tmp_string_release(tmp_name); } @@ -5669,10 +5669,10 @@ ZEND_VM_HANDLER(147, ZEND_ADD_ARRAY_UNPACK, ANY, ANY) { USE_OPLINE zval *op1; - + SAVE_OPLINE(); op1 = GET_OP1_ZVAL_PTR(BP_VAR_R); - + ZEND_VM_C_LABEL(add_unpack_again): if (EXPECTED(Z_TYPE_P(op1) == IS_ARRAY)) { HashTable *ht = Z_ARRVAL_P(op1); @@ -5713,11 +5713,11 @@ ZEND_VM_C_LABEL(add_unpack_again): } HANDLE_EXCEPTION(); } - + if (iter->funcs->rewind) { iter->funcs->rewind(iter); } - + for (; iter->funcs->valid(iter) == SUCCESS; ) { zval *val; @@ -5766,7 +5766,7 @@ ZEND_VM_C_LABEL(add_unpack_again): } else { zend_throw_error(NULL, "Only arrays and Traversables can be unpacked"); } - + FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -5871,7 +5871,7 @@ ZEND_VM_COLD_CONST_HANDLER(51, ZEND_CAST, CONST|TMP|VAR|CV, ANY, TYPE) } Z_OBJ_P(result)->properties = ht; } else if (Z_TYPE_P(expr) != IS_NULL) { - Z_OBJ_P(result)->properties = ht = zend_new_array(1); + Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1); expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); if (OP1_TYPE == IS_CONST) { if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 6bd3add11c263..8f694778619e7 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3989,7 +3989,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_CONST_H } Z_OBJ_P(result)->properties = ht; } else if (Z_TYPE_P(expr) != IS_NULL) { - Z_OBJ_P(result)->properties = ht = zend_new_array(1); + Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1); expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); if (IS_CONST == IS_CONST) { 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 } Z_OBJ_P(result)->properties = ht; } else if (Z_TYPE_P(expr) != IS_NULL) { - Z_OBJ_P(result)->properties = ht = zend_new_array(1); + Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1); expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); if (IS_TMP_VAR == IS_CONST) { 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 } Z_OBJ_P(result)->properties = ht; } else if (Z_TYPE_P(expr) != IS_NULL) { - Z_OBJ_P(result)->properties = ht = zend_new_array(1); + Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1); expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); if (IS_VAR == IS_CONST) { 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 } Z_OBJ_P(result)->properties = ht; } else if (Z_TYPE_P(expr) != IS_NULL) { - Z_OBJ_P(result)->properties = ht = zend_new_array(1); + Z_OBJ_P(result)->properties = ht = zend_new_array_assoc(1); expr = zend_hash_add_new(ht, ZSTR_KNOWN(ZEND_STR_SCALAR), expr); if (IS_CV == IS_CONST) { if (UNEXPECTED(Z_OPT_REFCOUNTED_P(expr))) Z_ADDREF_P(expr); diff --git a/ext/standard/array.c b/ext/standard/array.c index 7296e0f607b2c..6564333bb8bdb 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -2595,9 +2595,9 @@ PHP_FUNCTION(compact) or multiple string names, rather than a combination of both. So quickly guess a minimum result size based on that */ if (num_args && Z_TYPE(args[0]) == IS_ARRAY) { - array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0]))); + array_init_assoc_size(return_value, zend_hash_num_elements(Z_ARRVAL(args[0]))); } else { - array_init_size(return_value, num_args); + array_init_assoc_size(return_value, num_args); } for (i = 0; i < num_args; i++) { @@ -2688,7 +2688,7 @@ PHP_FUNCTION(array_fill_keys) ZEND_PARSE_PARAMETERS_END(); /* Initialize return array */ - array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys))); + array_init_assoc_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys))); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), entry) { ZVAL_DEREF(entry); diff --git a/travis/compile.sh b/travis/compile.sh index 52300c336106c..e4706e0f96163 100755 --- a/travis/compile.sh +++ b/travis/compile.sh @@ -1,18 +1,84 @@ #!/bin/bash -export CFLAGS="-O3" +if [[ "$ENABLE_ZTS" == 1 ]]; then + TS="--enable-zts"; +else + TS=""; +fi +if [[ "$ENABLE_DEBUG" == 1 ]]; then + DEBUG="--enable-debug"; +else + DEBUG=""; +fi + +if [[ -z "$CONFIG_LOG_FILE" ]]; then + CONFIG_QUIET="--quiet" + CONFIG_LOG_FILE="/dev/stdout" +else + CONFIG_QUIET="" +fi +if [[ -z "$MAKE_LOG_FILE" ]]; then + MAKE_QUIET="--quiet" + MAKE_LOG_FILE="/dev/stdout" +else + MAKE_QUIET="" +fi + +MAKE_JOBS=${MAKE_JOBS:-$(nproc)} + ./buildconf --force ./configure \ ---prefix="$HOME"/php-8.0.0-minsize-nts-install \ ---enable-iconv \ +--enable-option-checking=fatal \ +--prefix="$HOME"/php-install \ +$CONFIG_QUIET \ +$DEBUG \ +$TS \ +--enable-phpdbg \ +--enable-fpm \ +--with-pdo-mysql=mysqlnd \ +--with-mysqli=mysqlnd \ +--with-pgsql \ +--with-pdo-pgsql \ +--with-pdo-sqlite \ +--enable-intl \ +--without-pear \ +--enable-gd \ +--with-jpeg \ +--with-webp \ +--with-freetype \ +--with-xpm \ +--enable-exif \ +--with-zip \ +--with-zlib \ +--with-zlib-dir=/usr \ +--enable-soap \ +--enable-xmlreader \ +--with-xsl \ +--with-tidy \ +--with-xmlrpc \ +--enable-sysvsem \ +--enable-sysvshm \ +--enable-shmop \ +--enable-pcntl \ +--with-readline \ --enable-mbstring \ ---enable-dom \ ---enable-simplexml \ ---with-libxml \ ---enable-opcache \ ---enable-tokenizer \ ---enable-json \ ---enable-filter \ ---disable-all +--with-curl \ +--with-gettext \ +--enable-sockets \ +--with-bz2 \ +--with-openssl \ +--with-gmp \ +--enable-bcmath \ +--enable-calendar \ +--enable-ftp \ +--with-pspell=/usr \ +--with-enchant=/usr \ +--with-kerberos \ +--enable-sysvmsg \ +--with-ffi \ +--enable-zend-test=shared \ +--enable-werror \ +--with-pear \ +> "$CONFIG_LOG_FILE" -make -j8 -make install +make "-j${MAKE_JOBS}" $MAKE_QUIET > "$MAKE_LOG_FILE" +make install >> "$MAKE_LOG_FILE" From 96f495dcb910fd2c8af410824a6e93f1851b6d16 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 5 Oct 2019 13:48:05 -0400 Subject: [PATCH 12/16] Nit for json --- ext/json/json_parser.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index 2f8a260c98b62..1a1bed6e649fc 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -230,7 +230,7 @@ static int php_json_parser_array_append(php_json_parser *parser, zval *array, zv static int php_json_parser_object_create(php_json_parser *parser, zval *object) { if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) { - array_init(object); + array_init_assoc(object); return SUCCESS; } else { return object_init(object); From 97399491532711bf30f5e13b4b75e0e3ce1c4452 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 5 Oct 2019 14:12:12 -0400 Subject: [PATCH 13/16] Fix the nTableSize tracking --- Zend/zend_hash.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index dec5cde0fafc5..5986c31899a82 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -342,12 +342,15 @@ ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht) void *new_data, *old_data = HT_GET_DATA_ADDR(ht); Bucket *old_buckets = ht->arData; uint32_t nSize = ht->nTableSize; - uint32_t nNewSize = nSize >= HT_MIN_SIZE_UNPACKED ? nSize : HT_MIN_SIZE_UNPACKED; + if (nSize < HT_MIN_SIZE_UNPACKED) { + nSize = HT_MIN_SIZE_UNPACKED; + ht->nTableSize = HT_MIN_SIZE_UNPACKED; + } HT_ASSERT_RC1(ht); HT_FLAGS(ht) &= ~HASH_FLAG_PACKED; - new_data = pemalloc(HT_SIZE_EX(nNewSize, HT_SIZE_TO_MASK(nNewSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); - ht->nTableMask = HT_SIZE_TO_MASK(nNewSize); + new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); + ht->nTableMask = HT_SIZE_TO_MASK(nSize); HT_SET_DATA_ADDR(ht, new_data); memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed); pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); From a9328b1a80cd5454ff5b585de5010ab29da75ecf Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 5 Oct 2019 15:38:02 -0400 Subject: [PATCH 14/16] nit --- Zend/zend_hash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 5986c31899a82..95f76f7585c3c 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1191,7 +1191,7 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht) ht->nTableSize = nSize; new_data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); - ht->nTableMask = HT_SIZE_TO_MASK(ht->nTableSize); + ht->nTableMask = HT_SIZE_TO_MASK(nSize); HT_SET_DATA_ADDR(ht, new_data); memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed); pefree(old_data, GC_FLAGS(ht) & IS_ARRAY_PERSISTENT); From 96c469a86e622137976df2e8fbc15ed85032bef9 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 5 Oct 2019 16:25:24 -0400 Subject: [PATCH 15/16] Assert the new hash size is a power of 2 --- Zend/zend_hash.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 95f76f7585c3c..cfc9d9791d7f2 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -345,6 +345,9 @@ ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht) if (nSize < HT_MIN_SIZE_UNPACKED) { nSize = HT_MIN_SIZE_UNPACKED; ht->nTableSize = HT_MIN_SIZE_UNPACKED; + } else if (nSize & (nSize - 1)) { + nSize = zend_hash_check_size(nSize); + ht->nTableSize = nSize; } HT_ASSERT_RC1(ht); From c6b88d1440e7c1d1b8ec3ef45348ac449a183341 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sat, 5 Oct 2019 16:50:28 -0400 Subject: [PATCH 16/16] Forbid initializing a hash with a size less than 2 --- Zend/zend_hash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index cfc9d9791d7f2..20c4a82c754ec 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -246,7 +246,7 @@ static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize ht->nNextFreeElement = ZEND_LONG_MIN; ht->pDestructor = pDestructor; /* TODO: Decide on the best way to specify the size of a packed table exactly? This is a first attempt*/ - ht->nTableSize = nSize <= HT_MIN_SIZE_UNPACKED ? nSize : zend_hash_check_size(nSize); + ht->nTableSize = (nSize <= HT_MIN_SIZE_UNPACKED ? (nSize < HT_MIN_SIZE ? HT_MIN_SIZE : nSize) : zend_hash_check_size(nSize)); } ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent)