mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
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
This commit is contained in:
@@ -313,9 +313,11 @@ static bool zend_is_not_imported(zend_string *name) {
|
||||
return !FC(imports) || zend_hash_find_ptr_lc(FC(imports), name) == NULL;
|
||||
}
|
||||
|
||||
void zend_oparray_context_begin(zend_oparray_context *prev_context) /* {{{ */
|
||||
void zend_oparray_context_begin(zend_oparray_context *prev_context, zend_op_array *op_array) /* {{{ */
|
||||
{
|
||||
*prev_context = CG(context);
|
||||
CG(context).prev = CG(context).op_array ? prev_context : NULL;
|
||||
CG(context).op_array = op_array;
|
||||
CG(context).opcodes_size = INITIAL_OP_ARRAY_SIZE;
|
||||
CG(context).vars_size = 0;
|
||||
CG(context).literals_size = 0;
|
||||
@@ -2920,11 +2922,21 @@ static bool is_global_var_fetch(zend_ast *ast)
|
||||
|
||||
static bool this_guaranteed_exists(void) /* {{{ */
|
||||
{
|
||||
zend_op_array *op_array = CG(active_op_array);
|
||||
/* Instance methods always have a $this.
|
||||
* This also includes closures that have a scope and use $this. */
|
||||
return op_array->scope != NULL
|
||||
&& (op_array->fn_flags & ZEND_ACC_STATIC) == 0;
|
||||
zend_oparray_context *ctx = &CG(context);
|
||||
while (ctx) {
|
||||
/* Instance methods always have a $this.
|
||||
* This also includes closures that have a scope and use $this. */
|
||||
zend_op_array *op_array = ctx->op_array;
|
||||
if (op_array->fn_flags & ZEND_ACC_STATIC) {
|
||||
return false;
|
||||
} else if (op_array->scope) {
|
||||
return true;
|
||||
} else if (!(op_array->fn_flags & ZEND_ACC_CLOSURE)) {
|
||||
return false;
|
||||
}
|
||||
ctx = ctx->prev;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -7869,7 +7881,7 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel)
|
||||
op_array->fn_flags |= ZEND_ACC_TOP_LEVEL;
|
||||
}
|
||||
|
||||
zend_oparray_context_begin(&orig_oparray_context);
|
||||
zend_oparray_context_begin(&orig_oparray_context, op_array);
|
||||
|
||||
{
|
||||
/* Push a separator to the loop variable stack */
|
||||
|
||||
@@ -190,6 +190,8 @@ typedef struct _zend_live_range {
|
||||
|
||||
/* Compilation context that is different for each op array. */
|
||||
typedef struct _zend_oparray_context {
|
||||
struct _zend_oparray_context *prev;
|
||||
zend_op_array *op_array;
|
||||
uint32_t opcodes_size;
|
||||
int vars_size;
|
||||
int literals_size;
|
||||
@@ -802,7 +804,7 @@ void init_compiler(void);
|
||||
void shutdown_compiler(void);
|
||||
void zend_init_compiler_data_structures(void);
|
||||
|
||||
void zend_oparray_context_begin(zend_oparray_context *prev_context);
|
||||
void zend_oparray_context_begin(zend_oparray_context *prev_context, zend_op_array *op_array);
|
||||
void zend_oparray_context_end(zend_oparray_context *prev_context);
|
||||
void zend_file_context_begin(zend_file_context *prev_context);
|
||||
void zend_file_context_end(zend_file_context *prev_context);
|
||||
|
||||
@@ -614,7 +614,7 @@ static zend_op_array *zend_compile(int type)
|
||||
}
|
||||
|
||||
zend_file_context_begin(&original_file_context);
|
||||
zend_oparray_context_begin(&original_oparray_context);
|
||||
zend_oparray_context_begin(&original_oparray_context, op_array);
|
||||
zend_compile_top_stmt(CG(ast));
|
||||
CG(zend_lineno) = last_lineno;
|
||||
zend_emit_final_return(type == ZEND_USER_FUNCTION);
|
||||
|
||||
@@ -1742,7 +1742,10 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
|
||||
if (opline->op1_type == IS_UNUSED) {
|
||||
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
|
||||
ce = op_array->scope;
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
/* scope is NULL for closures. */
|
||||
if (ce) {
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
}
|
||||
op1_addr = 0;
|
||||
on_this = 1;
|
||||
} else {
|
||||
@@ -1790,7 +1793,10 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
|
||||
if (opline->op1_type == IS_UNUSED) {
|
||||
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
|
||||
ce = op_array->scope;
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
/* scope is NULL for closures. */
|
||||
if (ce) {
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
}
|
||||
op1_addr = 0;
|
||||
on_this = 1;
|
||||
} else {
|
||||
@@ -1831,7 +1837,10 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
|
||||
if (opline->op1_type == IS_UNUSED) {
|
||||
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
|
||||
ce = op_array->scope;
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
/* scope is NULL for closures. */
|
||||
if (ce) {
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
}
|
||||
op1_addr = 0;
|
||||
on_this = 1;
|
||||
} else {
|
||||
@@ -2305,7 +2314,10 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
|
||||
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
|
||||
op1_addr = 0;
|
||||
ce = op_array->scope;
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
/* scope is NULL for closures. */
|
||||
if (ce) {
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
}
|
||||
on_this = 1;
|
||||
} else {
|
||||
op1_info = OP1_INFO();
|
||||
@@ -2456,7 +2468,10 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
|
||||
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
|
||||
op1_addr = 0;
|
||||
ce = op_array->scope;
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
/* scope is NULL for closures. */
|
||||
if (ce) {
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
}
|
||||
on_this = 1;
|
||||
} else {
|
||||
op1_info = OP1_INFO();
|
||||
|
||||
@@ -4692,7 +4692,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
if (opline->op1_type == IS_UNUSED) {
|
||||
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
|
||||
ce = op_array->scope;
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
/* scope is NULL for closures. */
|
||||
if (ce) {
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
}
|
||||
op1_addr = 0;
|
||||
on_this = 1;
|
||||
} else {
|
||||
@@ -4783,7 +4786,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
if (opline->op1_type == IS_UNUSED) {
|
||||
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
|
||||
ce = op_array->scope;
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
/* scope is NULL for closures. */
|
||||
if (ce) {
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
}
|
||||
op1_addr = 0;
|
||||
on_this = 1;
|
||||
} else {
|
||||
@@ -4863,7 +4869,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
if (opline->op1_type == IS_UNUSED) {
|
||||
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
|
||||
ce = op_array->scope;
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
/* scope is NULL for closures. */
|
||||
if (ce) {
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
}
|
||||
op1_addr = 0;
|
||||
on_this = 1;
|
||||
} else {
|
||||
@@ -5930,7 +5939,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
if (opline->op1_type == IS_UNUSED) {
|
||||
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
|
||||
ce = op_array->scope;
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
/* scope is NULL for closures. */
|
||||
if (ce) {
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
}
|
||||
op1_addr = 0;
|
||||
on_this = 1;
|
||||
} else {
|
||||
@@ -6209,7 +6221,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
|
||||
if (opline->op1_type == IS_UNUSED) {
|
||||
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
|
||||
ce = op_array->scope;
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
/* scope is NULL for closures. */
|
||||
if (ce) {
|
||||
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
|
||||
}
|
||||
op1_addr = 0;
|
||||
on_this = 1;
|
||||
} else {
|
||||
|
||||
@@ -692,6 +692,12 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
|
||||
}
|
||||
}
|
||||
op1_type |= flags;
|
||||
} else if (opline->op1_type == IS_UNUSED && (op_array->fn_flags & ZEND_ACC_CLOSURE)) {
|
||||
uint32_t op1_flags = ZEND_VM_OP1_FLAGS(zend_get_opcode_flags(opline->opcode));
|
||||
if ((op1_flags & ZEND_VM_OP_MASK) == ZEND_VM_OP_THIS) {
|
||||
op1_type = IS_OBJECT;
|
||||
ce1 = Z_OBJCE(EX(This));
|
||||
}
|
||||
}
|
||||
if (opline->op2_type & (IS_TMP_VAR|IS_VAR|IS_CV)
|
||||
&& opline->opcode != ZEND_INSTANCEOF
|
||||
|
||||
Reference in New Issue
Block a user