Merge branch 'PHP-7.1'

* PHP-7.1:
  Introduced HT_IS_PACKED() and HT_IS_WITHOUT_HOLES() macros. (Benjamin Coutu)
This commit is contained in:
Dmitry Stogov 2016-10-19 23:12:17 +03:00
commit 65ea250022
6 changed files with 44 additions and 29 deletions

View file

@ -34,9 +34,7 @@
#define HT_POISONED_PTR ((HashTable *) (intptr_t) -1) #define HT_POISONED_PTR ((HashTable *) (intptr_t) -1)
#if ZEND_DEBUG #if ZEND_DEBUG
/*
#define HASH_MASK_CONSISTENCY 0xc0
*/
#define HT_OK 0x00 #define HT_OK 0x00
#define HT_IS_DESTROYING 0x40 #define HT_IS_DESTROYING 0x40
#define HT_DESTROYED 0x80 #define HT_DESTROYED 0x80
@ -44,10 +42,10 @@
static void _zend_is_inconsistent(const HashTable *ht, const char *file, int line) static void _zend_is_inconsistent(const HashTable *ht, const char *file, int line)
{ {
if ((ht->u.flags & HASH_MASK_CONSISTENCY) == HT_OK) { if (ht->u.v.consistency == HT_OK) {
return; return;
} }
switch ((ht->u.flags & HASH_MASK_CONSISTENCY)) { switch (ht->u.v.consistency) {
case HT_IS_DESTROYING: case HT_IS_DESTROYING:
zend_output_debug_string(1, "%s(%d) : ht=%p is being destroyed", file, line, ht); zend_output_debug_string(1, "%s(%d) : ht=%p is being destroyed", file, line, ht);
break; break;
@ -65,7 +63,7 @@ static void _zend_is_inconsistent(const HashTable *ht, const char *file, int lin
} }
#define IS_CONSISTENT(a) _zend_is_inconsistent(a, __FILE__, __LINE__); #define IS_CONSISTENT(a) _zend_is_inconsistent(a, __FILE__, __LINE__);
#define SET_INCONSISTENT(n) do { \ #define SET_INCONSISTENT(n) do { \
(ht)->u.flags |= n; \ (ht)->u.v.consistency = n; \
} while (0) } while (0)
#else #else
#define IS_CONSISTENT(a) #define IS_CONSISTENT(a)
@ -888,7 +886,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_rehash(HashTable *ht)
HT_HASH_RESET(ht); HT_HASH_RESET(ht);
i = 0; i = 0;
p = ht->arData; p = ht->arData;
if (ht->nNumUsed == ht->nNumOfElements) { if (HT_IS_WITHOUT_HOLES(ht)) {
do { do {
nIndex = p->h | ht->nTableMask; nIndex = p->h | ht->nTableMask;
Z_NEXT(p->val) = HT_HASH(ht, nIndex); Z_NEXT(p->val) = HT_HASH(ht, nIndex);
@ -1229,8 +1227,8 @@ ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
if (ht->pDestructor) { if (ht->pDestructor) {
SET_INCONSISTENT(HT_IS_DESTROYING); SET_INCONSISTENT(HT_IS_DESTROYING);
if (ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) { if (HT_HAS_STATIC_KEYS_ONLY(ht)) {
if (ht->nNumUsed == ht->nNumOfElements) { if (HT_IS_WITHOUT_HOLES(ht)) {
do { do {
ht->pDestructor(&p->val); ht->pDestructor(&p->val);
} while (++p != end); } while (++p != end);
@ -1241,7 +1239,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
} }
} while (++p != end); } while (++p != end);
} }
} else if (ht->nNumUsed == ht->nNumOfElements) { } else if (HT_IS_WITHOUT_HOLES(ht)) {
do { do {
ht->pDestructor(&p->val); ht->pDestructor(&p->val);
if (EXPECTED(p->key)) { if (EXPECTED(p->key)) {
@ -1261,7 +1259,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
SET_INCONSISTENT(HT_DESTROYED); SET_INCONSISTENT(HT_DESTROYED);
} else { } else {
if (!(ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS))) { if (!HT_HAS_STATIC_KEYS_ONLY(ht)) {
do { do {
if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) { if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) {
if (EXPECTED(p->key)) { if (EXPECTED(p->key)) {
@ -1300,11 +1298,11 @@ ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
end = p + ht->nNumUsed; end = p + ht->nNumUsed;
SET_INCONSISTENT(HT_IS_DESTROYING); SET_INCONSISTENT(HT_IS_DESTROYING);
if (ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) { if (HT_HAS_STATIC_KEYS_ONLY(ht)) {
do { do {
i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC); i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
} while (++p != end); } while (++p != end);
} else if (ht->nNumUsed == ht->nNumOfElements) { } else if (HT_IS_WITHOUT_HOLES(ht)) {
do { do {
i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC); i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
if (EXPECTED(p->key)) { if (EXPECTED(p->key)) {
@ -1342,8 +1340,8 @@ ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht)
p = ht->arData; p = ht->arData;
end = p + ht->nNumUsed; end = p + ht->nNumUsed;
if (ht->pDestructor) { if (ht->pDestructor) {
if (ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) { if (HT_HAS_STATIC_KEYS_ONLY(ht)) {
if (ht->nNumUsed == ht->nNumOfElements) { if (HT_IS_WITHOUT_HOLES(ht)) {
do { do {
ht->pDestructor(&p->val); ht->pDestructor(&p->val);
} while (++p != end); } while (++p != end);
@ -1354,7 +1352,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht)
} }
} while (++p != end); } while (++p != end);
} }
} else if (ht->nNumUsed == ht->nNumOfElements) { } else if (HT_IS_WITHOUT_HOLES(ht)) {
do { do {
ht->pDestructor(&p->val); ht->pDestructor(&p->val);
if (EXPECTED(p->key)) { if (EXPECTED(p->key)) {
@ -1372,8 +1370,8 @@ ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht)
} while (++p != end); } while (++p != end);
} }
} else { } else {
if (!(ht->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS))) { if (!HT_HAS_STATIC_KEYS_ONLY(ht)) {
if (ht->nNumUsed == ht->nNumOfElements) { if (HT_IS_WITHOUT_HOLES(ht)) {
do { do {
if (EXPECTED(p->key)) { if (EXPECTED(p->key)) {
zend_string_release(p->key); zend_string_release(p->key);
@ -1410,11 +1408,11 @@ ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht)
if (ht->nNumUsed) { if (ht->nNumUsed) {
p = ht->arData; p = ht->arData;
end = p + ht->nNumUsed; end = p + ht->nNumUsed;
if (ht->u.flags & HASH_FLAG_STATIC_KEYS) { if (HT_HAS_STATIC_KEYS_ONLY(ht)) {
do { do {
i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC); i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
} while (++p != end); } while (++p != end);
} else if (ht->nNumUsed == ht->nNumOfElements) { } else if (HT_IS_WITHOUT_HOLES(ht)) {
do { do {
i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC); i_zval_ptr_dtor(&p->val ZEND_FILE_LINE_CC);
if (EXPECTED(p->key)) { if (EXPECTED(p->key)) {
@ -1802,7 +1800,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
target->nInternalPointer = source->nInternalPointer; target->nInternalPointer = source->nInternalPointer;
HT_HASH_RESET_PACKED(target); HT_HASH_RESET_PACKED(target);
if (target->nNumUsed == target->nNumOfElements) { if (HT_IS_WITHOUT_HOLES(target)) {
zend_array_dup_packed_elements(source, target, 0); zend_array_dup_packed_elements(source, target, 0);
} else { } else {
zend_array_dup_packed_elements(source, target, 1); zend_array_dup_packed_elements(source, target, 1);
@ -1823,14 +1821,14 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target))); HT_SET_DATA_ADDR(target, emalloc(HT_SIZE(target)));
HT_HASH_RESET(target); HT_HASH_RESET(target);
if (target->u.flags & HASH_FLAG_STATIC_KEYS) { if (HT_HAS_STATIC_KEYS_ONLY(target)) {
if (source->nNumUsed == source->nNumOfElements) { if (HT_IS_WITHOUT_HOLES(source)) {
idx = zend_array_dup_elements(source, target, 1, 0); idx = zend_array_dup_elements(source, target, 1, 0);
} else { } else {
idx = zend_array_dup_elements(source, target, 1, 1); idx = zend_array_dup_elements(source, target, 1, 1);
} }
} else { } else {
if (source->nNumUsed == source->nNumOfElements) { if (HT_IS_WITHOUT_HOLES(source)) {
idx = zend_array_dup_elements(source, target, 0, 0); idx = zend_array_dup_elements(source, target, 0, 0);
} else { } else {
idx = zend_array_dup_elements(source, target, 0, 1); idx = zend_array_dup_elements(source, target, 0, 1);
@ -2253,7 +2251,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_sort_ex(HashTable *ht, sort_func_t sort, co
return SUCCESS; return SUCCESS;
} }
if (ht->nNumUsed == ht->nNumOfElements) { if (HT_IS_WITHOUT_HOLES(ht)) {
i = ht->nNumUsed; i = ht->nNumUsed;
} else { } else {
for (j = 0, i = 0; j < ht->nNumUsed; j++) { for (j = 0, i = 0; j < ht->nNumUsed; j++) {

View file

@ -39,10 +39,17 @@
#define HASH_FLAG_APPLY_PROTECTION (1<<1) #define HASH_FLAG_APPLY_PROTECTION (1<<1)
#define HASH_FLAG_PACKED (1<<2) #define HASH_FLAG_PACKED (1<<2)
#define HASH_FLAG_INITIALIZED (1<<3) #define HASH_FLAG_INITIALIZED (1<<3)
#define HASH_FLAG_STATIC_KEYS (1<<4) #define HASH_FLAG_STATIC_KEYS (1<<4) /* long and interned strings */
#define HASH_FLAG_HAS_EMPTY_IND (1<<5) #define HASH_FLAG_HAS_EMPTY_IND (1<<5)
#define HASH_MASK_CONSISTENCY 0xc0 #define HT_IS_PACKED(ht) \
(((ht)->u.flags & HASH_FLAG_PACKED) != 0)
#define HT_IS_WITHOUT_HOLES(ht) \
((ht)->nNumUsed == (ht)->nNumOfElements)
#define HT_HAS_STATIC_KEYS_ONLY(ht) \
(((ht)->u.flags & (HASH_FLAG_PACKED|HASH_FLAG_STATIC_KEYS)) != 0)
typedef struct _zend_hash_key { typedef struct _zend_hash_key {
zend_ulong h; zend_ulong h;

View file

@ -182,7 +182,7 @@ struct _zend_array {
zend_uchar flags, zend_uchar flags,
zend_uchar nApplyCount, zend_uchar nApplyCount,
zend_uchar nIteratorsCount, zend_uchar nIteratorsCount,
zend_uchar reserve) zend_uchar consistency)
} v; } v;
uint32_t flags; uint32_t flags;
} u; } u;

View file

@ -45,6 +45,10 @@ static int php_json_determine_array_type(zval *val) /* {{{ */
zend_string *key; zend_string *key;
zend_ulong index, idx; zend_ulong index, idx;
if (HT_IS_PACKED(myht) && HT_IS_WITHOUT_HOLES(myht)) {
return PHP_JSON_OUTPUT_ARRAY;
}
idx = 0; idx = 0;
ZEND_HASH_FOREACH_KEY(myht, index, key) { ZEND_HASH_FOREACH_KEY(myht, index, key) {
if (key) { if (key) {

View file

@ -3483,6 +3483,10 @@ static int is_map(zval *array)
zend_string *key; zend_string *key;
zend_ulong i = 0; zend_ulong i = 0;
if (HT_IS_PACKED(Z_ARRVAL_P(array)) && HT_IS_WITHOUT_HOLES(Z_ARRVAL_P(array))) {
return FALSE;
}
ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(array), index, key) { ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(array), index, key) {
if (key || index != i) { if (key || index != i) {
return TRUE; return TRUE;

View file

@ -2903,7 +2903,9 @@ PHP_FUNCTION(array_slice)
/* Start at the beginning and go until we hit offset */ /* Start at the beginning and go until we hit offset */
pos = 0; pos = 0;
if ((Z_ARRVAL_P(input)->u.flags & HASH_FLAG_PACKED) && !preserve_keys) { if (HT_IS_PACKED(Z_ARRVAL_P(input)) &&
(!preserve_keys ||
(offset == 0 && HT_IS_WITHOUT_HOLES(Z_ARRVAL_P(input))))) {
zend_hash_real_init(Z_ARRVAL_P(return_value), 1); zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) { ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), entry) { ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(input), entry) {