Skip to content

Commit 600d591

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. Closes GH-14181
1 parent 5e7baaa commit 600d591

File tree

6 files changed

+69
-19
lines changed

6 files changed

+69
-19
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: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,7 +1742,10 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
17421742
if (opline->op1_type == IS_UNUSED) {
17431743
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
17441744
ce = op_array->scope;
1745-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
1745+
/* scope is NULL for closures. */
1746+
if (ce) {
1747+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
1748+
}
17461749
op1_addr = 0;
17471750
on_this = 1;
17481751
} else {
@@ -1790,7 +1793,10 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
17901793
if (opline->op1_type == IS_UNUSED) {
17911794
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
17921795
ce = op_array->scope;
1793-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
1796+
/* scope is NULL for closures. */
1797+
if (ce) {
1798+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
1799+
}
17941800
op1_addr = 0;
17951801
on_this = 1;
17961802
} else {
@@ -1831,7 +1837,10 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
18311837
if (opline->op1_type == IS_UNUSED) {
18321838
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
18331839
ce = op_array->scope;
1834-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
1840+
/* scope is NULL for closures. */
1841+
if (ce) {
1842+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
1843+
}
18351844
op1_addr = 0;
18361845
on_this = 1;
18371846
} else {
@@ -2305,7 +2314,10 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
23052314
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
23062315
op1_addr = 0;
23072316
ce = op_array->scope;
2308-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
2317+
/* scope is NULL for closures. */
2318+
if (ce) {
2319+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
2320+
}
23092321
on_this = 1;
23102322
} else {
23112323
op1_info = OP1_INFO();
@@ -2456,7 +2468,10 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
24562468
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
24572469
op1_addr = 0;
24582470
ce = op_array->scope;
2459-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
2471+
/* scope is NULL for closures. */
2472+
if (ce) {
2473+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
2474+
}
24602475
on_this = 1;
24612476
} else {
24622477
op1_info = OP1_INFO();

ext/opcache/jit/zend_jit_trace.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4692,7 +4692,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
46924692
if (opline->op1_type == IS_UNUSED) {
46934693
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
46944694
ce = op_array->scope;
4695-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4695+
/* scope is NULL for closures. */
4696+
if (ce) {
4697+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4698+
}
46964699
op1_addr = 0;
46974700
on_this = 1;
46984701
} else {
@@ -4783,7 +4786,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
47834786
if (opline->op1_type == IS_UNUSED) {
47844787
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
47854788
ce = op_array->scope;
4786-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4789+
/* scope is NULL for closures. */
4790+
if (ce) {
4791+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4792+
}
47874793
op1_addr = 0;
47884794
on_this = 1;
47894795
} else {
@@ -4863,7 +4869,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
48634869
if (opline->op1_type == IS_UNUSED) {
48644870
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
48654871
ce = op_array->scope;
4866-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4872+
/* scope is NULL for closures. */
4873+
if (ce) {
4874+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
4875+
}
48674876
op1_addr = 0;
48684877
on_this = 1;
48694878
} else {
@@ -5930,7 +5939,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
59305939
if (opline->op1_type == IS_UNUSED) {
59315940
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
59325941
ce = op_array->scope;
5933-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
5942+
/* scope is NULL for closures. */
5943+
if (ce) {
5944+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
5945+
}
59345946
op1_addr = 0;
59355947
on_this = 1;
59365948
} else {
@@ -6209,7 +6221,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
62096221
if (opline->op1_type == IS_UNUSED) {
62106222
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
62116223
ce = op_array->scope;
6212-
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
6224+
/* scope is NULL for closures. */
6225+
if (ce) {
6226+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
6227+
}
62136228
op1_addr = 0;
62146229
on_this = 1;
62156230
} else {

ext/opcache/jit/zend_jit_vm_helpers.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,12 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
692692
}
693693
}
694694
op1_type |= flags;
695+
} else if (opline->op1_type == IS_UNUSED && (op_array->fn_flags & ZEND_ACC_CLOSURE)) {
696+
uint32_t op1_flags = ZEND_VM_OP1_FLAGS(zend_get_opcode_flags(opline->opcode));
697+
if ((op1_flags & ZEND_VM_OP_MASK) == ZEND_VM_OP_THIS) {
698+
op1_type = IS_OBJECT;
699+
ce1 = Z_OBJCE(EX(This));
700+
}
695701
}
696702
if (opline->op2_type & (IS_TMP_VAR|IS_VAR|IS_CV)
697703
&& opline->opcode != ZEND_INSTANCEOF

0 commit comments

Comments
 (0)