]> granicus.if.org Git - php/commitdiff
Use runtime-cache to avoid hash lookups in BIND_GLOBAL instruction
authorDmitry Stogov <dmitry@zend.com>
Tue, 16 Sep 2014 20:52:45 +0000 (00:52 +0400)
committerDmitry Stogov <dmitry@zend.com>
Tue, 16 Sep 2014 20:52:45 +0000 (00:52 +0400)
Zend/zend_compile.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/opcache/Optimizer/compact_literals.c

index 0f91a8115544520c1d7c6f6834ef073d49c22644..df44138d4fb6b1622d84cd18fbbb537f9db851f8 100644 (file)
@@ -4586,7 +4586,8 @@ void zend_compile_global_var(zend_ast *ast TSRMLS_DC) /* {{{ */
        }
 
        if (zend_try_compile_cv(&result, var_ast TSRMLS_CC) == SUCCESS) {
-               zend_emit_op(NULL, ZEND_BIND_GLOBAL, &result, &name_node TSRMLS_CC);
+               zend_op *opline = zend_emit_op(NULL, ZEND_BIND_GLOBAL, &result, &name_node TSRMLS_CC);
+               zend_alloc_cache_slot(opline->op2.constant TSRMLS_CC);
        } else {
                zend_emit_op(&result, ZEND_FETCH_W, &name_node, NULL TSRMLS_CC);
 
index c591b9b4cca0b5482d613a225e046e45c257fc2d..ac015aea5260ff06210dc04d171bf0cacbc4aab7 100644 (file)
@@ -5891,19 +5891,46 @@ ZEND_VM_HANDLER(168, ZEND_BIND_GLOBAL, CV, CONST)
        zval *varname;
        zval *value;
        zval *variable_ptr;
-       zend_string *name;
+       Bucket *p;
+       uint32_t idx;
 
        SAVE_OPLINE();
        varname = GET_OP2_ZVAL_PTR(BP_VAR_R);
-       name = Z_STR_P(varname);
-       value = zend_hash_find(&EG(symbol_table).ht, name);
-       if (value == NULL) {
-               value = zend_hash_add_new(&EG(symbol_table).ht, name, &EG(uninitialized_zval));
+       idx = (uint32_t)(uintptr_t)CACHED_PTR(Z_CACHE_SLOT_P(varname));
+       /* index 0 can't be cached (NULL is a mark of uninitialized cache slot) */
+       p = EG(symbol_table).ht.arData + idx; 
+       if (EXPECTED(idx > 0) &&
+           EXPECTED(idx < EG(symbol_table).ht.nNumUsed) &&
+           EXPECTED(Z_TYPE(p->val) != IS_UNDEF) &&
+        (EXPECTED(p->key == Z_STR_P(varname)) ||
+         (EXPECTED(p->h == Z_STR_P(varname)->h) &&
+          EXPECTED(p->key != NULL) &&
+          EXPECTED(p->key->len == Z_STRLEN_P(varname)) &&
+          EXPECTED(memcmp(p->key->val, Z_STRVAL_P(varname), Z_STRLEN_P(varname)) == 0)))) {
+               value = &EG(symbol_table).ht.arData[idx].val;
                /* GLOBAL variable may be an INDIRECT pointer to CV */
-       } else if (Z_TYPE_P(value) == IS_INDIRECT) {
-               value = Z_INDIRECT_P(value);
-               if (Z_TYPE_P(value) == IS_UNDEF) {
-                       ZVAL_NULL(value);
+               if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+                       value = Z_INDIRECT_P(value);
+                       if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+                               ZVAL_NULL(value);
+                       }
+               }
+       } else {
+               value = zend_hash_find(&EG(symbol_table).ht, Z_STR_P(varname));
+               if (UNEXPECTED(value == NULL)) {
+                       value = zend_hash_add_new(&EG(symbol_table).ht, Z_STR_P(varname), &EG(uninitialized_zval));
+                       idx = ((char*)value - (char*)EG(symbol_table).ht.arData) / sizeof(Bucket);
+                       CACHE_PTR(Z_CACHE_SLOT_P(varname), (void*)(uintptr_t)idx);
+               } else {
+                       idx = ((char*)value - (char*)EG(symbol_table).ht.arData) / sizeof(Bucket);
+                       CACHE_PTR(Z_CACHE_SLOT_P(varname), (void*)(uintptr_t)idx);
+                       /* GLOBAL variable may be an INDIRECT pointer to CV */
+                       if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+                               value = Z_INDIRECT_P(value);
+                               if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+                                       ZVAL_NULL(value);
+                               }
+                       }
                }
        }
 
index fb2456070ef55940c5d9475cc0c689f2c094ebc3..d2afba627251ae70dba9aff6507ec9c236d5ace2 100644 (file)
@@ -36402,19 +36402,46 @@ static int ZEND_FASTCALL  ZEND_BIND_GLOBAL_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HAN
        zval *varname;
        zval *value;
        zval *variable_ptr;
-       zend_string *name;
+       Bucket *p;
+       uint32_t idx;
 
        SAVE_OPLINE();
        varname = opline->op2.zv;
-       name = Z_STR_P(varname);
-       value = zend_hash_find(&EG(symbol_table).ht, name);
-       if (value == NULL) {
-               value = zend_hash_add_new(&EG(symbol_table).ht, name, &EG(uninitialized_zval));
+       idx = (uint32_t)(uintptr_t)CACHED_PTR(Z_CACHE_SLOT_P(varname));
+       /* index 0 can't be cached (NULL is a mark of uninitialized cache slot) */
+       p = EG(symbol_table).ht.arData + idx;
+       if (EXPECTED(idx > 0) &&
+           EXPECTED(idx < EG(symbol_table).ht.nNumUsed) &&
+           EXPECTED(Z_TYPE(p->val) != IS_UNDEF) &&
+        (EXPECTED(p->key == Z_STR_P(varname)) ||
+         (EXPECTED(p->h == Z_STR_P(varname)->h) &&
+          EXPECTED(p->key != NULL) &&
+          EXPECTED(p->key->len == Z_STRLEN_P(varname)) &&
+          EXPECTED(memcmp(p->key->val, Z_STRVAL_P(varname), Z_STRLEN_P(varname)) == 0)))) {
+               value = &EG(symbol_table).ht.arData[idx].val;
                /* GLOBAL variable may be an INDIRECT pointer to CV */
-       } else if (Z_TYPE_P(value) == IS_INDIRECT) {
-               value = Z_INDIRECT_P(value);
-               if (Z_TYPE_P(value) == IS_UNDEF) {
-                       ZVAL_NULL(value);
+               if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+                       value = Z_INDIRECT_P(value);
+                       if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+                               ZVAL_NULL(value);
+                       }
+               }
+       } else {
+               value = zend_hash_find(&EG(symbol_table).ht, Z_STR_P(varname));
+               if (UNEXPECTED(value == NULL)) {
+                       value = zend_hash_add_new(&EG(symbol_table).ht, Z_STR_P(varname), &EG(uninitialized_zval));
+                       idx = ((char*)value - (char*)EG(symbol_table).ht.arData) / sizeof(Bucket);
+                       CACHE_PTR(Z_CACHE_SLOT_P(varname), (void*)(uintptr_t)idx);
+               } else {
+                       idx = ((char*)value - (char*)EG(symbol_table).ht.arData) / sizeof(Bucket);
+                       CACHE_PTR(Z_CACHE_SLOT_P(varname), (void*)(uintptr_t)idx);
+                       /* GLOBAL variable may be an INDIRECT pointer to CV */
+                       if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+                               value = Z_INDIRECT_P(value);
+                               if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+                                       ZVAL_NULL(value);
+                               }
+                       }
                }
        }
 
index 28e7a11314ea0d2feedf424fe385e3e9dcdaa831..091437e11908f9fbd7581ca66fdeaab3bd6a79dd 100644 (file)
@@ -40,6 +40,7 @@
 #define LITERAL_STATIC_PROPERTY              0x0700
 #define LITERAL_METHOD                       0x0800
 #define LITERAL_PROPERTY                     0x0900
+#define LITERAL_GLOBAL                       0x0A00
 
 #define LITERAL_EX_CLASS                     0x4000
 #define LITERAL_EX_OBJ                       0x2000
@@ -278,6 +279,9 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
                                                }
                                        }
                                        break;
+                               case ZEND_BIND_GLOBAL:
+                                       LITERAL_INFO(opline->op2.constant, LITERAL_GLOBAL, 0, 1, 1);
+                                       break;
                                default:
                                        if (ZEND_OP1_TYPE(opline) == IS_CONST) {
                                                LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1);