Skip to content

Commit b882892

Browse files
committed
Avoid hash lookups in BIND_STATIC and BIND_LEXICAL opcode handlers.
Encode static variable offset into opline->extended_value.
1 parent 1621f17 commit b882892

File tree

10 files changed

+57
-32
lines changed

10 files changed

+57
-32
lines changed

Zend/zend_closures.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,16 @@ void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var) /
729729
}
730730
/* }}} */
731731

732+
void zend_closure_bind_var_ex(zval *closure_zv, uint32_t offset, zval *val) /* {{{ */
733+
{
734+
zend_closure *closure = (zend_closure *) Z_OBJ_P(closure_zv);
735+
HashTable *static_variables = closure->func.op_array.static_variables;
736+
zval *var = (zval*)((char*)static_variables->arData + offset);
737+
zval_ptr_dtor(var);
738+
ZVAL_COPY_VALUE(var, val);
739+
}
740+
/* }}} */
741+
732742
/*
733743
* Local variables:
734744
* tab-width: 4

Zend/zend_closures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ BEGIN_EXTERN_C()
2828

2929
void zend_register_closure_ce(void);
3030
void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var);
31+
void zend_closure_bind_var_ex(zval *closure_zv, uint32_t offset, zval *val);
3132

3233
extern ZEND_API zend_class_entry *zend_ce_closure;
3334

Zend/zend_compile.c

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4247,7 +4247,7 @@ void zend_compile_global_var(zend_ast *ast) /* {{{ */
42474247
}
42484248
/* }}} */
42494249

4250-
static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, zend_bool by_ref) /* {{{ */
4250+
static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, uint32_t by_ref) /* {{{ */
42514251
{
42524252
znode var_node;
42534253
zend_op *opline;
@@ -4274,7 +4274,7 @@ static void zend_compile_static_var_common(zend_ast *var_ast, zval *value, zend_
42744274
}
42754275
CG(active_op_array)->static_variables = zend_array_dup(CG(active_op_array)->static_variables);
42764276
}
4277-
zend_hash_update(CG(active_op_array)->static_variables, var_name, value);
4277+
value = zend_hash_update(CG(active_op_array)->static_variables, var_name, value);
42784278

42794279
if (zend_string_equals_literal(var_name, "this")) {
42804280
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_
42834283
opline = zend_emit_op(NULL, ZEND_BIND_STATIC, NULL, &var_node);
42844284
opline->op1_type = IS_CV;
42854285
opline->op1.var = lookup_cv(CG(active_op_array), var_name);
4286-
opline->extended_value = by_ref;
4286+
opline->extended_value = (uint32_t)((char*)value - (char*)CG(active_op_array)->static_variables->arData) | by_ref;
42874287
}
42884288
/* }}} */
42894289

@@ -4299,7 +4299,7 @@ void zend_compile_static_var(zend_ast *ast) /* {{{ */
42994299
ZVAL_NULL(&value_zv);
43004300
}
43014301

4302-
zend_compile_static_var_common(var_ast, &value_zv, 1);
4302+
zend_compile_static_var_common(var_ast, &value_zv, ZEND_BIND_REF);
43034303
}
43044304
/* }}} */
43054305

@@ -5672,16 +5672,32 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */
56725672
}
56735673
/* }}} */
56745674

5675-
static void zend_compile_closure_binding(znode *closure, zend_ast *uses_ast) /* {{{ */
5675+
static void zend_compile_closure_binding(znode *closure, zend_op_array *op_array, zend_ast *uses_ast) /* {{{ */
56765676
{
56775677
zend_ast_list *list = zend_ast_get_list(uses_ast);
56785678
uint32_t i;
56795679

5680+
if (!list->children) {
5681+
return;
5682+
}
5683+
5684+
if (!op_array->static_variables) {
5685+
op_array->static_variables = zend_new_array(8);
5686+
}
5687+
5688+
if (GC_REFCOUNT(op_array->static_variables) > 1) {
5689+
if (!(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)) {
5690+
GC_DELREF(op_array->static_variables);
5691+
}
5692+
op_array->static_variables = zend_array_dup(op_array->static_variables);
5693+
}
5694+
56805695
for (i = 0; i < list->children; ++i) {
56815696
zend_ast *var_name_ast = list->child[i];
56825697
zend_string *var_name = zval_make_interned_string(zend_ast_get_zval(var_name_ast));
5683-
zend_bool by_ref = var_name_ast->attr;
5698+
uint32_t by_ref = var_name_ast->attr;
56845699
zend_op *opline;
5700+
zval *value;
56855701

56865702
if (zend_string_equals_literal(var_name, "this")) {
56875703
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) /*
56915707
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use auto-global as lexical variable");
56925708
}
56935709

5710+
value = zend_hash_add(op_array->static_variables, var_name, &EG(uninitialized_zval));
5711+
if (!value) {
5712+
zend_error_noreturn(E_COMPILE_ERROR,
5713+
"Cannot use variable $%s twice", ZSTR_VAL(var_name));
5714+
}
5715+
56945716
opline = zend_emit_op(NULL, ZEND_BIND_LEXICAL, closure, NULL);
56955717
opline->op2_type = IS_CV;
56965718
opline->op2.var = lookup_cv(CG(active_op_array), var_name);
5697-
opline->extended_value = by_ref;
5719+
opline->extended_value = (uint32_t)((char*)value - (char*)op_array->static_variables->arData) | by_ref;
56985720
}
56995721
}
57005722
/* }}} */
@@ -5708,16 +5730,10 @@ void zend_compile_closure_uses(zend_ast *ast) /* {{{ */
57085730
for (i = 0; i < list->children; ++i) {
57095731
zend_ast *var_ast = list->child[i];
57105732
zend_string *var_name = zend_ast_get_str(var_ast);
5711-
zend_bool by_ref = var_ast->attr;
5733+
uint32_t by_ref = var_ast->attr;
57125734
zval zv;
57135735
ZVAL_NULL(&zv);
57145736

5715-
if (op_array->static_variables
5716-
&& zend_hash_exists(op_array->static_variables, var_name)) {
5717-
zend_error_noreturn(E_COMPILE_ERROR,
5718-
"Cannot use variable $%s twice", ZSTR_VAL(var_name));
5719-
}
5720-
57215737
{
57225738
int i;
57235739
for (i = 0; i < op_array->last_var; i++) {
@@ -5996,7 +6012,7 @@ void zend_compile_func_decl(znode *result, zend_ast *ast) /* {{{ */
59966012
} else {
59976013
zend_begin_func_decl(result, op_array, decl);
59986014
if (uses_ast) {
5999-
zend_compile_closure_binding(result, uses_ast);
6015+
zend_compile_closure_binding(result, op_array, uses_ast);
60006016
}
60016017
}
60026018

Zend/zend_compile.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,8 @@ static zend_always_inline int zend_check_arg_send_type(const zend_function *zf,
970970
#define ZEND_RETURN_VAL 0
971971
#define ZEND_RETURN_REF 1
972972

973+
#define ZEND_BIND_VAL 0
974+
#define ZEND_BIND_REF 1
973975

974976
#define ZEND_RETURNS_FUNCTION (1<<0)
975977
#define ZEND_RETURNS_VALUE (1<<1)

Zend/zend_language_parser.y

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1021,7 +1021,7 @@ lexical_var_list:
10211021

10221022
lexical_var:
10231023
T_VARIABLE { $$ = $1; }
1024-
| '&' T_VARIABLE { $$ = $2; $$->attr = 1; }
1024+
| '&' T_VARIABLE { $$ = $2; $$->attr = ZEND_BIND_REF; }
10251025
;
10261026

10271027
function_call:

Zend/zend_vm_def.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7827,10 +7827,9 @@ ZEND_VM_HANDLER(182, ZEND_BIND_LEXICAL, TMP, CV, REF)
78277827
USE_OPLINE
78287828
zend_free_op free_op1, free_op2;
78297829
zval *closure, *var;
7830-
zend_string *var_name;
78317830

78327831
closure = GET_OP1_ZVAL_PTR(BP_VAR_R);
7833-
if (opline->extended_value) {
7832+
if (opline->extended_value & ZEND_BIND_REF) {
78347833
/* By-ref binding */
78357834
var = GET_OP2_ZVAL_PTR(BP_VAR_W);
78367835
if (Z_ISREF_P(var)) {
@@ -7851,8 +7850,7 @@ ZEND_VM_HANDLER(182, ZEND_BIND_LEXICAL, TMP, CV, REF)
78517850
Z_TRY_ADDREF_P(var);
78527851
}
78537852

7854-
var_name = CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var));
7855-
zend_closure_bind_var(closure, var_name, var);
7853+
zend_closure_bind_var_ex(closure, (opline->extended_value & ~ZEND_BIND_REF), var);
78567854
ZEND_VM_NEXT_OPCODE();
78577855
}
78587856

@@ -7878,9 +7876,9 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, CONST, REF)
78787876
}
78797877

78807878
varname = GET_OP2_ZVAL_PTR(BP_VAR_R);
7881-
value = zend_hash_find_ex(ht, Z_STR_P(varname), 1);
7879+
value = (zval*)((char*)ht->arData + (opline->extended_value & ~ZEND_BIND_REF));
78827880

7883-
if (opline->extended_value) {
7881+
if (opline->extended_value & ZEND_BIND_REF) {
78847882
if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
78857883
SAVE_OPLINE();
78867884
if (UNEXPECTED(zval_update_constant_ex(value, EX(func)->op_array.scope) != SUCCESS)) {

Zend/zend_vm_execute.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20366,10 +20366,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_LEXICAL_SPEC_TMP_CV_HANDL
2036620366
USE_OPLINE
2036720367
zend_free_op free_op1;
2036820368
zval *closure, *var;
20369-
zend_string *var_name;
2037020369

2037120370
closure = _get_zval_ptr_tmp(opline->op1.var, &free_op1 EXECUTE_DATA_CC);
20372-
if (opline->extended_value) {
20371+
if (opline->extended_value & ZEND_BIND_REF) {
2037320372
/* By-ref binding */
2037420373
var = _get_zval_ptr_cv_BP_VAR_W(opline->op2.var EXECUTE_DATA_CC);
2037520374
if (Z_ISREF_P(var)) {
@@ -20390,8 +20389,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_LEXICAL_SPEC_TMP_CV_HANDL
2039020389
Z_TRY_ADDREF_P(var);
2039120390
}
2039220391

20393-
var_name = CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var));
20394-
zend_closure_bind_var(closure, var_name, var);
20392+
zend_closure_bind_var_ex(closure, (opline->extended_value & ~ZEND_BIND_REF), var);
2039520393
ZEND_VM_NEXT_OPCODE();
2039620394
}
2039720395

@@ -42028,9 +42026,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_CONST_HAND
4202842026
}
4202942027

4203042028
varname = RT_CONSTANT(opline, opline->op2);
42031-
value = zend_hash_find_ex(ht, Z_STR_P(varname), 1);
42029+
value = (zval*)((char*)ht->arData + (opline->extended_value & ~ZEND_BIND_REF));
4203242030

42033-
if (opline->extended_value) {
42031+
if (opline->extended_value & ZEND_BIND_REF) {
4203442032
if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
4203542033
SAVE_OPLINE();
4203642034
if (UNEXPECTED(zval_update_constant_ex(value, EX(func)->op_array.scope) != SUCCESS)) {

ext/opcache/Optimizer/zend_dfg.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg
164164
}
165165
goto op2_use;
166166
case ZEND_BIND_LEXICAL:
167-
if ((build_flags & ZEND_SSA_RC_INFERENCE) || opline->extended_value) {
167+
if ((build_flags & ZEND_SSA_RC_INFERENCE) || (opline->extended_value & ZEND_BIND_REF)) {
168168
goto op2_def;
169169
}
170170
goto op2_use;

ext/opcache/Optimizer/zend_inference.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2824,7 +2824,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
28242824
break;
28252825
case ZEND_BIND_STATIC:
28262826
tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF
2827-
| (opline->extended_value ? MAY_BE_REF : (MAY_BE_RC1 | MAY_BE_RCN));
2827+
| ((opline->extended_value & ZEND_BIND_REF) ? MAY_BE_REF : (MAY_BE_RC1 | MAY_BE_RCN));
28282828
UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def);
28292829
break;
28302830
case ZEND_SEND_VAR:
@@ -2839,7 +2839,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
28392839
break;
28402840
case ZEND_BIND_LEXICAL:
28412841
if (ssa_ops[i].op2_def >= 0) {
2842-
if (opline->extended_value) {
2842+
if (opline->extended_value & ZEND_BIND_REF) {
28432843
tmp = t2 | MAY_BE_REF;
28442844
} else {
28452845
tmp = t2 & ~(MAY_BE_RC1|MAY_BE_RCN);

ext/opcache/Optimizer/zend_ssa.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,7 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
747747
}
748748
break;
749749
case ZEND_BIND_LEXICAL:
750-
if (opline->extended_value || (build_flags & ZEND_SSA_RC_INFERENCE)) {
750+
if ((opline->extended_value & ZEND_BIND_REF) || (build_flags & ZEND_SSA_RC_INFERENCE)) {
751751
ssa_ops[k].op2_def = ssa_vars_count;
752752
var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
753753
ssa_vars_count++;

0 commit comments

Comments
 (0)