From 2cf93032ee0f9a8defa3df289258fa2a0a12da8d Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 25 Dec 2021 21:51:29 +0100 Subject: [PATCH] Sink op_array scope case into get_class_entry() This handles references to the current class through its name rather than self (and for cases where is is not linked yet and thus not covered by the context lookup). Rather than handling this only for FETCH_CLASS_CONSTANT optimization, integrate this into the generic get_class_entry() utility. --- Zend/Optimizer/dfa_pass.c | 2 +- Zend/Optimizer/escape_analysis.c | 4 ++-- Zend/Optimizer/pass1.c | 13 ++++--------- Zend/Optimizer/zend_inference.c | 9 +++++---- Zend/Optimizer/zend_optimizer.c | 9 +++++++-- Zend/Optimizer/zend_optimizer_internal.h | 3 ++- Zend/Optimizer/zend_ssa.c | 2 +- 7 files changed, 22 insertions(+), 20 deletions(-) diff --git a/Zend/Optimizer/dfa_pass.c b/Zend/Optimizer/dfa_pass.c index 1f846959bc0..0218a77d3f9 100644 --- a/Zend/Optimizer/dfa_pass.c +++ b/Zend/Optimizer/dfa_pass.c @@ -293,7 +293,7 @@ static inline bool can_elide_return_type_check( ZEND_TYPE_FOREACH(arg_info->type, single_type) { if (ZEND_TYPE_HAS_NAME(*single_type)) { zend_string *lcname = zend_string_tolower(ZEND_TYPE_NAME(*single_type)); - zend_class_entry *ce = zend_optimizer_get_class_entry(script, lcname); + zend_class_entry *ce = zend_optimizer_get_class_entry(script, op_array, lcname); zend_string_release(lcname); bool result = ce && safe_instanceof(use_info->ce, ce); if (result == !is_intersection) { diff --git a/Zend/Optimizer/escape_analysis.c b/Zend/Optimizer/escape_analysis.c index e13015ceb7c..e66fc4f9e71 100644 --- a/Zend/Optimizer/escape_analysis.c +++ b/Zend/Optimizer/escape_analysis.c @@ -160,7 +160,7 @@ static bool is_allocation_def(zend_op_array *op_array, zend_ssa *ssa, int def, i /* objects with destructors should escape */ if (opline->op1_type == IS_CONST) { zend_class_entry *ce = zend_optimizer_get_class_entry( - script, Z_STR_P(CRT_CONSTANT(opline->op1)+1)); + script, op_array, Z_STR_P(CRT_CONSTANT(opline->op1)+1)); uint32_t forbidden_flags = /* These flags will always cause an exception */ ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS @@ -228,7 +228,7 @@ static bool is_local_def(zend_op_array *op_array, zend_ssa *ssa, int def, int va /* objects with destructors should escape */ if (opline->op1_type == IS_CONST) { zend_class_entry *ce = zend_optimizer_get_class_entry( - script, Z_STR_P(CRT_CONSTANT(opline->op1)+1)); + script, op_array, Z_STR_P(CRT_CONSTANT(opline->op1)+1)); if (ce && !ce->create_object && !ce->constructor && !ce->destructor && !ce->__get && !ce->__set && !ce->parent) { return 1; diff --git a/Zend/Optimizer/pass1.c b/Zend/Optimizer/pass1.c index b330ca24b4d..1aad01cb2f1 100644 --- a/Zend/Optimizer/pass1.c +++ b/Zend/Optimizer/pass1.c @@ -179,15 +179,10 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx) if (opline->op1_type == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) { /* for A::B */ - if (op_array->scope && - zend_string_equals_ci(Z_STR(ZEND_OP1_LITERAL(opline)), op_array->scope->name)) { - ce = op_array->scope; - } else { - ce = zend_optimizer_get_class_entry( - ctx->script, Z_STR(op_array->literals[opline->op1.constant + 1])); - if (!ce) { - break; - } + ce = zend_optimizer_get_class_entry( + ctx->script, op_array, Z_STR(op_array->literals[opline->op1.constant + 1])); + if (!ce) { + break; } } else if (op_array->scope && opline->op1_type == IS_UNUSED && diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c index 52d093db116..c7df495c0ae 100644 --- a/Zend/Optimizer/zend_inference.c +++ b/Zend/Optimizer/zend_inference.c @@ -2143,7 +2143,8 @@ static uint32_t zend_convert_type(const zend_script *script, zend_type type, zen * we use a plain object type for class unions. */ if (ZEND_TYPE_HAS_NAME(type)) { zend_string *lcname = zend_string_tolower(ZEND_TYPE_NAME(type)); - *pce = zend_optimizer_get_class_entry(script, lcname); + // TODO: Pass through op_array. + *pce = zend_optimizer_get_class_entry(script, NULL, lcname); zend_string_release_ex(lcname, 0); } } @@ -2231,7 +2232,7 @@ static zend_property_info *zend_fetch_static_prop_info(const zend_script *script } } else if (opline->op2_type == IS_CONST) { zval *zv = CRT_CONSTANT(opline->op2); - ce = zend_optimizer_get_class_entry(script, Z_STR_P(zv + 1)); + ce = zend_optimizer_get_class_entry(script, op_array, Z_STR_P(zv + 1)); } if (ce) { @@ -3015,7 +3016,7 @@ static zend_always_inline zend_result _zend_update_type_info( } else if (opline->op2_type == IS_CONST) { zval *zv = CRT_CONSTANT(opline->op2); if (Z_TYPE_P(zv) == IS_STRING) { - ce = zend_optimizer_get_class_entry(script, Z_STR_P(zv+1)); + ce = zend_optimizer_get_class_entry(script, op_array, Z_STR_P(zv+1)); UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_op->result_def); } else { UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def); @@ -3027,7 +3028,7 @@ static zend_always_inline zend_result _zend_update_type_info( case ZEND_NEW: tmp = MAY_BE_RC1|MAY_BE_RCN|MAY_BE_OBJECT; if (opline->op1_type == IS_CONST && - (ce = zend_optimizer_get_class_entry(script, Z_STR_P(CRT_CONSTANT(opline->op1)+1))) != NULL) { + (ce = zend_optimizer_get_class_entry(script, op_array, Z_STR_P(CRT_CONSTANT(opline->op1)+1))) != NULL) { UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_op->result_def); } else if ((t1 & MAY_BE_CLASS) && ssa_op->op1_use >= 0 && ssa_var_info[ssa_op->op1_use].ce) { UPDATE_SSA_OBJ_TYPE(ssa_var_info[ssa_op->op1_use].ce, ssa_var_info[ssa_op->op1_use].is_instanceof, ssa_op->result_def); diff --git a/Zend/Optimizer/zend_optimizer.c b/Zend/Optimizer/zend_optimizer.c index 9de7a944da1..1abeeefeaca 100644 --- a/Zend/Optimizer/zend_optimizer.c +++ b/Zend/Optimizer/zend_optimizer.c @@ -694,7 +694,8 @@ void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_ } } -zend_class_entry *zend_optimizer_get_class_entry(const zend_script *script, zend_string *lcname) { +zend_class_entry *zend_optimizer_get_class_entry( + const zend_script *script, const zend_op_array *op_array, zend_string *lcname) { zend_class_entry *ce = script ? zend_hash_find_ptr(&script->class_table, lcname) : NULL; if (ce) { return ce; @@ -705,6 +706,10 @@ zend_class_entry *zend_optimizer_get_class_entry(const zend_script *script, zend return ce; } + if (op_array && op_array->scope && zend_string_equals_ci(op_array->scope->name, lcname)) { + return op_array->scope; + } + return NULL; } @@ -713,7 +718,7 @@ static zend_class_entry *get_class_entry_from_op1( if (opline->op1_type == IS_CONST) { zval *op1 = CRT_CONSTANT(opline->op1); if (Z_TYPE_P(op1) == IS_STRING) { - return zend_optimizer_get_class_entry(script, Z_STR_P(op1 + 1)); + return zend_optimizer_get_class_entry(script, op_array, Z_STR_P(op1 + 1)); } } else if (opline->op1_type == IS_UNUSED && op_array->scope && !(op_array->scope->ce_flags & ZEND_ACC_TRAIT) diff --git a/Zend/Optimizer/zend_optimizer_internal.h b/Zend/Optimizer/zend_optimizer_internal.h index bd4367eaf27..550b911052a 100644 --- a/Zend/Optimizer/zend_optimizer_internal.h +++ b/Zend/Optimizer/zend_optimizer_internal.h @@ -96,7 +96,8 @@ bool zend_optimizer_replace_by_const(zend_op_array *op_array, uint32_t var, zval *val); zend_op *zend_optimizer_get_loop_var_def(const zend_op_array *op_array, zend_op *free_opline); -zend_class_entry *zend_optimizer_get_class_entry(const zend_script *script, zend_string *lcname); +zend_class_entry *zend_optimizer_get_class_entry( + const zend_script *script, const zend_op_array *op_array, zend_string *lcname); void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx); void zend_optimizer_pass3(zend_op_array *op_array, zend_optimizer_ctx *ctx); diff --git a/Zend/Optimizer/zend_ssa.c b/Zend/Optimizer/zend_ssa.c index 9ca2e11a6f7..98f60468a0e 100644 --- a/Zend/Optimizer/zend_ssa.c +++ b/Zend/Optimizer/zend_ssa.c @@ -527,7 +527,7 @@ static void place_essa_pis( (opline-1)->op2_type == IS_CONST) { int var = EX_VAR_TO_NUM((opline-1)->op1.var); zend_string *lcname = Z_STR_P(CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2) + 1); - zend_class_entry *ce = zend_optimizer_get_class_entry(script, lcname); + zend_class_entry *ce = zend_optimizer_get_class_entry(script, op_array, lcname); if (!ce) { continue; }