Skip to content

Commit 36e1c97

Browse files
committed
OPcache support, remove ASSIGN_STATIC
1 parent 8cb302a commit 36e1c97

22 files changed

+662
-673
lines changed

Zend/Optimizer/block_pass.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,7 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op
995995
case ZEND_COALESCE:
996996
case ZEND_ASSERT_CHECK:
997997
case ZEND_JMP_NULL:
998+
case ZEND_JMP_STATIC_DEF:
998999
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start);
9991000
break;
10001001
case ZEND_CATCH:

Zend/Optimizer/dce.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ static inline bool may_have_side_effects(
145145
case ZEND_COALESCE:
146146
case ZEND_ASSERT_CHECK:
147147
case ZEND_JMP_NULL:
148+
case ZEND_JMP_STATIC_DEF:
148149
/* For our purposes a jumps and branches are side effects. */
149150
return 1;
150151
case ZEND_BEGIN_SILENCE:

Zend/Optimizer/dfa_pass.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,7 @@ static void zend_ssa_replace_control_link(zend_op_array *op_array, zend_ssa *ssa
650650
case ZEND_COALESCE:
651651
case ZEND_ASSERT_CHECK:
652652
case ZEND_JMP_NULL:
653+
case ZEND_JMP_STATIC_DEF:
653654
if (ZEND_OP2_JMP_ADDR(opline) == op_array->opcodes + old->start) {
654655
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, op_array->opcodes + dst->start);
655656
}

Zend/Optimizer/pass1.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
354354
case ZEND_ASSERT_CHECK:
355355
case ZEND_JMP_NULL:
356356
case ZEND_VERIFY_NEVER_TYPE:
357+
case ZEND_JMP_STATIC_DEF:
357358
collect_constants = 0;
358359
break;
359360
}

Zend/Optimizer/sccp.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,6 +1772,7 @@ static void sccp_mark_feasible_successors(
17721772
case ZEND_CATCH:
17731773
case ZEND_FE_FETCH_R:
17741774
case ZEND_FE_FETCH_RW:
1775+
case ZEND_JMP_STATIC_DEF:
17751776
scdf_mark_edge_feasible(scdf, block_num, block->successors[0]);
17761777
scdf_mark_edge_feasible(scdf, block_num, block->successors[1]);
17771778
return;

Zend/Optimizer/zend_cfg.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ ZEND_API void zend_build_cfg(zend_arena **arena, const zend_op_array *op_array,
369369
case ZEND_COALESCE:
370370
case ZEND_ASSERT_CHECK:
371371
case ZEND_JMP_NULL:
372+
case ZEND_JMP_STATIC_DEF:
372373
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
373374
BB_START(i + 1);
374375
break;
@@ -522,6 +523,7 @@ ZEND_API void zend_build_cfg(zend_arena **arena, const zend_op_array *op_array,
522523
case ZEND_COALESCE:
523524
case ZEND_ASSERT_CHECK:
524525
case ZEND_JMP_NULL:
526+
case ZEND_JMP_STATIC_DEF:
525527
block->successors_count = 2;
526528
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
527529
block->successors[1] = j + 1;

Zend/Optimizer/zend_optimizer.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,7 @@ void zend_optimizer_migrate_jump(zend_op_array *op_array, zend_op *new_opline, z
720720
case ZEND_COALESCE:
721721
case ZEND_ASSERT_CHECK:
722722
case ZEND_JMP_NULL:
723+
case ZEND_JMP_STATIC_DEF:
723724
ZEND_SET_OP_JMP_ADDR(new_opline, new_opline->op2, ZEND_OP2_JMP_ADDR(opline));
724725
break;
725726
case ZEND_FE_FETCH_R:
@@ -763,6 +764,7 @@ void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_
763764
case ZEND_COALESCE:
764765
case ZEND_ASSERT_CHECK:
765766
case ZEND_JMP_NULL:
767+
case ZEND_JMP_STATIC_DEF:
766768
ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(opline) - shiftlist[ZEND_OP2_JMP_ADDR(opline) - op_array->opcodes]);
767769
break;
768770
case ZEND_CATCH:
@@ -1154,6 +1156,7 @@ static void zend_redo_pass_two(zend_op_array *op_array)
11541156
case ZEND_FE_RESET_RW:
11551157
case ZEND_ASSERT_CHECK:
11561158
case ZEND_JMP_NULL:
1159+
case ZEND_JMP_STATIC_DEF:
11571160
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
11581161
break;
11591162
case ZEND_CATCH:
@@ -1274,6 +1277,7 @@ static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa)
12741277
case ZEND_FE_RESET_RW:
12751278
case ZEND_ASSERT_CHECK:
12761279
case ZEND_JMP_NULL:
1280+
case ZEND_JMP_STATIC_DEF:
12771281
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
12781282
break;
12791283
case ZEND_CATCH:

Zend/tests/bug79778.phpt

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,36 @@ print_r($closure1);
2525

2626
?>
2727
--EXPECT--
28-
object(Closure)#1 (0) {
28+
object(Closure)#1 (1) {
29+
["static"]=>
30+
array(1) {
31+
["var"]=>
32+
NULL
33+
}
2934
}
3035
Closure Object
3136
(
37+
[static] => Array
38+
(
39+
[var] =>
40+
)
41+
3242
)
3343
Undefined constant "CONST_REF"
34-
object(Closure)#1 (0) {
44+
object(Closure)#1 (1) {
45+
["static"]=>
46+
array(1) {
47+
["var"]=>
48+
NULL
49+
}
3550
}
3651
Closure Object
3752
(
53+
[static] => Array
54+
(
55+
[var] =>
56+
)
57+
3858
)
3959
object(Closure)#1 (1) {
4060
["static"]=>

Zend/zend_compile.c

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2174,7 +2174,6 @@ static inline void zend_update_jump_target(uint32_t opnum_jump, uint32_t opnum_t
21742174
zend_op *opline = &CG(active_op_array)->opcodes[opnum_jump];
21752175
switch (opline->opcode) {
21762176
case ZEND_JMP:
2177-
case ZEND_JMP_STATIC_DEF:
21782177
opline->op1.opline_num = opnum_target;
21792178
break;
21802179
case ZEND_JMPZ:
@@ -2184,6 +2183,7 @@ static inline void zend_update_jump_target(uint32_t opnum_jump, uint32_t opnum_t
21842183
case ZEND_JMP_SET:
21852184
case ZEND_COALESCE:
21862185
case ZEND_JMP_NULL:
2186+
case ZEND_JMP_STATIC_DEF:
21872187
opline->op2.opline_num = opnum_target;
21882188
break;
21892189
EMPTY_SWITCH_DEFAULT_CASE()
@@ -4789,7 +4789,7 @@ static void zend_compile_static_var(zend_ast *ast) /* {{{ */
47894789
if (!value_ast) {
47904790
zval value_zv;
47914791
ZVAL_NULL(&value_zv);
4792-
zend_compile_static_var_common(zend_ast_get_str(var_ast), &value_zv, ZEND_BIND_REF);
4792+
zend_compile_static_var_common(var_name, &value_zv, ZEND_BIND_REF);
47934793
} else {
47944794
zend_op *opline;
47954795

@@ -4800,31 +4800,43 @@ static void zend_compile_static_var(zend_ast *ast) /* {{{ */
48004800
CG(active_op_array)->static_variables = zend_new_array(8);
48014801
}
48024802

4803+
if (zend_string_equals_literal(var_name, "this")) {
4804+
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as static variable");
4805+
}
48034806
if (zend_hash_exists(CG(active_op_array)->static_variables, var_name)) {
48044807
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate declaration of static variable $%s", ZSTR_VAL(var_name));
48054808
}
48064809

4807-
zval placeholder;
4808-
ZVAL_UNDEF(&placeholder);
4809-
zval *placeholder_ptr = zend_hash_update(CG(active_op_array)->static_variables, var_name, &placeholder);
4810+
zval *placeholder_ptr = zend_hash_update(CG(active_op_array)->static_variables, var_name, &EG(uninitialized_zval));
4811+
Z_TYPE_EXTRA_P(placeholder_ptr) = IS_TYPE_UNINITIALIZED;
48104812
uint32_t placeholder_offset = (uint32_t)((char*)placeholder_ptr - (char*)CG(active_op_array)->static_variables->arData);
48114813

4812-
uint32_t jmp_opnum = get_next_op_number();
4814+
uint32_t static_def_jmp_opnum = get_next_op_number();
48134815
opline = zend_emit_op(NULL, ZEND_JMP_STATIC_DEF, NULL, NULL);
48144816
opline->extended_value = placeholder_offset;
48154817

48164818
znode expr;
48174819
zend_compile_expr(&expr, value_ast);
48184820

4819-
opline = zend_emit_op(NULL, ZEND_ASSIGN_STATIC, &expr, NULL);
4820-
opline->extended_value = placeholder_offset;
4821+
opline = zend_emit_op(NULL, ZEND_BIND_STATIC, NULL, NULL);
4822+
opline->op1_type = IS_CV;
4823+
opline->op1.var = lookup_cv(var_name);
4824+
opline->extended_value = placeholder_offset | ZEND_BIND_REF;
48214825

4822-
zend_update_jump_target_to_next(jmp_opnum);
4826+
opline = zend_emit_op(NULL, ZEND_ASSIGN, NULL, &expr);
4827+
opline->op1_type = IS_CV;
4828+
opline->op1.var = lookup_cv(var_name);
4829+
4830+
uint32_t skip_bind_static_jmp_opnum = zend_emit_jump(0);
4831+
4832+
zend_update_jump_target_to_next(static_def_jmp_opnum);
48234833

48244834
opline = zend_emit_op(NULL, ZEND_BIND_STATIC, NULL, NULL);
48254835
opline->op1_type = IS_CV;
48264836
opline->op1.var = lookup_cv(var_name);
48274837
opline->extended_value = placeholder_offset | ZEND_BIND_REF;
4838+
4839+
zend_update_jump_target_to_next(skip_bind_static_jmp_opnum);
48284840
}
48294841
}
48304842
/* }}} */

Zend/zend_opcode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1103,7 +1103,6 @@ ZEND_API void pass_two(zend_op_array *op_array)
11031103
}
11041104
ZEND_FALLTHROUGH;
11051105
case ZEND_JMP:
1106-
case ZEND_JMP_STATIC_DEF:
11071106
ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op1);
11081107
break;
11091108
case ZEND_JMPZ:
@@ -1115,6 +1114,7 @@ ZEND_API void pass_two(zend_op_array *op_array)
11151114
case ZEND_FE_RESET_R:
11161115
case ZEND_FE_RESET_RW:
11171116
case ZEND_JMP_NULL:
1117+
case ZEND_JMP_STATIC_DEF:
11181118
ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
11191119
break;
11201120
case ZEND_ASSERT_CHECK:

Zend/zend_types.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,9 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
587587
#define Z_TYPE_FLAGS(zval) (zval).u1.v.type_flags
588588
#define Z_TYPE_FLAGS_P(zval_p) Z_TYPE_FLAGS(*(zval_p))
589589

590+
#define Z_TYPE_EXTRA(zval) (zval).u1.v.u.extra
591+
#define Z_TYPE_EXTRA_P(zval_p) Z_TYPE_EXTRA(*(zval_p))
592+
590593
#define Z_TYPE_INFO(zval) (zval).u1.type_info
591594
#define Z_TYPE_INFO_P(zval_p) Z_TYPE_INFO(*(zval_p))
592595

@@ -693,6 +696,11 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) {
693696
/* zval.u1.v.type_flags */
694697
#define IS_TYPE_REFCOUNTED (1<<0)
695698
#define IS_TYPE_COLLECTABLE (1<<1)
699+
/* Used for static variables to check if they have been initialized. We can't use IS_UNDEF because
700+
* we can't store IS_UNDEF zvals in static_variables HashTable. This needs to live in type_info so
701+
* that the ZEND_ASSIGN overrides it but lives in extra to avoid breaking the Z_REFCOUNTED()
702+
* optimization that only checks for Z_TYPE_FLAGS() without `& (IS_TYPE_COLLECTABLE|IS_TYPE_REFCOUNTED)`. */
703+
#define IS_TYPE_UNINITIALIZED (1<<0)
696704

697705
#if 1
698706
/* This optimized version assumes that we have a single "type_flag" */
@@ -1446,5 +1454,4 @@ static zend_always_inline uint32_t zval_delref_p(zval* pz) {
14461454
#define ZVAL_COPY_OR_DUP_PROP(z, v) \
14471455
do { ZVAL_COPY_OR_DUP(z, v); Z_PROP_FLAG_P(z) = Z_PROP_FLAG_P(v); } while (0)
14481456

1449-
14501457
#endif /* ZEND_TYPES_H */

Zend/zend_vm_def.h

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8890,7 +8890,7 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, UNUSED, REF)
88908890
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
88918891
}
88928892

8893-
ZEND_VM_HANDLER(203, ZEND_JMP_STATIC_DEF, JMP_ADDR, UNUSED)
8893+
ZEND_VM_HANDLER(203, ZEND_JMP_STATIC_DEF, ANY, JMP_ADDR)
88948894
{
88958895
USE_OPLINE
88968896
HashTable *ht;
@@ -8903,40 +8903,11 @@ ZEND_VM_HANDLER(203, ZEND_JMP_STATIC_DEF, JMP_ADDR, UNUSED)
89038903
ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
89048904

89058905
value = (zval*)((char*)ht->arData + (opline->extended_value));
8906-
if (Z_TYPE_P(value) == IS_UNDEF) {
8906+
if (Z_TYPE_EXTRA_P(value) == IS_TYPE_UNINITIALIZED) {
89078907
ZEND_VM_NEXT_OPCODE();
89088908
} else {
8909-
ZEND_VM_JMP_EX(OP_JMP_ADDR(opline, opline->op1), 0);
8910-
}
8911-
}
8912-
8913-
ZEND_VM_HANDLER(204, ZEND_ASSIGN_STATIC, ANY, UNUSED)
8914-
{
8915-
USE_OPLINE
8916-
HashTable *ht;
8917-
zval *static_var;
8918-
zval *value;
8919-
8920-
value = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
8921-
8922-
ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr);
8923-
if (!ht) {
8924-
ht = zend_array_dup(EX(func)->op_array.static_variables);
8925-
ZEND_MAP_PTR_SET(EX(func)->op_array.static_variables_ptr, ht);
8926-
}
8927-
ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
8928-
8929-
static_var = (zval*)((char*)ht->arData + (opline->extended_value));
8930-
8931-
SAVE_OPLINE();
8932-
i_zval_ptr_dtor(static_var);
8933-
if (EG(exception)) {
8934-
HANDLE_EXCEPTION();
8909+
ZEND_VM_JMP_EX(OP_JMP_ADDR(opline, opline->op2), 0);
89358910
}
8936-
ZVAL_COPY(static_var, value);
8937-
8938-
FREE_OP1();
8939-
ZEND_VM_NEXT_OPCODE();
89408911
}
89418912

89428913
ZEND_VM_HOT_HANDLER(184, ZEND_FETCH_THIS, UNUSED, UNUSED)

0 commit comments

Comments
 (0)