Skip to content

Commit 077460f

Browse files
committed
Omit FETCH_THIS in closures
Non-static closures are guaranteed to have $this. The existing comment highlights this, but fails to handle it correctly.
1 parent c8920aa commit 077460f

File tree

5 files changed

+73
-29
lines changed

5 files changed

+73
-29
lines changed

Zend/zend_compile.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -313,9 +313,11 @@ static bool zend_is_not_imported(zend_string *name) {
313313
return !FC(imports) || zend_hash_find_ptr_lc(FC(imports), name) == NULL;
314314
}
315315

316-
void zend_oparray_context_begin(zend_oparray_context *prev_context) /* {{{ */
316+
void zend_oparray_context_begin(zend_oparray_context *prev_context, zend_op_array *op_array) /* {{{ */
317317
{
318318
*prev_context = CG(context);
319+
CG(context).prev = CG(context).op_array ? prev_context : NULL;
320+
CG(context).op_array = op_array;
319321
CG(context).opcodes_size = INITIAL_OP_ARRAY_SIZE;
320322
CG(context).vars_size = 0;
321323
CG(context).literals_size = 0;
@@ -2920,11 +2922,21 @@ static bool is_global_var_fetch(zend_ast *ast)
29202922

29212923
static bool this_guaranteed_exists(void) /* {{{ */
29222924
{
2923-
zend_op_array *op_array = CG(active_op_array);
2924-
/* Instance methods always have a $this.
2925-
* This also includes closures that have a scope and use $this. */
2926-
return op_array->scope != NULL
2927-
&& (op_array->fn_flags & ZEND_ACC_STATIC) == 0;
2925+
zend_oparray_context *ctx = &CG(context);
2926+
while (ctx) {
2927+
/* Instance methods always have a $this.
2928+
* This also includes closures that have a scope and use $this. */
2929+
zend_op_array *op_array = ctx->op_array;
2930+
if (op_array->fn_flags & ZEND_ACC_STATIC) {
2931+
return false;
2932+
} else if (op_array->scope) {
2933+
return true;
2934+
} else if (!(op_array->fn_flags & ZEND_ACC_CLOSURE)) {
2935+
return false;
2936+
}
2937+
ctx = ctx->prev;
2938+
}
2939+
return false;
29282940
}
29292941
/* }}} */
29302942

@@ -7869,7 +7881,7 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel)
78697881
op_array->fn_flags |= ZEND_ACC_TOP_LEVEL;
78707882
}
78717883

7872-
zend_oparray_context_begin(&orig_oparray_context);
7884+
zend_oparray_context_begin(&orig_oparray_context, op_array);
78737885

78747886
{
78757887
/* Push a separator to the loop variable stack */

Zend/zend_compile.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ typedef struct _zend_live_range {
190190

191191
/* Compilation context that is different for each op array. */
192192
typedef struct _zend_oparray_context {
193+
struct _zend_oparray_context *prev;
194+
zend_op_array *op_array;
193195
uint32_t opcodes_size;
194196
int vars_size;
195197
int literals_size;
@@ -802,7 +804,7 @@ void init_compiler(void);
802804
void shutdown_compiler(void);
803805
void zend_init_compiler_data_structures(void);
804806

805-
void zend_oparray_context_begin(zend_oparray_context *prev_context);
807+
void zend_oparray_context_begin(zend_oparray_context *prev_context, zend_op_array *op_array);
806808
void zend_oparray_context_end(zend_oparray_context *prev_context);
807809
void zend_file_context_begin(zend_file_context *prev_context);
808810
void zend_file_context_end(zend_file_context *prev_context);

Zend/zend_language_scanner.l

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ static zend_op_array *zend_compile(int type)
614614
}
615615

616616
zend_file_context_begin(&original_file_context);
617-
zend_oparray_context_begin(&original_oparray_context);
617+
zend_oparray_context_begin(&original_oparray_context, op_array);
618618
zend_compile_top_stmt(CG(ast));
619619
CG(zend_lineno) = last_lineno;
620620
zend_emit_final_return(type == ZEND_USER_FUNCTION);

ext/opcache/jit/zend_jit.c

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1729,8 +1729,11 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
17291729
on_this = 0;
17301730
if (opline->op1_type == IS_UNUSED) {
17311731
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
1732-
ce = op_array->scope;
1733-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
1732+
/* scope is NULL for closures. */
1733+
if (op_array->scope) {
1734+
ce = op_array->scope;
1735+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
1736+
}
17341737
op1_addr = 0;
17351738
on_this = 1;
17361739
} else {
@@ -1777,8 +1780,11 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
17771780
on_this = 0;
17781781
if (opline->op1_type == IS_UNUSED) {
17791782
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
1780-
ce = op_array->scope;
1781-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
1783+
/* scope is NULL for closures. */
1784+
if (op_array->scope) {
1785+
ce = op_array->scope;
1786+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
1787+
}
17821788
op1_addr = 0;
17831789
on_this = 1;
17841790
} else {
@@ -1818,8 +1824,11 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
18181824
on_this = 0;
18191825
if (opline->op1_type == IS_UNUSED) {
18201826
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
1821-
ce = op_array->scope;
1822-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
1827+
/* scope is NULL for closures. */
1828+
if (op_array->scope) {
1829+
ce = op_array->scope;
1830+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
1831+
}
18231832
op1_addr = 0;
18241833
on_this = 1;
18251834
} else {
@@ -2291,8 +2300,11 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
22912300
if (opline->op1_type == IS_UNUSED) {
22922301
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
22932302
op1_addr = 0;
2294-
ce = op_array->scope;
2295-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
2303+
/* scope is NULL for closures. */
2304+
if (op_array->scope) {
2305+
ce = op_array->scope;
2306+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
2307+
}
22962308
on_this = 1;
22972309
} else {
22982310
op1_info = OP1_INFO();
@@ -2442,8 +2454,11 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
24422454
if (opline->op1_type == IS_UNUSED) {
24432455
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
24442456
op1_addr = 0;
2445-
ce = op_array->scope;
2446-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
2457+
/* scope is NULL for closures. */
2458+
if (op_array->scope) {
2459+
ce = op_array->scope;
2460+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
2461+
}
24472462
on_this = 1;
24482463
} else {
24492464
op1_info = OP1_INFO();

ext/opcache/jit/zend_jit_trace.c

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4650,8 +4650,11 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
46504650
op1_indirect = 0;
46514651
if (opline->op1_type == IS_UNUSED) {
46524652
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
4653-
ce = op_array->scope;
4654-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4653+
/* scope is NULL for closures. */
4654+
if (op_array->scope) {
4655+
ce = op_array->scope;
4656+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4657+
}
46554658
op1_addr = 0;
46564659
on_this = 1;
46574660
} else {
@@ -4741,8 +4744,11 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
47414744
op1_indirect = 0;
47424745
if (opline->op1_type == IS_UNUSED) {
47434746
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
4744-
ce = op_array->scope;
4745-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4747+
/* scope is NULL for closures. */
4748+
if (op_array->scope) {
4749+
ce = op_array->scope;
4750+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4751+
}
47464752
op1_addr = 0;
47474753
on_this = 1;
47484754
} else {
@@ -4821,8 +4827,11 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
48214827
op1_indirect = 0;
48224828
if (opline->op1_type == IS_UNUSED) {
48234829
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
4824-
ce = op_array->scope;
4825-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4830+
/* scope is NULL for closures. */
4831+
if (op_array->scope) {
4832+
ce = op_array->scope;
4833+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4834+
}
48264835
op1_addr = 0;
48274836
on_this = 1;
48284837
} else {
@@ -5879,8 +5888,11 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
58795888
op1_indirect = 0;
58805889
if (opline->op1_type == IS_UNUSED) {
58815890
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
5882-
ce = op_array->scope;
5883-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
5891+
/* scope is NULL for closures. */
5892+
if (op_array->scope) {
5893+
ce = op_array->scope;
5894+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
5895+
}
58845896
op1_addr = 0;
58855897
on_this = 1;
58865898
} else {
@@ -6158,8 +6170,11 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
61586170
ce_is_instanceof = 0;
61596171
if (opline->op1_type == IS_UNUSED) {
61606172
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
6161-
ce = op_array->scope;
6162-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
6173+
/* scope is NULL for closures. */
6174+
if (op_array->scope) {
6175+
ce = op_array->scope;
6176+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
6177+
}
61636178
op1_addr = 0;
61646179
on_this = 1;
61656180
} else {

0 commit comments

Comments
 (0)