From 759f4ecd8bb2c87babc3890dbf40c3003ee320e0 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 25 Jun 2019 11:26:29 +0300 Subject: [PATCH] Keep lowercased parent class name as second argument of DECLARE_CLASS to avoid extra work at run-time --- Zend/zend_compile.c | 17 +++++++++++++---- Zend/zend_compile.h | 2 +- Zend/zend_inheritance.c | 4 ++-- Zend/zend_inheritance.h | 2 +- Zend/zend_vm_def.h | 6 +++--- Zend/zend_vm_execute.h | 6 +++--- ext/opcache/Optimizer/compact_literals.c | 5 +++++ ext/opcache/ZendAccelerator.c | 2 +- 8 files changed, 29 insertions(+), 15 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index cb9419c7b8a..20501176487 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1057,7 +1057,7 @@ ZEND_API int do_bind_function(zval *lcname) /* {{{ */ } /* }}} */ -ZEND_API int do_bind_class(zval *lcname) /* {{{ */ +ZEND_API int do_bind_class(zval *lcname, zend_string *lc_parent_name) /* {{{ */ { zend_class_entry *ce; zval *rtd_key, *zv; @@ -1084,7 +1084,7 @@ ZEND_API int do_bind_class(zval *lcname) /* {{{ */ return FAILURE; } - zend_do_link_class(ce); + zend_do_link_class(ce, lc_parent_name); return SUCCESS; } /* }}} */ @@ -1151,9 +1151,11 @@ ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array, uint3 const zend_op *opline = &op_array->opcodes[opline_num]; zval *lcname = RT_CONSTANT(opline, opline->op1); zend_class_entry *ce = zend_hash_find_ptr(EG(class_table), Z_STR_P(lcname + 1)); - zend_class_entry *parent_ce = zend_lookup_class(ce->parent_name); + zend_string *lc_parent_name = Z_STR_P(RT_CONSTANT(opline, opline->op2)); + zend_class_entry *parent_ce = zend_lookup_class_ex(ce->parent_name, lc_parent_name, 0); + if (ce && parent_ce && zend_can_early_bind(ce, parent_ce)) { - do_bind_class(lcname); + do_bind_class(lcname, lc_parent_name); } opline_num = op_array->opcodes[opline_num].result.opline_num; } @@ -6458,6 +6460,13 @@ zend_op *zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */ opline = get_next_op(); + if (ce->parent_name) { + /* Lowercased parent name */ + zend_string *lc_parent_name = zend_string_tolower(ce->parent_name); + opline->op2_type = IS_CONST; + LITERAL_STR(opline->op2, lc_parent_name); + } + opline->op1_type = IS_CONST; LITERAL_STR(opline->op1, lcname); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index cfefe9ce310..6721612b4cf 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -751,7 +751,7 @@ zend_bool zend_handle_encoding_declaration(zend_ast *ast); void zend_do_free(znode *op1); ZEND_API int do_bind_function(zval *lcname); -ZEND_API int do_bind_class(zval *lcname); +ZEND_API int do_bind_class(zval *lcname, zend_string *lc_parent_name); ZEND_API uint32_t zend_build_delayed_early_binding_list(const zend_op_array *op_array); ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array, uint32_t first_early_binding_opline); diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index e62d990c18a..e107e851774 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -2362,11 +2362,11 @@ static void report_variance_errors(zend_class_entry *ce) { zend_hash_index_del(all_obligations, num_key); } -ZEND_API void zend_do_link_class(zend_class_entry *ce) /* {{{ */ +ZEND_API void zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name) /* {{{ */ { if (ce->parent_name) { zend_class_entry *parent = zend_fetch_class_by_name( - ce->parent_name, NULL, ZEND_FETCH_CLASS_ALLOW_UNLINKED); + ce->parent_name, lc_parent_name, ZEND_FETCH_CLASS_ALLOW_UNLINKED); if (!(parent->ce_flags & ZEND_ACC_LINKED)) { add_dependency_obligation(ce, parent); } diff --git a/Zend/zend_inheritance.h b/Zend/zend_inheritance.h index e2e37b82529..2ce6dec7d18 100644 --- a/Zend/zend_inheritance.h +++ b/Zend/zend_inheritance.h @@ -27,7 +27,7 @@ BEGIN_EXTERN_C() ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface); ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce); -ZEND_API void zend_do_link_class(zend_class_entry *ce); +ZEND_API void zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name); void zend_verify_abstract_class(zend_class_entry *ce); void zend_check_deprecated_constructor(const zend_class_entry *ce); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 3508cba5dd0..bd14092fb31 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -7030,7 +7030,7 @@ ZEND_VM_HANDLER(139, ZEND_DECLARE_CLASS, CONST, ANY) USE_OPLINE SAVE_OPLINE(); - do_bind_class(RT_CONSTANT(opline, opline->op1)); + do_bind_class(RT_CONSTANT(opline, opline->op1), (OP2_TYPE == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -7043,7 +7043,7 @@ ZEND_VM_HANDLER(145, ZEND_DECLARE_CLASS_DELAYED, CONST, ANY) if ((zce = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1)) == NULL || ((orig_zce = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)+1), 1)) != NULL && Z_CE_P(zce) != Z_CE_P(orig_zce))) { - do_bind_class(RT_CONSTANT(opline, opline->op1)); + do_bind_class(RT_CONSTANT(opline, opline->op1), (OP2_TYPE == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL); } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -7064,7 +7064,7 @@ ZEND_VM_HANDLER(171, ZEND_DECLARE_ANON_CLASS, ANY, ANY, JMP_ADDR) ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value); ZEND_VM_CONTINUE(); } - zend_do_link_class(ce); + zend_do_link_class(ce, (OP2_TYPE == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index b5e63d394f7..4f7aa5dc076 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2111,7 +2111,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_ANON_CLASS_SPEC_HANDLE ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value); ZEND_VM_CONTINUE(); } - zend_do_link_class(ce); + zend_do_link_class(ce, (opline->op2_type == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -4022,7 +4022,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_CLASS_SPEC_CONST_HANDL USE_OPLINE SAVE_OPLINE(); - do_bind_class(RT_CONSTANT(opline, opline->op1)); + do_bind_class(RT_CONSTANT(opline, opline->op1), (opline->op2_type == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -4035,7 +4035,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_CLASS_DELAYED_SPEC_CON if ((zce = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1)) == NULL || ((orig_zce = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)+1), 1)) != NULL && Z_CE_P(zce) != Z_CE_P(orig_zce))) { - do_bind_class(RT_CONSTANT(opline, opline->op1)); + do_bind_class(RT_CONSTANT(opline, opline->op1), (opline->op2_type == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL); } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c index ad5497f8d40..e5ba87d9893 100644 --- a/ext/opcache/Optimizer/compact_literals.c +++ b/ext/opcache/Optimizer/compact_literals.c @@ -270,9 +270,14 @@ literals_handle_static_prop: LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1); break; case ZEND_DECLARE_FUNCTION: + LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 2); + break; case ZEND_DECLARE_CLASS: case ZEND_DECLARE_CLASS_DELAYED: LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 2); + if (opline->op2_type == IS_CONST) { + LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1); + } break; case ZEND_ISSET_ISEMPTY_DIM_OBJ: case ZEND_ASSIGN_DIM: diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 60e44c6508c..86b6d5ce7c3 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -3582,7 +3582,7 @@ static void preload_link(void) } else { CG(zend_lineno) = ce->info.user.line_start; } - zend_do_link_class(ce); + zend_do_link_class(ce, NULL); CG(in_compilation) = 0; CG(compiled_filename) = NULL;