]> granicus.if.org Git - php/commitdiff
Reduce overhead of case-insensitive constants deprecation for "fast path"
authorDmitry Stogov <dmitry@zend.com>
Tue, 17 Jul 2018 09:58:58 +0000 (12:58 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 17 Jul 2018 09:58:58 +0000 (12:58 +0300)
Zend/zend_constants.c
Zend/zend_constants.h
Zend/zend_execute.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 8b68858ad4c45401751dc3b3b20fdf0d178e377c..48b01863eac313c0e8d0488cb01a06f23edd2f54 100644 (file)
@@ -478,56 +478,6 @@ failure:
        return &c->value;
 }
 
-ZEND_API zend_constant* ZEND_FASTCALL zend_quick_get_constant(
-               const zval *key, uint32_t flags, zend_bool *is_deprecated)
-{
-       zval *zv;
-       const zval *orig_key = key;
-       zend_constant *c = NULL;
-
-       zv = zend_hash_find_ex(EG(zend_constants), Z_STR_P(key), 1);
-       if (zv) {
-               c = (zend_constant*)Z_PTR_P(zv);
-       } else {
-               key++;
-               zv = zend_hash_find_ex(EG(zend_constants), Z_STR_P(key), 1);
-               if (zv && (((zend_constant*)Z_PTR_P(zv))->flags & CONST_CS) == 0) {
-                       c = (zend_constant*)Z_PTR_P(zv);
-               } else {
-                       if ((flags & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) {
-                               key++;
-                               zv = zend_hash_find_ex(EG(zend_constants), Z_STR_P(key), 1);
-                               if (zv) {
-                                       c = (zend_constant*)Z_PTR_P(zv);
-                               } else {
-                                   key++;
-                                       zv = zend_hash_find_ex(EG(zend_constants), Z_STR_P(key), 1);
-                                       if (zv && (((zend_constant*)Z_PTR_P(zv))->flags & CONST_CS) == 0) {
-                                               c = (zend_constant*)Z_PTR_P(zv);
-                                       }
-                               }
-                       }
-               }
-       }
-
-       if (!c) {
-               return NULL;
-       }
-
-       if (is_deprecated) {
-               if (c->flags & (CONST_CS|CONST_CT_SUBST)) {
-                       /* Constant is case-sensitive or true/false/null */
-                       *is_deprecated = 0;
-               } else {
-                       zend_bool ns_fallback = key >= orig_key + 2;
-                       const zval *access_key = ns_fallback ? orig_key + 2 : orig_key - 1;
-                       *is_deprecated = is_access_deprecated(c, Z_STRVAL_P(access_key));
-               }
-       }
-
-       return c;
-}
-
 static void* zend_hash_add_constant(HashTable *ht, zend_string *key, zend_constant *c)
 {
        void *ret;
index e06d91ee14c03127ff876cce2afdcf156eefc312..b8112d33a1483db97a1e49a2a052e379e43af74f 100644 (file)
@@ -82,8 +82,6 @@ ZEND_API int zend_register_constant(zend_constant *c);
 #ifdef ZTS
 void zend_copy_constants(HashTable *target, HashTable *sourc);
 #endif
-ZEND_API zend_constant* ZEND_FASTCALL zend_quick_get_constant(
-               const zval *key, uint32_t flags, zend_bool *is_deprecated);
 END_EXTERN_C()
 
 #define ZEND_CONSTANT_DTOR free_zend_constant
index 0778c19dddc4cfe6b97e55396d990444d66e9e1e..6abdc4c2ca5ea3dc531dac2c84f790ae63e82b11 100644 (file)
@@ -3285,6 +3285,119 @@ static zend_never_inline zend_bool ZEND_FASTCALL zend_fe_reset_iterator(zval *ar
 }
 /* }}} */
 
+static zend_always_inline int _zend_quick_get_constant(
+               const zval *key, uint32_t flags, int check_defined_only OPLINE_DC EXECUTE_DATA_DC) /* {{{ */
+{
+       zval *zv;
+       const zval *orig_key = key;
+       zend_constant *c = NULL;
+
+       zv = zend_hash_find_ex(EG(zend_constants), Z_STR_P(key), 1);
+       if (zv) {
+               c = (zend_constant*)Z_PTR_P(zv);
+       } else {
+               key++;
+               zv = zend_hash_find_ex(EG(zend_constants), Z_STR_P(key), 1);
+               if (zv && (((zend_constant*)Z_PTR_P(zv))->flags & CONST_CS) == 0) {
+                       c = (zend_constant*)Z_PTR_P(zv);
+               } else {
+                       if ((flags & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) {
+                               key++;
+                               zv = zend_hash_find_ex(EG(zend_constants), Z_STR_P(key), 1);
+                               if (zv) {
+                                       c = (zend_constant*)Z_PTR_P(zv);
+                               } else {
+                                   key++;
+                                       zv = zend_hash_find_ex(EG(zend_constants), Z_STR_P(key), 1);
+                                       if (zv && (((zend_constant*)Z_PTR_P(zv))->flags & CONST_CS) == 0) {
+                                               c = (zend_constant*)Z_PTR_P(zv);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if (!c) {
+               if (!check_defined_only) {
+                       if ((opline->op1.num & IS_CONSTANT_UNQUALIFIED) != 0) {
+                               char *actual = (char *)zend_memrchr(Z_STRVAL_P(RT_CONSTANT(opline, opline->op2)), '\\', Z_STRLEN_P(RT_CONSTANT(opline, opline->op2)));
+                               if (!actual) {
+                                       ZVAL_STR_COPY(EX_VAR(opline->result.var), Z_STR_P(RT_CONSTANT(opline, opline->op2)));
+                               } else {
+                                       actual++;
+                                       ZVAL_STRINGL(EX_VAR(opline->result.var),
+                                                       actual, Z_STRLEN_P(RT_CONSTANT(opline, opline->op2)) - (actual - Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))));
+                               }
+                               /* non-qualified constant - allow text substitution */
+                               zend_error(E_WARNING, "Use of undefined constant %s - assumed '%s' (this will throw an Error in a future version of PHP)",
+                                               Z_STRVAL_P(EX_VAR(opline->result.var)), Z_STRVAL_P(EX_VAR(opline->result.var)));
+                       } else {
+                               zend_throw_error(NULL, "Undefined constant '%s'", Z_STRVAL_P(RT_CONSTANT(opline, opline->op2)));
+                               ZVAL_UNDEF(EX_VAR(opline->result.var));
+                       }
+               }
+               return FAILURE;
+       }
+
+       if (!check_defined_only) {
+               ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value);
+               if (!(c->flags & (CONST_CS|CONST_CT_SUBST))) {
+                       const char *ns_sep;
+                       size_t shortname_offset;
+                       size_t shortname_len;
+                       zend_bool is_deprecated;
+
+                       if (flags & IS_CONSTANT_UNQUALIFIED) {
+                               const zval *access_key;
+
+                               if (!(flags & IS_CONSTANT_IN_NAMESPACE)) {
+                                       access_key = orig_key - 1;
+                               } else {
+                                       if (key < orig_key + 2) {
+                                               goto check_short_name;
+                                       } else {
+                                               access_key = orig_key + 2;
+                                       }
+                               }
+                               is_deprecated = !zend_string_equals(c->name, Z_STR_P(access_key));
+                       } else {
+check_short_name:
+                               ns_sep = zend_memrchr(ZSTR_VAL(c->name), '\\', ZSTR_LEN(c->name));
+                               ZEND_ASSERT(ns_sep);
+                               /* Namespaces are always case-insensitive. Only compare shortname. */
+                               shortname_offset = ns_sep - ZSTR_VAL(c->name) + 1;
+                               shortname_len = ZSTR_LEN(c->name) - shortname_offset;
+
+                               is_deprecated = memcmp(ZSTR_VAL(c->name) + shortname_offset, Z_STRVAL_P(orig_key - 1) + shortname_offset, shortname_len) != 0;
+                       }
+
+                       if (is_deprecated) {
+                               zend_error(E_DEPRECATED,
+                                       "Case-insensitive constants are deprecated. "
+                                       "The correct casing for this constant is \"%s\"",
+                                       ZSTR_VAL(c->name));
+                               return SUCCESS;
+                       }
+               }
+       }
+
+       CACHE_PTR(opline->extended_value, c);
+       return SUCCESS;
+}
+/* }}} */
+
+static zend_never_inline void ZEND_FASTCALL zend_quick_get_constant(
+               const zval *key, uint32_t flags OPLINE_DC EXECUTE_DATA_DC) /* {{{ */
+{
+       _zend_quick_get_constant(key, flags, 0 OPLINE_CC EXECUTE_DATA_CC);
+}
+
+static zend_never_inline int ZEND_FASTCALL zend_quick_check_constant(
+               const zval *key, uint32_t flags OPLINE_DC EXECUTE_DATA_DC) /* {{{ */
+{
+       return _zend_quick_get_constant(key, flags, 1 OPLINE_CC EXECUTE_DATA_CC);
+}
+
 #ifdef ZEND_VM_TRACE_HANDLERS
 # include "zend_vm_trace_handlers.h"
 #elif defined(ZEND_VM_TRACE_MAP)
index 3d0fdc01829ac2ee9f6e21b547ae858320a1ea3a..087dd3ac84be4710e60fa3206ad9fd35881407e4 100644 (file)
@@ -5045,47 +5045,16 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, UNUSED|CONST_FETCH, CONST, CACHE_SLOT)
 {
        USE_OPLINE
        zend_constant *c;
-       zend_bool is_deprecated;
 
        c = CACHED_PTR(opline->extended_value);
        if (EXPECTED(c != NULL) && EXPECTED(!IS_SPECIAL_CACHE_VAL(c))) {
-               /* pass */
-       } else if (UNEXPECTED((c = zend_quick_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num, &is_deprecated)) == NULL)) {
-               SAVE_OPLINE();
-
-               if ((opline->op1.num & IS_CONSTANT_UNQUALIFIED) != 0) {
-                       char *actual = (char *)zend_memrchr(Z_STRVAL_P(RT_CONSTANT(opline, opline->op2)), '\\', Z_STRLEN_P(RT_CONSTANT(opline, opline->op2)));
-                       if (!actual) {
-                               ZVAL_STR_COPY(EX_VAR(opline->result.var), Z_STR_P(RT_CONSTANT(opline, opline->op2)));
-                       } else {
-                               actual++;
-                               ZVAL_STRINGL(EX_VAR(opline->result.var),
-                                               actual, Z_STRLEN_P(RT_CONSTANT(opline, opline->op2)) - (actual - Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))));
-                       }
-                       /* non-qualified constant - allow text substitution */
-                       zend_error(E_WARNING, "Use of undefined constant %s - assumed '%s' (this will throw an Error in a future version of PHP)",
-                                       Z_STRVAL_P(EX_VAR(opline->result.var)), Z_STRVAL_P(EX_VAR(opline->result.var)));
-                       ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
-               } else {
-                       zend_throw_error(NULL, "Undefined constant '%s'", Z_STRVAL_P(RT_CONSTANT(opline, opline->op2)));
-                       ZVAL_UNDEF(EX_VAR(opline->result.var));
-                       HANDLE_EXCEPTION();
-               }
-       } else if (is_deprecated) {
-               SAVE_OPLINE();
-               zend_error(E_DEPRECATED,
-                       "Case-insensitive constants are deprecated. "
-                       "The correct casing for this constant is \"%s\"",
-                       ZSTR_VAL(c->name));
                ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value);
-               ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
-       } else {
-               CACHE_PTR(opline->extended_value, c);
+               ZEND_VM_NEXT_OPCODE();
        }
 
-       ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value);
-
-       ZEND_VM_NEXT_OPCODE();
+       SAVE_OPLINE();
+       zend_quick_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num OPLINE_CC EXECUTE_DATA_CC);
+       ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
 ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CONST, CACHE_SLOT)
@@ -7620,11 +7589,10 @@ ZEND_VM_HANDLER(122, ZEND_DEFINED, CONST, ANY, CACHE_SLOT)
                                break;
                        }
                }
-               if ((c = zend_quick_get_constant(RT_CONSTANT(opline, opline->op1), 0, NULL)) == NULL) {
+               if (zend_quick_check_constant(RT_CONSTANT(opline, opline->op1), ZEND_GET_CONSTANT_NO_DEPRECATION_CHECK OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
                        CACHE_PTR(opline->extended_value, ENCODE_SPECIAL_CACHE_NUM(zend_hash_num_elements(EG(zend_constants))));
                        result = 0;
                } else {
-                       CACHE_PTR(opline->extended_value, c);
                        result = 1;
                }
        } while (0);
index c5598d6da7d89dc0faa1c6900e19def209ed1271..a177bcea0fbdf0d7d9bbc5ef2f99bd6950f76a21 100644 (file)
@@ -3883,11 +3883,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DEFINED_SPEC_CONST_HANDLER(ZEN
                                break;
                        }
                }
-               if ((c = zend_quick_get_constant(RT_CONSTANT(opline, opline->op1), 0, NULL)) == NULL) {
+               if (zend_quick_check_constant(RT_CONSTANT(opline, opline->op1), ZEND_GET_CONSTANT_NO_DEPRECATION_CHECK OPLINE_CC EXECUTE_DATA_CC) != SUCCESS) {
                        CACHE_PTR(opline->extended_value, ENCODE_SPECIAL_CACHE_NUM(zend_hash_num_elements(EG(zend_constants))));
                        result = 0;
                } else {
-                       CACHE_PTR(opline->extended_value, c);
                        result = 1;
                }
        } while (0);
@@ -31965,47 +31964,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_UNUSED_CON
 {
        USE_OPLINE
        zend_constant *c;
-       zend_bool is_deprecated;
 
        c = CACHED_PTR(opline->extended_value);
        if (EXPECTED(c != NULL) && EXPECTED(!IS_SPECIAL_CACHE_VAL(c))) {
-               /* pass */
-       } else if (UNEXPECTED((c = zend_quick_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num, &is_deprecated)) == NULL)) {
-               SAVE_OPLINE();
-
-               if ((opline->op1.num & IS_CONSTANT_UNQUALIFIED) != 0) {
-                       char *actual = (char *)zend_memrchr(Z_STRVAL_P(RT_CONSTANT(opline, opline->op2)), '\\', Z_STRLEN_P(RT_CONSTANT(opline, opline->op2)));
-                       if (!actual) {
-                               ZVAL_STR_COPY(EX_VAR(opline->result.var), Z_STR_P(RT_CONSTANT(opline, opline->op2)));
-                       } else {
-                               actual++;
-                               ZVAL_STRINGL(EX_VAR(opline->result.var),
-                                               actual, Z_STRLEN_P(RT_CONSTANT(opline, opline->op2)) - (actual - Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))));
-                       }
-                       /* non-qualified constant - allow text substitution */
-                       zend_error(E_WARNING, "Use of undefined constant %s - assumed '%s' (this will throw an Error in a future version of PHP)",
-                                       Z_STRVAL_P(EX_VAR(opline->result.var)), Z_STRVAL_P(EX_VAR(opline->result.var)));
-                       ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
-               } else {
-                       zend_throw_error(NULL, "Undefined constant '%s'", Z_STRVAL_P(RT_CONSTANT(opline, opline->op2)));
-                       ZVAL_UNDEF(EX_VAR(opline->result.var));
-                       HANDLE_EXCEPTION();
-               }
-       } else if (is_deprecated) {
-               SAVE_OPLINE();
-               zend_error(E_DEPRECATED,
-                       "Case-insensitive constants are deprecated. "
-                       "The correct casing for this constant is \"%s\"",
-                       ZSTR_VAL(c->name));
                ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value);
-               ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
-       } else {
-               CACHE_PTR(opline->extended_value, c);
+               ZEND_VM_NEXT_OPCODE();
        }
 
-       ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value);
-
-       ZEND_VM_NEXT_OPCODE();
+       SAVE_OPLINE();
+       zend_quick_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num OPLINE_CC EXECUTE_DATA_CC);
+       ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
 static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)