]> granicus.if.org Git - php/commitdiff
Optimized access to global constants using values with pre-calculated hash_values...
authorDmitry Stogov <dmitry@php.net>
Thu, 22 Apr 2010 15:03:17 +0000 (15:03 +0000)
committerDmitry Stogov <dmitry@php.net>
Thu, 22 Apr 2010 15:03:17 +0000 (15:03 +0000)
NEWS
Zend/micro_bench.php
Zend/zend.h
Zend/zend_compile.c
Zend/zend_constants.c
Zend/zend_constants.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/NEWS b/NEWS
index cb4f239c3e4e89bbbf5e564dfcfa98b4052dfa83..f829f3110d3077b02c9c257b467ff35d21cd99fa 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,8 @@
   . ZEND_FETCH_DIM_? may fetch array and dimension operans in a different order
   . ZEND_RETURN is splitted into two new instructions ZEND_RETURN and 
     ZEND_RETURN_BY_REF
+  . optimized access to global constants using values with pre-calculated
+    hash_values from litersls table
 - Added concept of interned strings. All strings constants known at compile
   time are allocated in a single copy and never changed. (Dmitry)
 - Added an optimization which saves memory and emalloc/efree calls for empty
index e07ee88ce5784566a8a5b90dbf65a8536a1c6063..0d705e942b1fa637d7065629f12d85ff2f300a4e 100644 (file)
@@ -166,6 +166,14 @@ function create_object($n) {
        }
 }
 
+define('TEST', null);
+
+function read_const($n) {
+       for ($i = 0; $i < $n; ++$i) {
+               $x = TEST;
+       }
+}
+
 /*****/
 
 function empty_loop($n) {
@@ -272,4 +280,6 @@ $x->read_const(N);
 $t = end_test($t, '$x = Foo::TEST', $overhead);
 create_object(N);
 $t = end_test($t, 'new Foo()', $overhead);
+read_const(N);
+$t = end_test($t, '$x = TEST', $overhead);
 total($t0, "Total");
index 8aafd2cf81c847dfc2e40df8d67c6af066bba6e3..7efa9f4825d886e2ba59e26eb6b46625cde59224 100644 (file)
@@ -525,11 +525,12 @@ typedef int (*zend_write_func_t)(const char *str, uint str_length);
 #define IS_CONSTANT_ARRAY      9
 
 /* Ugly hack to support constants as static array indices */
-#define IS_CONSTANT_TYPE_MASK  0x0f
-#define IS_CONSTANT_UNQUALIFIED        0x10
-#define IS_CONSTANT_INDEX              0x80
-#define IS_LEXICAL_VAR                 0x20
-#define IS_LEXICAL_REF                 0x40
+#define IS_CONSTANT_TYPE_MASK          0x00f
+#define IS_CONSTANT_UNQUALIFIED                0x010
+#define IS_CONSTANT_INDEX                      0x080
+#define IS_LEXICAL_VAR                         0x020
+#define IS_LEXICAL_REF                         0x040
+#define IS_CONSTANT_IN_NAMESPACE       0x100
 
 /* overloaded elements data types */
 #define OE_IS_ARRAY            (1<<0)
index c523a3dfa0693ca91b80711a7a6cc8bc2c24f123..9909643795e27674d23b04f9e3d2ff98d63d8023 100644 (file)
@@ -420,6 +420,76 @@ int zend_add_class_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_D
 }
 /* }}} */
 
+int zend_add_const_name_literal(zend_op_array *op_array, const zval *zv, int unqualified TSRMLS_DC) /* {{{ */
+{
+       int ret, tmp_literal;
+       char *name, *tmp_name, *ns_separator;
+       int name_len, ns_len;
+       zval c;
+
+       if (op_array->last_literal > 0 && 
+           &op_array->literals[op_array->last_literal - 1].constant == zv) {
+               /* we already have function name as last literal (do nothing) */
+               ret = op_array->last_literal - 1;
+       } else {
+               ret = zend_add_literal(op_array, zv);
+       }
+
+       /* skip leading '\\' */ 
+       if (Z_STRVAL_P(zv)[0] == '\\') {
+               name_len = Z_STRLEN_P(zv) - 1;
+               name = Z_STRVAL_P(zv) + 1;
+       } else {
+               name_len = Z_STRLEN_P(zv);
+               name = Z_STRVAL_P(zv);
+       }
+       ns_separator = zend_memrchr(name, '\\', name_len);
+       if (ns_separator) {
+               ns_len = ns_separator - name;
+       } else {
+               ns_len = 0;
+       }
+
+       if (ns_len) {
+               /* lowercased namespace name & original constant name */
+               tmp_name = estrndup(name, name_len);
+               zend_str_tolower(tmp_name, ns_len);
+               ZVAL_STRINGL(&c, tmp_name, name_len, 0);
+               tmp_literal = zend_add_literal(CG(active_op_array), &c);
+               CALCULATE_LITERAL_HASH(tmp_literal);
+
+               /* lowercased namespace name & lowercased constant name */
+               tmp_name = zend_str_tolower_dup(name, name_len);
+               ZVAL_STRINGL(&c, tmp_name, name_len, 0);
+               tmp_literal = zend_add_literal(CG(active_op_array), &c);
+               CALCULATE_LITERAL_HASH(tmp_literal);
+       }
+
+       if (ns_len) {
+               if (!unqualified) {
+                       return ret;
+               }
+               ns_len++;
+               name += ns_len;
+               name_len -= ns_len;
+       }
+
+       /* original constant name */
+       tmp_name = estrndup(name, name_len);
+       ZVAL_STRINGL(&c, tmp_name, name_len, 0);
+       tmp_literal = zend_add_literal(CG(active_op_array), &c);
+       CALCULATE_LITERAL_HASH(tmp_literal);
+
+       /* lowercased constant name */
+       tmp_name = zend_str_tolower_dup(name, name_len);
+       ZVAL_STRINGL(&c, tmp_name, name_len, 0);
+       tmp_literal = zend_add_literal(CG(active_op_array), &c);
+       CALCULATE_LITERAL_HASH(tmp_literal);
+
+       return ret;
+}
+/* }}} */
+
 #define LITERAL_STRINGL(op, str, len, copy) do { \
                zval _c; \
                ZVAL_STRINGL(&_c, str, len, copy); \
@@ -4149,14 +4219,20 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con
                        opline->result.var = get_temporary_variable(CG(active_op_array));
                        GET_NODE(result, opline->result);
                        SET_UNUSED(opline->op1);
-                       if(compound) {
+                       opline->op2_type = IS_CONST;
+                       if (compound) {
                                /* the name is unambiguous */
                                opline->extended_value = 0;
-                       } else {
+                               opline->op2.constant = zend_add_const_name_literal(CG(active_op_array), &constant_name->u.constant, 0 TSRMLS_CC);
+                       } else {                                
                                opline->extended_value = IS_CONSTANT_UNQUALIFIED;
+                               if (CG(current_namespace)) {
+                                       opline->extended_value |= IS_CONSTANT_IN_NAMESPACE;
+                                       opline->op2.constant = zend_add_const_name_literal(CG(active_op_array), &constant_name->u.constant, 1 TSRMLS_CC);
+                               } else {
+                                       opline->op2.constant = zend_add_const_name_literal(CG(active_op_array), &constant_name->u.constant, 0 TSRMLS_CC);
+                               }
                        }
-                       SET_NODE(opline->op2, constant_name);
-                       CALCULATE_LITERAL_HASH(opline->op2.constant);
                        break;
        }
 }
index 1743ffd2a89a6992b0c3f31321afcf9e2bfbfde6..f58184269807b4e9bc6694f87fcdeef8dcbd1409 100644 (file)
@@ -222,6 +222,31 @@ ZEND_API void zend_register_string_constant(const char *name, uint name_len, cha
        zend_register_stringl_constant(name, name_len, strval, strlen(strval), flags, module_number TSRMLS_CC);
 }
 
+static int zend_get_halt_offset_constant(const char *name, uint name_len, zend_constant **c TSRMLS_DC)
+{
+       int ret;
+       static char haltoff[] = "__COMPILER_HALT_OFFSET__";
+
+       if (!EG(in_execution)) {
+               return 0;
+       } else if (name_len == sizeof("__COMPILER_HALT_OFFSET__")-1 &&
+                 !memcmp(name, "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1)) {
+               char *cfilename, *haltname;
+               int len, clen;
+
+               cfilename = zend_get_executed_filename(TSRMLS_C);
+               clen = strlen(cfilename);
+               /* check for __COMPILER_HALT_OFFSET__ */
+               zend_mangle_property_name(&haltname, &len, haltoff,
+                       sizeof("__COMPILER_HALT_OFFSET__") - 1, cfilename, clen, 0);
+               ret = zend_hash_find(EG(zend_constants), haltname, len+1, (void **) c);
+               efree(haltname);
+               return (ret == SUCCESS);
+       } else {
+               return 0;
+       }
+}
+
 
 ZEND_API int zend_get_constant(const char *name, uint name_len, zval *result TSRMLS_DC)
 {
@@ -237,29 +262,7 @@ ZEND_API int zend_get_constant(const char *name, uint name_len, zval *result TSR
                                retval=0;
                        }
                } else {
-                       static char haltoff[] = "__COMPILER_HALT_OFFSET__";
-
-                       if (!EG(in_execution)) {
-                               retval = 0;
-                       } else if (name_len == sizeof("__COMPILER_HALT_OFFSET__")-1 &&
-                                 !memcmp(name, "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1)) {
-                               char *cfilename, *haltname;
-                               int len, clen;
-
-                               cfilename = zend_get_executed_filename(TSRMLS_C);
-                               clen = strlen(cfilename);
-                               /* check for __COMPILER_HALT_OFFSET__ */
-                               zend_mangle_property_name(&haltname, &len, haltoff,
-                                       sizeof("__COMPILER_HALT_OFFSET__") - 1, cfilename, clen, 0);
-                               if (zend_hash_find(EG(zend_constants), haltname, len+1, (void **) &c) == SUCCESS) {
-                                       retval = 1;
-                               } else {
-                                       retval=0;
-                               }
-                               pefree(haltname, 0);
-                       } else {
-                               retval=0;
-                       }
+                       retval = zend_get_halt_offset_constant(name, name_len, &c TSRMLS_CC);
                }
                efree(lookup_name);
        }
@@ -410,6 +413,41 @@ finish:
        return zend_get_constant(name, name_len, result TSRMLS_CC);
 }
 
+int zend_quick_get_constant(const zend_literal *key, zval *result, ulong flags TSRMLS_DC)
+{
+       zend_constant *c;
+
+       if (zend_hash_quick_find(EG(zend_constants), Z_STRVAL(key->constant), Z_STRLEN(key->constant) + 1, key->hash_value, (void **) &c) == FAILURE) {
+               key++;
+               if (zend_hash_quick_find(EG(zend_constants), Z_STRVAL(key->constant), Z_STRLEN(key->constant) + 1, key->hash_value, (void **) &c) == FAILURE ||
+                   (c->flags & CONST_CS) != 0) {
+                       if ((flags & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) {
+                               key++;
+                               if (zend_hash_quick_find(EG(zend_constants), Z_STRVAL(key->constant), Z_STRLEN(key->constant) + 1, key->hash_value, (void **) &c) == FAILURE) {
+                                   key++;
+                                       if (zend_hash_quick_find(EG(zend_constants), Z_STRVAL(key->constant), Z_STRLEN(key->constant) + 1, key->hash_value, (void **) &c) == FAILURE ||
+                                           (c->flags & CONST_CS) != 0) {
+
+                                               key--;
+                                               if (!zend_get_halt_offset_constant(Z_STRVAL(key->constant), Z_STRLEN(key->constant), &c TSRMLS_CC)) {
+                                                       return 0;
+                                               }
+                                       }
+                               }
+                       } else {
+                               key--;
+                               if (!zend_get_halt_offset_constant(Z_STRVAL(key->constant), Z_STRLEN(key->constant), &c TSRMLS_CC)) {
+                                       return 0;
+                               }
+                       }
+               }
+       }
+
+       INIT_PZVAL_COPY(result, &c->value);
+       zval_copy_ctor(result);
+       return 1;
+}
+
 ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC)
 {
        char *lowercase_name = NULL;
index 75fb67e2eb9f5c265a7f3da5d4e258305667ee0c..e8fb3f2116b170144b4a90a0c1a91632e34fcd59 100644 (file)
@@ -69,6 +69,7 @@ ZEND_API void zend_register_stringl_constant(const char *name, uint name_len, ch
 ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC);
 void zend_copy_constants(HashTable *target, HashTable *sourc);
 void copy_zend_constant(zend_constant *c);
+int zend_quick_get_constant(const zend_literal *key, zval *result, ulong flags TSRMLS_DC);
 END_EXTERN_C()
 
 #define ZEND_CONSTANT_DTOR (void (*)(void *)) free_zend_constant
index b9e718fced5f4d857d587a658ec448ddd4249f57..953f58a74c57080d86a2f3932634ef4df6c62b81 100644 (file)
@@ -3329,7 +3329,7 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|CONST|UNUSED, CONST)
        SAVE_OPLINE();
        if (OP1_TYPE == IS_UNUSED) {
                /* namespaced constant */
-               if (!zend_get_constant_ex(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), &EX_T(opline->result.var).tmp_var, NULL, opline->extended_value TSRMLS_CC)) {
+               if (!zend_quick_get_constant(opline->op2.literal + 1, &EX_T(opline->result.var).tmp_var, opline->extended_value TSRMLS_CC)) {
                        if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {
                                char *actual = (char *)zend_memrchr(Z_STRVAL_P(opline->op2.zv), '\\', Z_STRLEN_P(opline->op2.zv));
                                if(!actual) {
index e6e4f90cdee8703cae4ba49bc739eccb89db184c..e48b807eea01b0ccfbe976f784a95fbd1c11afd7 100644 (file)
@@ -2981,7 +2981,7 @@ static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCO
        SAVE_OPLINE();
        if (IS_CONST == IS_UNUSED) {
                /* namespaced constant */
-               if (!zend_get_constant_ex(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), &EX_T(opline->result.var).tmp_var, NULL, opline->extended_value TSRMLS_CC)) {
+               if (!zend_quick_get_constant(opline->op2.literal + 1, &EX_T(opline->result.var).tmp_var, opline->extended_value TSRMLS_CC)) {
                        if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {
                                char *actual = (char *)zend_memrchr(Z_STRVAL_P(opline->op2.zv), '\\', Z_STRLEN_P(opline->op2.zv));
                                if(!actual) {
@@ -11495,7 +11495,7 @@ static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE
        SAVE_OPLINE();
        if (IS_VAR == IS_UNUSED) {
                /* namespaced constant */
-               if (!zend_get_constant_ex(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), &EX_T(opline->result.var).tmp_var, NULL, opline->extended_value TSRMLS_CC)) {
+               if (!zend_quick_get_constant(opline->op2.literal + 1, &EX_T(opline->result.var).tmp_var, opline->extended_value TSRMLS_CC)) {
                        if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {
                                char *actual = (char *)zend_memrchr(Z_STRVAL_P(opline->op2.zv), '\\', Z_STRLEN_P(opline->op2.zv));
                                if(!actual) {
@@ -19381,7 +19381,7 @@ static int ZEND_FASTCALL  ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPC
        SAVE_OPLINE();
        if (IS_UNUSED == IS_UNUSED) {
                /* namespaced constant */
-               if (!zend_get_constant_ex(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), &EX_T(opline->result.var).tmp_var, NULL, opline->extended_value TSRMLS_CC)) {
+               if (!zend_quick_get_constant(opline->op2.literal + 1, &EX_T(opline->result.var).tmp_var, opline->extended_value TSRMLS_CC)) {
                        if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {
                                char *actual = (char *)zend_memrchr(Z_STRVAL_P(opline->op2.zv), '\\', Z_STRLEN_P(opline->op2.zv));
                                if(!actual) {