]> granicus.if.org Git - php/commitdiff
Perform run-time binding reusing HashTable bucket (without new bucket insertion).
authorDmitry Stogov <dmitry@zend.com>
Tue, 28 Aug 2018 21:35:07 +0000 (00:35 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 28 Aug 2018 21:35:07 +0000 (00:35 +0300)
Zend/zend_compile.c
Zend/zend_hash.c
Zend/zend_hash.h

index 13622fbe27dbfc8054126fb5ba5757e58f484268..45e154cbe97b37e04df0651f8bdb7d4c21c122a8 100644 (file)
@@ -1042,33 +1042,30 @@ static zend_never_inline ZEND_COLD ZEND_NORETURN void do_bind_function_error(zen
        if (old_function->type == ZEND_USER_FUNCTION
                && old_function->op_array.last > 0) {
                zend_error_noreturn(error_level, "Cannot redeclare %s() (previously declared in %s:%d)",
-                                       ZSTR_VAL(op_array->function_name),
+                                       op_array ? ZSTR_VAL(op_array->function_name) : ZSTR_VAL(old_function->common.function_name),
                                        ZSTR_VAL(old_function->op_array.filename),
                                        old_function->op_array.opcodes[0].lineno);
        } else {
-               zend_error_noreturn(error_level, "Cannot redeclare %s()", ZSTR_VAL(op_array->function_name));
+               zend_error_noreturn(error_level, "Cannot redeclare %s()",
+                       op_array ? ZSTR_VAL(op_array->function_name) : ZSTR_VAL(old_function->common.function_name));
        }
 }
 
 ZEND_API int do_bind_function(zval *lcname) /* {{{ */
 {
-       zend_function *function, *new_function;
+       zend_function *function;
        zval *rtd_key, *zv;
 
        rtd_key = lcname + 1;
        zv = zend_hash_find_ex(EG(function_table), Z_STR_P(rtd_key), 1);
-       new_function = function = (zend_function*)Z_PTR_P(zv);
-       if (function->op_array.static_variables
-        && !(function->op_array.fn_flags & ZEND_ACC_IMMUTABLE)) {
-               new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
-               memcpy(new_function, function, sizeof(zend_op_array));
-               function->op_array.static_variables = NULL; /* NULL out the unbound function */
-               if (function->op_array.refcount) {
-                       (*function->op_array.refcount)++;
-               }
-       }
-       if (UNEXPECTED(zend_hash_add_ptr(EG(function_table), Z_STR_P(lcname), new_function) == NULL)) {
-               do_bind_function_error(Z_STR_P(lcname), &new_function->op_array, 0);
+       if (UNEXPECTED(!zv)) {
+               do_bind_function_error(Z_STR_P(lcname), NULL, 0);
+               return FAILURE;
+       }
+       function = (zend_function*)Z_PTR_P(zv);
+       zv = zend_hash_set_bucket_key(EG(function_table), (Bucket*)zv, Z_STR_P(lcname));
+       if (UNEXPECTED(!zv)) {
+               do_bind_function_error(Z_STR_P(lcname), &function->op_array, 0);
                return FAILURE;
        }
        return SUCCESS;
@@ -1082,22 +1079,20 @@ ZEND_API int do_bind_class(zval *lcname) /* {{{ */
 
        rtd_key = lcname + 1;
        zv = zend_hash_find_ex(EG(class_table), Z_STR_P(rtd_key), 1);
-       ZEND_ASSERT(zv);
-       ce = (zend_class_entry*)Z_PTR_P(zv);
+       if (UNEXPECTED(!zv)) {
+               zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare  %s, because the name is already in use", Z_STRVAL_P(lcname));
+               return FAILURE;
+       }
 
-       if (UNEXPECTED(zend_hash_add_ptr(EG(class_table), Z_STR_P(lcname), ce) == NULL)) {
-               /* If we're in compile time, in practice, it's quite possible
-                * that we'll never reach this class declaration at runtime,
-                * so we shut up about it.  This allows the if (!defined('FOO')) { return; }
-                * approach to work.
-                */
+       ce = (zend_class_entry*)Z_PTR_P(zv);
+       zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, Z_STR_P(lcname));
+       if (UNEXPECTED(!zv)) {
                zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
                return FAILURE;
-       } else {
-               ce->refcount++;
-               zend_do_link_class(ce, NULL);
-               return SUCCESS;
        }
+
+       zend_do_link_class(ce, NULL);
+       return SUCCESS;
 }
 /* }}} */
 
@@ -1110,7 +1105,7 @@ ZEND_API int do_bind_inherited_class(zval *lcname, zend_class_entry *parent_ce)
 
        zv = zend_hash_find_ex(EG(class_table), Z_STR_P(rtd_key), 1);
 
-       if (!zv) {
+       if (UNEXPECTED(!zv)) {
                /* If we're in compile time, in practice, it's quite possible
                 * that we'll never reach this class declaration at runtime,
                 * so we shut up about it.  This allows the if (!defined('FOO')) { return; }
@@ -1120,17 +1115,15 @@ ZEND_API int do_bind_inherited_class(zval *lcname, zend_class_entry *parent_ce)
                return FAILURE;
        }
 
-       ce = (zend_class_entry*)Z_PTR_P(zv);
-
-       ce->refcount++;
-
        /* Register the derived class */
-       if (zend_hash_add_ptr(EG(class_table), Z_STR_P(lcname), ce) == NULL) {
+       ce = (zend_class_entry*)Z_PTR_P(zv);
+       zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, Z_STR_P(lcname));
+       if (UNEXPECTED(!zv)) {
                zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
+               return FAILURE;
        }
 
        zend_do_link_class(ce, parent_ce);
-
        return SUCCESS;
 }
 /* }}} */
index 3a8815336d4a719e50eb2a6b7f84fe38511a26b5..0caf37d7aaaac2cf13793161bfda30d171c22fb0 100644 (file)
@@ -1026,6 +1026,55 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_next_index_insert_new(HashTable *ht, zval
        return _zend_hash_index_add_or_update_i(ht, ht->nNextFreeElement, pData, HASH_ADD | HASH_ADD_NEW | HASH_ADD_NEXT);
 }
 
+ZEND_API zval* ZEND_FASTCALL zend_hash_set_bucket_key(HashTable *ht, Bucket *b, zend_string *key)
+{
+       uint32_t nIndex;
+       uint32_t idx, i;
+       Bucket *p, *arData;
+
+       IS_CONSISTENT(ht);
+       HT_ASSERT_RC1(ht);
+       ZEND_ASSERT(!(HT_FLAGS(ht) & HASH_FLAG_PACKED));
+
+       p = zend_hash_find_bucket(ht, key, 0);
+       if (UNEXPECTED(p)) {
+               return (p == b) ? &p->val : NULL;
+       }
+
+       if (!ZSTR_IS_INTERNED(key)) {
+               zend_string_addref(key);
+               HT_FLAGS(ht) &= ~HASH_FLAG_STATIC_KEYS;
+       }
+
+       arData = ht->arData;
+
+       /* del from hash */
+       idx = HT_IDX_TO_HASH(b - arData);
+       nIndex = b->h | ht->nTableMask;
+       i = HT_HASH_EX(arData, nIndex);
+       if (i == idx) {
+               HT_HASH_EX(arData, nIndex) = Z_NEXT(b->val);
+       } else {
+               p = HT_HASH_TO_BUCKET_EX(arData, i);
+               while (Z_NEXT(p->val) != idx) {
+                       i = Z_NEXT(p->val);
+                       p = HT_HASH_TO_BUCKET_EX(arData, i);
+               }
+               Z_NEXT(p->val) = Z_NEXT(b->val);
+       }
+       zend_string_release(b->key);
+
+       /* add to hash */
+       idx = b - arData;
+       b->key = key;
+       b->h = ZSTR_H(key);
+       nIndex = b->h | ht->nTableMask;
+       Z_NEXT(b->val) = HT_HASH_EX(arData, nIndex);
+       HT_HASH_EX(arData, nIndex) = HT_IDX_TO_HASH(idx);
+
+       return &b->val;
+}
+
 static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht)
 {
 
index 440c92160e3678bf361825e3103f105482729114..7f53003ae8a3e687d54b9ec4f49d488198cb5436 100644 (file)
@@ -128,6 +128,8 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_empty_element(HashTable *ht, ze
 ZEND_API zval* ZEND_FASTCALL zend_hash_add_empty_element(HashTable *ht, zend_string *key);
 ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_empty_element(HashTable *ht, const char *key, size_t len);
 
+ZEND_API zval* ZEND_FASTCALL zend_hash_set_bucket_key(HashTable *ht, Bucket *p, zend_string *key);
+
 #define ZEND_HASH_APPLY_KEEP                           0
 #define ZEND_HASH_APPLY_REMOVE                         1<<0
 #define ZEND_HASH_APPLY_STOP                           1<<1