Improved hash table copying

This commit is contained in:
Dmitry Stogov 2015-05-19 13:22:58 +03:00
parent 27b83079fe
commit 6c8d49b6b0
2 changed files with 44 additions and 36 deletions

View File

@ -877,7 +877,7 @@ static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht,
__fill_ht->nInternalPointer = 0; \
} while (0)
static zend_always_inline void _zend_hash_append(HashTable *ht, zend_string *key, zval *zv)
static zend_always_inline zval *_zend_hash_append(HashTable *ht, zend_string *key, zval *zv)
{
uint32_t idx = ht->nNumUsed++;
uint32_t nIndex;
@ -896,9 +896,10 @@ static zend_always_inline void _zend_hash_append(HashTable *ht, zend_string *key
HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
ht->nNumUsed = idx + 1;
ht->nNumOfElements++;
return &p->val;
}
static zend_always_inline void _zend_hash_append_ptr(HashTable *ht, zend_string *key, void *ptr)
static zend_always_inline zval *_zend_hash_append_ptr(HashTable *ht, zend_string *key, void *ptr)
{
uint32_t idx = ht->nNumUsed++;
uint32_t nIndex;
@ -917,6 +918,7 @@ static zend_always_inline void _zend_hash_append_ptr(HashTable *ht, zend_string
HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
ht->nNumUsed = idx + 1;
ht->nNumOfElements++;
return &p->val;
}
static zend_always_inline void _zend_hash_append_ind(HashTable *ht, zend_string *key, zval *ptr)

View File

@ -124,11 +124,12 @@ void zend_accel_move_user_functions(HashTable *src, HashTable *dst)
dtor_func_t orig_dtor = src->pDestructor;
src->pDestructor = NULL;
zend_hash_extend(dst, dst->nNumUsed + src->nNumUsed, 0);
ZEND_HASH_REVERSE_FOREACH_BUCKET(src, p) {
zend_function *function = Z_PTR(p->val);
if (EXPECTED(function->type == ZEND_USER_FUNCTION)) {
zend_hash_add_new_ptr(dst, p->key, function);
_zend_hash_append_ptr(dst, p->key, function);
zend_hash_del_bucket(src, p);
} else {
break;
@ -636,23 +637,25 @@ static void zend_class_copy_ctor(zend_class_entry **pce)
static void zend_accel_function_hash_copy(HashTable *target, HashTable *source)
{
zend_function *function1, *function2;
uint idx;
Bucket *p;
Bucket *p, *end;
zval *t;
for (idx = 0; idx < source->nNumUsed; idx++) {
p = source->arData + idx;
if (Z_TYPE(p->val) == IS_UNDEF) continue;
zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
p = source->arData;
end = p + source->nNumUsed;
for (; p != end; p++) {
if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
ZEND_ASSERT(p->key);
t = zend_hash_add(target, p->key, &p->val);
if (UNEXPECTED(t == NULL)) {
if (p->key->len > 0 && p->key->val[0] == 0) {
t = zend_hash_find(target, p->key);
if (UNEXPECTED(t != NULL)) {
if (EXPECTED(p->key->len > 0) && EXPECTED(p->key->val[0] == 0)) {
/* Mangled key */
t = zend_hash_update(target, p->key, &p->val);
} else {
t = zend_hash_find(target, p->key);
goto failure;
}
} else {
_zend_hash_append_ptr(target, p->key, Z_PTR(p->val));
}
}
target->nInternalPointer = target->nNumOfElements ? 0 : HT_INVALID_IDX;
@ -678,25 +681,26 @@ failure:
static void zend_accel_function_hash_copy_from_shm(HashTable *target, HashTable *source)
{
zend_function *function1, *function2;
uint idx;
Bucket *p;
Bucket *p, *end;
zval *t;
for (idx = 0; idx < source->nNumUsed; idx++) {
p = source->arData + idx;
if (Z_TYPE(p->val) == IS_UNDEF) continue;
zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
p = source->arData;
end = p + source->nNumUsed;
for (; p != end; p++) {
if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
ZEND_ASSERT(p->key);
t = zend_hash_add(target, p->key, &p->val);
if (UNEXPECTED(t == NULL)) {
if (p->key->len > 0 && p->key->val[0] == 0) {
t = zend_hash_find(target, p->key);
if (UNEXPECTED(t != NULL)) {
if (EXPECTED(p->key->len > 0) && EXPECTED(p->key->val[0] == 0)) {
/* Mangled key */
t = zend_hash_update(target, p->key, &p->val);
zend_hash_update_ptr(target, p->key, ARENA_REALLOC(Z_PTR(p->val)));
} else {
t = zend_hash_find(target, p->key);
goto failure;
}
} else {
_zend_hash_append_ptr(target, p->key, ARENA_REALLOC(Z_PTR(p->val)));
}
Z_PTR_P(t) = ARENA_REALLOC(Z_PTR(p->val));
}
target->nInternalPointer = target->nNumOfElements ? 0 : HT_INVALID_IDX;
return;
@ -721,26 +725,28 @@ failure:
static void zend_accel_class_hash_copy(HashTable *target, HashTable *source, unique_copy_ctor_func_t pCopyConstructor)
{
zend_class_entry *ce1;
uint idx;
Bucket *p;
Bucket *p, *end;
zval *t;
for (idx = 0; idx < source->nNumUsed; idx++) {
p = source->arData + idx;
if (Z_TYPE(p->val) == IS_UNDEF) continue;
zend_hash_extend(target, target->nNumUsed + source->nNumUsed, 0);
p = source->arData;
end = p + source->nNumUsed;
for (; p != end; p++) {
if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
ZEND_ASSERT(p->key);
t = zend_hash_add(target, p->key, &p->val);
if (UNEXPECTED(t == NULL)) {
if (p->key->len > 0 && p->key->val[0] == 0) {
t = zend_hash_find(target, p->key);
if (UNEXPECTED(t != NULL)) {
if (EXPECTED(p->key->len > 0) && EXPECTED(p->key->val[0] == 0)) {
/* Mangled key - ignore and wait for runtime */
continue;
} else if (!ZCG(accel_directives).ignore_dups) {
t = zend_hash_find(target, p->key);
} else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) {
goto failure;
}
}
if (pCopyConstructor) {
pCopyConstructor(&Z_PTR_P(t));
} else {
t = _zend_hash_append_ptr(target, p->key, Z_PTR(p->val));
if (pCopyConstructor) {
pCopyConstructor(&Z_PTR_P(t));
}
}
}
target->nInternalPointer = target->nNumOfElements ? 0 : HT_INVALID_IDX;