From: Dmitry Stogov Date: Tue, 16 Sep 2014 20:52:45 +0000 (+0400) Subject: Use runtime-cache to avoid hash lookups in BIND_GLOBAL instruction X-Git-Tag: POST_NATIVE_TLS_MERGE^2~248 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=551ee4165b62ff6dbd32ce0dcc213d66fc8ae083;p=php Use runtime-cache to avoid hash lookups in BIND_GLOBAL instruction --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0f91a81155..df44138d4f 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -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); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index c591b9b4cc..ac015aea52 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -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); + } + } } } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index fb2456070e..d2afba6272 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -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); + } + } } } diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c index 28e7a11314..091437e119 100644 --- a/ext/opcache/Optimizer/compact_literals.c +++ b/ext/opcache/Optimizer/compact_literals.c @@ -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);