Skip to content

Commit 6bd8f40

Browse files
committed
Move observer_declared_function_notify until after pass_two()
For early observing, there already exists a op_array_ctor hook on zend_extension. However the goal of the declared_function observer is noting the time when a fully defined function starts existing in the function_tables. This also prevents the observer being called in case there were compilation errors. Ultimately, this now gives a consistent behaviour with respect to how it works when opcache is enabled: - pass_two is done, opcodes and flags are all finalized. - similarly class_linked notifications also only happen once the class is actually finalized. - any extension wanting to delay the observer call may add the ZEND_COMPILE_IGNORE_OBSERVER compiler_option, then call it itself.
1 parent d3b2272 commit 6bd8f40

File tree

1 file changed

+24
-22
lines changed

1 file changed

+24
-22
lines changed

Zend/zend_compile.c

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7271,7 +7271,7 @@ static uint32_t zend_add_dynamic_func_def(zend_op_array *def) {
72717271
return def_offset;
72727272
}
72737273

7274-
static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_ast_decl *decl, bool toplevel) /* {{{ */
7274+
static zend_string *zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_ast_decl *decl, bool toplevel) /* {{{ */
72757275
{
72767276
zend_string *unqualified_name, *name, *lcname;
72777277
zend_op *opline;
@@ -7305,23 +7305,20 @@ static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_as
73057305
if (UNEXPECTED(zend_hash_add_ptr(CG(function_table), lcname, op_array) == NULL)) {
73067306
do_bind_function_error(lcname, op_array, 1);
73077307
}
7308-
zend_observer_function_declared_notify(op_array, lcname);
7309-
zend_string_release_ex(lcname, 0);
7310-
return;
7311-
}
7312-
7313-
uint32_t func_ref = zend_add_dynamic_func_def(op_array);
7314-
if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
7315-
opline = zend_emit_op_tmp(result, ZEND_DECLARE_LAMBDA_FUNCTION, NULL, NULL);
7316-
opline->op2.num = func_ref;
73177308
} else {
7318-
opline = get_next_op();
7319-
opline->opcode = ZEND_DECLARE_FUNCTION;
7320-
opline->op1_type = IS_CONST;
7321-
LITERAL_STR(opline->op1, zend_string_copy(lcname));
7322-
opline->op2.num = func_ref;
7309+
uint32_t func_ref = zend_add_dynamic_func_def(op_array);
7310+
if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
7311+
opline = zend_emit_op_tmp(result, ZEND_DECLARE_LAMBDA_FUNCTION, NULL, NULL);
7312+
opline->op2.num = func_ref;
7313+
} else {
7314+
opline = get_next_op();
7315+
opline->opcode = ZEND_DECLARE_FUNCTION;
7316+
opline->op1_type = IS_CONST;
7317+
LITERAL_STR(opline->op1, zend_string_copy(lcname));
7318+
opline->op2.num = func_ref;
7319+
}
73237320
}
7324-
zend_string_release_ex(lcname, 0);
7321+
return lcname;
73257322
}
73267323
/* }}} */
73277324

@@ -7333,7 +7330,7 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel)
73337330
zend_ast *stmt_ast = decl->child[2];
73347331
zend_ast *return_type_ast = decl->child[3];
73357332
bool is_method = decl->kind == ZEND_AST_METHOD;
7336-
zend_string *method_lcname = NULL;
7333+
zend_string *lcname = NULL;
73377334

73387335
zend_class_entry *orig_class_entry = CG(active_class_entry);
73397336
zend_op_array *orig_op_array = CG(active_op_array);
@@ -7362,9 +7359,9 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel)
73627359

73637360
if (is_method) {
73647361
bool has_body = stmt_ast != NULL;
7365-
method_lcname = zend_begin_method_decl(op_array, decl->name, has_body);
7362+
lcname = zend_begin_method_decl(op_array, decl->name, has_body);
73667363
} else {
7367-
zend_begin_func_decl(result, op_array, decl, toplevel);
7364+
lcname = zend_begin_func_decl(result, op_array, decl, toplevel);
73687365
if (decl->kind == ZEND_AST_ARROW_FUNC) {
73697366
find_implicit_binds(&info, params_ast, stmt_ast);
73707367
compile_implicit_lexical_binds(&info, result, op_array);
@@ -7407,7 +7404,7 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel)
74077404
}
74087405

74097406
zend_compile_params(params_ast, return_type_ast,
7410-
is_method && zend_string_equals_literal(method_lcname, ZEND_TOSTRING_FUNC_NAME) ? IS_STRING : 0);
7407+
is_method && zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME) ? IS_STRING : 0);
74117408
if (CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) {
74127409
zend_mark_function_as_generator();
74137410
zend_emit_op(NULL, ZEND_GENERATOR_CREATE, NULL, NULL);
@@ -7436,8 +7433,7 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel)
74367433
if (is_method) {
74377434
CG(zend_lineno) = decl->start_lineno;
74387435
zend_check_magic_method_implementation(
7439-
CG(active_class_entry), (zend_function *) op_array, method_lcname, E_COMPILE_ERROR);
7440-
zend_string_release_ex(method_lcname, 0);
7436+
CG(active_class_entry), (zend_function *) op_array, lcname, E_COMPILE_ERROR);
74417437
}
74427438

74437439
/* put the implicit return on the really last line */
@@ -7452,6 +7448,12 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel)
74527448
/* Pop the loop variable stack separator */
74537449
zend_stack_del_top(&CG(loop_var_stack));
74547450

7451+
if (toplevel) {
7452+
zend_observer_function_declared_notify(op_array, lcname);
7453+
}
7454+
7455+
zend_string_release_ex(lcname, 0);
7456+
74557457
CG(active_op_array) = orig_op_array;
74567458
CG(active_class_entry) = orig_class_entry;
74577459
}

0 commit comments

Comments
 (0)