]> granicus.if.org Git - php/commitdiff
Avoid hash lookups in BIND_STATIC and BIND_LEXICAL opcode handlers.
authorDmitry Stogov <dmitry@zend.com>
Mon, 20 Aug 2018 13:10:09 +0000 (16:10 +0300)
committerDmitry Stogov <dmitry@zend.com>
Mon, 20 Aug 2018 13:10:09 +0000 (16:10 +0300)
Encode static variable offset into opline->extended_value.

Zend/zend_closures.c
Zend/zend_closures.h
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_language_parser.y
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/opcache/Optimizer/zend_dfg.c
ext/opcache/Optimizer/zend_inference.c
ext/opcache/Optimizer/zend_ssa.c

index 629abd4399887f2329aec740b362cfa2ce409526..494c8892218fb128ec9522725aea3e6ea7c0c924 100644 (file)
@@ -729,6 +729,16 @@ void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var) /
 }
 /* }}} */
 
+void zend_closure_bind_var_ex(zval *closure_zv, uint32_t offset, zval *val) /* {{{ */
+{
+       zend_closure *closure = (zend_closure *) Z_OBJ_P(closure_zv);
+       HashTable *static_variables = closure->func.op_array.static_variables;
+       zval *var = (zval*)((char*)static_variables->arData + offset);
+       zval_ptr_dtor(var);
+       ZVAL_COPY_VALUE(var, val);
+}
+/* }}} */
+
 /*
  * Local variables:
  * tab-width: 4
index b55174da086bc72748d74a87a5415bdea6419939..0b50ef2622146ad084c332190693aa969b6bdf03 100644 (file)
@@ -28,6 +28,7 @@ BEGIN_EXTERN_C()
 
 void zend_register_closure_ce(void);
 void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var);
+void zend_closure_bind_var_ex(zval *closure_zv, uint32_t offset, zval *val);
 
 extern ZEND_API zend_class_entry *zend_ce_closure;
 
index 7c63771fed9cdff209914847b010b5eee9874be2..8a5d15bfa30cb028635b2765f9f2bbd2d1c82808 100644 (file)
@@ -4247,7 +4247,7 @@ void zend_compile_global_var(zend_ast *ast) /* {{{ */
 }
 /* }}} */
 
-static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, zend_bool by_ref) /* {{{ */
+static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, uint32_t by_ref) /* {{{ */
 {
        znode var_node;
        zend_op *opline;
@@ -4274,7 +4274,7 @@ static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, zend_
                }
                CG(active_op_array)->static_variables = zend_array_dup(CG(active_op_array)->static_variables);
        }
-       zend_hash_update(CG(active_op_array)->static_variables, var_name, value);
+       value = zend_hash_update(CG(active_op_array)->static_variables, var_name, value);
 
        if (zend_string_equals_literal(var_name, "this")) {
                zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as static variable");
@@ -4283,7 +4283,7 @@ static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, zend_
        opline = zend_emit_op(NULL, ZEND_BIND_STATIC, NULL, &var_node);
        opline->op1_type = IS_CV;
        opline->op1.var = lookup_cv(CG(active_op_array), var_name);
-       opline->extended_value = by_ref;
+       opline->extended_value = (uint32_t)((char*)value - (char*)CG(active_op_array)->static_variables->arData) | by_ref;
 }
 /* }}} */
 
@@ -4299,7 +4299,7 @@ void zend_compile_static_var(zend_ast *ast) /* {{{ */
                ZVAL_NULL(&value_zv);
        }
 
-       zend_compile_static_var_common(var_ast, &value_zv, 1);
+       zend_compile_static_var_common(var_ast, &value_zv, ZEND_BIND_REF);
 }
 /* }}} */
 
@@ -5672,16 +5672,32 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */
 }
 /* }}} */
 
-static void zend_compile_closure_binding(znode *closure, zend_ast *uses_ast) /* {{{ */
+static void zend_compile_closure_binding(znode *closure, zend_op_array *op_array, zend_ast *uses_ast) /* {{{ */
 {
        zend_ast_list *list = zend_ast_get_list(uses_ast);
        uint32_t i;
 
+       if (!list->children) {
+               return;
+       }
+
+       if (!op_array->static_variables) {
+               op_array->static_variables = zend_new_array(8);
+       }
+
+       if (GC_REFCOUNT(op_array->static_variables) > 1) {
+               if (!(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
+                       GC_DELREF(op_array->static_variables);
+               }
+               op_array->static_variables = zend_array_dup(op_array->static_variables);
+       }
+
        for (i = 0; i < list->children; ++i) {
                zend_ast *var_name_ast = list->child[i];
                zend_string *var_name = zval_make_interned_string(zend_ast_get_zval(var_name_ast));
-               zend_bool by_ref = var_name_ast->attr;
+               uint32_t by_ref = var_name_ast->attr;
                zend_op *opline;
+               zval *value;
 
                if (zend_string_equals_literal(var_name, "this")) {
                        zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as lexical variable");
@@ -5691,10 +5707,16 @@ static void zend_compile_closure_binding(znode *closure, zend_ast *uses_ast) /*
                        zend_error_noreturn(E_COMPILE_ERROR, "Cannot use auto-global as lexical variable");
                }
 
+               value = zend_hash_add(op_array->static_variables, var_name, &EG(uninitialized_zval));
+               if (!value) {
+                       zend_error_noreturn(E_COMPILE_ERROR,
+                               "Cannot use variable $%s twice", ZSTR_VAL(var_name));
+               }
+
                opline = zend_emit_op(NULL, ZEND_BIND_LEXICAL, closure, NULL);
                opline->op2_type = IS_CV;
                opline->op2.var = lookup_cv(CG(active_op_array), var_name);
-               opline->extended_value = by_ref;
+               opline->extended_value = (uint32_t)((char*)value - (char*)op_array->static_variables->arData) | by_ref;
        }
 }
 /* }}} */
@@ -5708,16 +5730,10 @@ void zend_compile_closure_uses(zend_ast *ast) /* {{{ */
        for (i = 0; i < list->children; ++i) {
                zend_ast *var_ast = list->child[i];
                zend_string *var_name = zend_ast_get_str(var_ast);
-               zend_bool by_ref = var_ast->attr;
+               uint32_t by_ref = var_ast->attr;
                zval zv;
                ZVAL_NULL(&zv);
 
-               if (op_array->static_variables
-                               && zend_hash_exists(op_array->static_variables, var_name)) {
-                       zend_error_noreturn(E_COMPILE_ERROR,
-                               "Cannot use variable $%s twice", ZSTR_VAL(var_name));
-               }
-
                {
                        int i;
                        for (i = 0; i < op_array->last_var; i++) {
@@ -5996,7 +6012,7 @@ void zend_compile_func_decl(znode *result, zend_ast *ast) /* {{{ */
        } else {
                zend_begin_func_decl(result, op_array, decl);
                if (uses_ast) {
-                       zend_compile_closure_binding(result, uses_ast);
+                       zend_compile_closure_binding(result, op_array, uses_ast);
                }
        }
 
index e1bb9eb376341926acb46f2c637d5c6fadfdfb26..805369edfaab86aafdbf6e0b4233f22f0ed201c5 100644 (file)
@@ -970,6 +970,8 @@ static zend_always_inline int zend_check_arg_send_type(const zend_function *zf,
 #define ZEND_RETURN_VAL 0
 #define ZEND_RETURN_REF 1
 
+#define ZEND_BIND_VAL 0
+#define ZEND_BIND_REF 1
 
 #define ZEND_RETURNS_FUNCTION (1<<0)
 #define ZEND_RETURNS_VALUE    (1<<1)
index e984d5254e399714b937fa0f759903d9b7bad263..c6060dee32047669f5eeb06c2a23979319ff1d11 100644 (file)
@@ -1021,7 +1021,7 @@ lexical_var_list:
 
 lexical_var:
                T_VARIABLE              { $$ = $1; }
-       |       '&' T_VARIABLE  { $$ = $2; $$->attr = 1; }
+       |       '&' T_VARIABLE  { $$ = $2; $$->attr = ZEND_BIND_REF; }
 ;
 
 function_call:
index 14dc9e676361286e179b20e3f78eb72ec7b27732..82372fdb917579e6e5717026beb12d694bc87767 100644 (file)
@@ -7827,10 +7827,9 @@ ZEND_VM_HANDLER(182, ZEND_BIND_LEXICAL, TMP, CV, REF)
        USE_OPLINE
        zend_free_op free_op1, free_op2;
        zval *closure, *var;
-       zend_string *var_name;
 
        closure = GET_OP1_ZVAL_PTR(BP_VAR_R);
-       if (opline->extended_value) {
+       if (opline->extended_value & ZEND_BIND_REF) {
                /* By-ref binding */
                var = GET_OP2_ZVAL_PTR(BP_VAR_W);
                if (Z_ISREF_P(var)) {
@@ -7851,8 +7850,7 @@ ZEND_VM_HANDLER(182, ZEND_BIND_LEXICAL, TMP, CV, REF)
                Z_TRY_ADDREF_P(var);
        }
 
-       var_name = CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var));
-       zend_closure_bind_var(closure, var_name, var);
+       zend_closure_bind_var_ex(closure, (opline->extended_value & ~ZEND_BIND_REF), var);
        ZEND_VM_NEXT_OPCODE();
 }
 
@@ -7878,9 +7876,9 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, CONST, REF)
        }
 
        varname = GET_OP2_ZVAL_PTR(BP_VAR_R);
-       value = zend_hash_find_ex(ht, Z_STR_P(varname), 1);
+       value = (zval*)((char*)ht->arData + (opline->extended_value & ~ZEND_BIND_REF));
 
-       if (opline->extended_value) {
+       if (opline->extended_value & ZEND_BIND_REF) {
                if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
                        SAVE_OPLINE();
                        if (UNEXPECTED(zval_update_constant_ex(value, EX(func)->op_array.scope) != SUCCESS)) {
index 523e0985f9eb53312cadf0aaa3d30c9676fa701a..20c0e672633e05753b6ccc8fd30637fc46062d92 100644 (file)
@@ -20366,10 +20366,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_LEXICAL_SPEC_TMP_CV_HANDL
        USE_OPLINE
        zend_free_op free_op1;
        zval *closure, *var;
-       zend_string *var_name;
 
        closure = _get_zval_ptr_tmp(opline->op1.var, &free_op1 EXECUTE_DATA_CC);
-       if (opline->extended_value) {
+       if (opline->extended_value & ZEND_BIND_REF) {
                /* By-ref binding */
                var = _get_zval_ptr_cv_BP_VAR_W(opline->op2.var EXECUTE_DATA_CC);
                if (Z_ISREF_P(var)) {
@@ -20390,8 +20389,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_LEXICAL_SPEC_TMP_CV_HANDL
                Z_TRY_ADDREF_P(var);
        }
 
-       var_name = CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var));
-       zend_closure_bind_var(closure, var_name, var);
+       zend_closure_bind_var_ex(closure, (opline->extended_value & ~ZEND_BIND_REF), var);
        ZEND_VM_NEXT_OPCODE();
 }
 
@@ -42028,9 +42026,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_CONST_HAND
        }
 
        varname = RT_CONSTANT(opline, opline->op2);
-       value = zend_hash_find_ex(ht, Z_STR_P(varname), 1);
+       value = (zval*)((char*)ht->arData + (opline->extended_value & ~ZEND_BIND_REF));
 
-       if (opline->extended_value) {
+       if (opline->extended_value & ZEND_BIND_REF) {
                if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
                        SAVE_OPLINE();
                        if (UNEXPECTED(zval_update_constant_ex(value, EX(func)->op_array.scope) != SUCCESS)) {
index 224ea56167a1f08e118e22c95589f0bbb5763bb2..403ac3c0b34486e8a6c09d9660a537fc475794a2 100644 (file)
@@ -164,7 +164,7 @@ op1_use:
                                                        }
                                                        goto op2_use;
                                                case ZEND_BIND_LEXICAL:
-                                                       if ((build_flags & ZEND_SSA_RC_INFERENCE) || opline->extended_value) {
+                                                       if ((build_flags & ZEND_SSA_RC_INFERENCE) || (opline->extended_value & ZEND_BIND_REF)) {
                                                                goto op2_def;
                                                        }
                                                        goto op2_use;
index 92a4cbeaea265828c40f530614194f05329b1834..46749b64c6d54a4e4bb362713748553c2792e71c 100644 (file)
@@ -2824,7 +2824,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
                        break;
                case ZEND_BIND_STATIC:
                        tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF
-                               | (opline->extended_value ? MAY_BE_REF : (MAY_BE_RC1 | MAY_BE_RCN));
+                               | ((opline->extended_value & ZEND_BIND_REF) ? MAY_BE_REF : (MAY_BE_RC1 | MAY_BE_RCN));
                        UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def);
                        break;
                case ZEND_SEND_VAR:
@@ -2839,7 +2839,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
                        break;
                case ZEND_BIND_LEXICAL:
                        if (ssa_ops[i].op2_def >= 0) {
-                               if (opline->extended_value) {
+                               if (opline->extended_value & ZEND_BIND_REF) {
                                        tmp = t2 | MAY_BE_REF;
                                } else {
                                        tmp = t2 & ~(MAY_BE_RC1|MAY_BE_RCN);
index a18f4a875c09d3a58bd351a85798e97aaee023aa..b4f54264bab9508cdef80e6e396378d31eb637d6 100644 (file)
@@ -747,7 +747,7 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
                                        }
                                        break;
                                case ZEND_BIND_LEXICAL:
-                                       if (opline->extended_value || (build_flags & ZEND_SSA_RC_INFERENCE)) {
+                                       if ((opline->extended_value & ZEND_BIND_REF) || (build_flags & ZEND_SSA_RC_INFERENCE)) {
                                                ssa_ops[k].op2_def = ssa_vars_count;
                                                var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
                                                ssa_vars_count++;