Skip to content

Commit cfd0bfb

Browse files
committed
Reference dynamic functions through dynamic_defs
1 parent 4414fd9 commit cfd0bfb

13 files changed

+134
-97
lines changed

Zend/zend_compile.c

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,28 +1072,22 @@ static zend_never_inline ZEND_COLD ZEND_NORETURN void do_bind_function_error(zen
10721072
}
10731073
}
10741074

1075-
ZEND_API zend_result do_bind_function(zval *lcname) /* {{{ */
1075+
ZEND_API zend_result do_bind_function(zend_function *func, zval *lcname) /* {{{ */
10761076
{
1077-
zend_function *function;
1078-
zval *rtd_key, *zv;
1079-
1080-
rtd_key = lcname + 1;
1081-
zv = zend_hash_find_ex(EG(function_table), Z_STR_P(rtd_key), 1);
1082-
if (UNEXPECTED(!zv)) {
1083-
do_bind_function_error(Z_STR_P(lcname), NULL, 0);
1077+
zend_function *added_func = zend_hash_add_ptr(EG(function_table), Z_STR_P(lcname), func);
1078+
if (UNEXPECTED(!added_func)) {
1079+
do_bind_function_error(Z_STR_P(lcname), &func->op_array, 0);
10841080
return FAILURE;
10851081
}
1086-
function = (zend_function*)Z_PTR_P(zv);
1087-
if (UNEXPECTED(function->common.fn_flags & ZEND_ACC_PRELOADED)
1088-
&& !(CG(compiler_options) & ZEND_COMPILE_PRELOAD)) {
1089-
zv = zend_hash_add(EG(function_table), Z_STR_P(lcname), zv);
1090-
} else {
1091-
zv = zend_hash_set_bucket_key(EG(function_table), (Bucket*)zv, Z_STR_P(lcname));
1082+
1083+
if (func->op_array.refcount) {
1084+
++*func->op_array.refcount;
10921085
}
1093-
if (UNEXPECTED(!zv)) {
1094-
do_bind_function_error(Z_STR_P(lcname), &function->op_array, 0);
1095-
return FAILURE;
1086+
if (func->common.function_name) {
1087+
zend_string_addref(func->common.function_name);
10961088
}
1089+
/* We can't addref static_variables here :(
1090+
* We make sure it's NULLed when destroyed though. */
10971091
return SUCCESS;
10981092
}
10991093
/* }}} */
@@ -6901,9 +6895,18 @@ zend_string *zend_begin_method_decl(zend_op_array *op_array, zend_string *name,
69016895
}
69026896
/* }}} */
69036897

6898+
static uint32_t zend_add_dynamic_func_def(zend_op_array *def) {
6899+
zend_op_array *op_array = CG(active_op_array);
6900+
uint32_t def_offset = op_array->num_dynamic_func_defs++;
6901+
op_array->dynamic_func_defs = erealloc(
6902+
op_array->dynamic_func_defs, op_array->num_dynamic_func_defs * sizeof(zend_op_array *));
6903+
op_array->dynamic_func_defs[def_offset] = def;
6904+
return def_offset;
6905+
}
6906+
69046907
static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_ast_decl *decl, bool toplevel) /* {{{ */
69056908
{
6906-
zend_string *unqualified_name, *name, *lcname, *key;
6909+
zend_string *unqualified_name, *name, *lcname;
69076910
zend_op *opline;
69086911

69096912
unqualified_name = decl->name;
@@ -6939,25 +6942,16 @@ static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_as
69396942
return;
69406943
}
69416944

6942-
/* Generate RTD keys until we find one that isn't in use yet. */
6943-
key = NULL;
6944-
do {
6945-
zend_tmp_string_release(key);
6946-
key = zend_build_runtime_definition_key(lcname, decl->start_lineno);
6947-
} while (!zend_hash_add_ptr(CG(function_table), key, op_array));
6948-
6945+
uint32_t func_ref = zend_add_dynamic_func_def(op_array);
69496946
if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
69506947
opline = zend_emit_op_tmp(result, ZEND_DECLARE_LAMBDA_FUNCTION, NULL, NULL);
6951-
opline->extended_value = zend_alloc_cache_slot();
6952-
opline->op1_type = IS_CONST;
6953-
LITERAL_STR(opline->op1, key);
6948+
opline->op2.num = func_ref;
69546949
} else {
69556950
opline = get_next_op();
69566951
opline->opcode = ZEND_DECLARE_FUNCTION;
69576952
opline->op1_type = IS_CONST;
69586953
LITERAL_STR(opline->op1, zend_string_copy(lcname));
6959-
/* RTD key is placed after lcname literal in op1 */
6960-
zend_add_literal_string(&key);
6954+
opline->op2.num = func_ref;
69616955
}
69626956
zend_string_release_ex(lcname, 0);
69636957
}

Zend/zend_compile.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,13 @@ struct _zend_op_array {
446446
zend_string *doc_comment;
447447

448448
int last_literal;
449+
uint32_t num_dynamic_func_defs;
449450
zval *literals;
450451

452+
/* Functions and classes that are declared dynamically are stored here and
453+
* referenced by index from opcodes. */
454+
zend_op_array **dynamic_func_defs;
455+
451456
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
452457
};
453458

@@ -768,7 +773,7 @@ bool zend_handle_encoding_declaration(zend_ast *ast);
768773
/* parser-driven code generators */
769774
void zend_do_free(znode *op1);
770775

771-
ZEND_API zend_result do_bind_function(zval *lcname);
776+
ZEND_API zend_result do_bind_function(zend_function *func, zval *lcname);
772777
ZEND_API zend_result do_bind_class(zval *lcname, zend_string *lc_parent_name);
773778
ZEND_API uint32_t zend_build_delayed_early_binding_list(const zend_op_array *op_array);
774779
ZEND_API void zend_do_delayed_early_binding(zend_op_array *op_array, uint32_t first_early_binding_opline);

Zend/zend_opcode.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz
8585
op_array->last_literal = 0;
8686
op_array->literals = NULL;
8787

88+
op_array->num_dynamic_func_defs = 0;
89+
op_array->dynamic_func_defs = NULL;
90+
8891
ZEND_MAP_PTR_INIT(op_array->run_time_cache, NULL);
8992
op_array->cache_size = zend_op_array_extension_handles * sizeof(void*);
9093

@@ -462,6 +465,7 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
462465
if (ht && !(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
463466
if (GC_DELREF(ht) == 0) {
464467
zend_array_destroy(ht);
468+
ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
465469
}
466470
}
467471
}
@@ -541,6 +545,12 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
541545
}
542546
efree(arg_info);
543547
}
548+
if (op_array->num_dynamic_func_defs) {
549+
for (i = 0; i < op_array->num_dynamic_func_defs; i++) {
550+
destroy_op_array(op_array->dynamic_func_defs[i]);
551+
}
552+
efree(op_array->dynamic_func_defs);
553+
}
544554
}
545555

546556
static void zend_update_extended_stmts(zend_op_array *op_array)

Zend/zend_vm_def.h

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7566,12 +7566,14 @@ ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY, CACHE_SLOT)
75667566
ZEND_VM_NEXT_OPCODE();
75677567
}
75687568

7569-
ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, ANY)
7569+
ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, UNUSED)
75707570
{
7571+
zend_function *func;
75717572
USE_OPLINE
75727573

75737574
SAVE_OPLINE();
7574-
do_bind_function(RT_CONSTANT(opline, opline->op1));
7575+
func = (zend_function *) EX(func)->op_array.dynamic_func_defs[opline->op2.num];
7576+
do_bind_function(func, RT_CONSTANT(opline, opline->op1));
75757577
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
75767578
}
75777579

@@ -7836,23 +7838,14 @@ ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST)
78367838
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
78377839
}
78387840

7839-
ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED, CACHE_SLOT)
7841+
ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED)
78407842
{
78417843
USE_OPLINE
78427844
zend_function *func;
7843-
zval *zfunc;
78447845
zval *object;
78457846
zend_class_entry *called_scope;
78467847

7847-
func = CACHED_PTR(opline->extended_value);
7848-
if (UNEXPECTED(func == NULL)) {
7849-
zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
7850-
ZEND_ASSERT(zfunc != NULL);
7851-
func = Z_FUNC_P(zfunc);
7852-
ZEND_ASSERT(func->type == ZEND_USER_FUNCTION);
7853-
CACHE_PTR(opline->extended_value, func);
7854-
}
7855-
7848+
func = (zend_function *) EX(func)->op_array.dynamic_func_defs[opline->op2.num];
78567849
if (Z_TYPE(EX(This)) == IS_OBJECT) {
78577850
called_scope = Z_OBJCE(EX(This));
78587851
if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_STATIC) ||

Zend/zend_vm_execute.h

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2813,15 +2813,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_ANON_CLASS_SPEC_HANDLE
28132813
ZEND_VM_NEXT_OPCODE();
28142814
}
28152815

2816-
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_FUNCTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
2817-
{
2818-
USE_OPLINE
2819-
2820-
SAVE_OPLINE();
2821-
do_bind_function(RT_CONSTANT(opline, opline->op1));
2822-
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
2823-
}
2824-
28252816
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_TICKS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
28262817
{
28272818
USE_OPLINE
@@ -3718,6 +3709,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_UNUSED_HAND
37183709
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
37193710
}
37203711

3712+
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_FUNCTION_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
3713+
{
3714+
zend_function *func;
3715+
USE_OPLINE
3716+
3717+
SAVE_OPLINE();
3718+
func = (zend_function *) EX(func)->op_array.dynamic_func_defs[opline->op2.num];
3719+
do_bind_function(func, RT_CONSTANT(opline, opline->op1));
3720+
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
3721+
}
3722+
37213723
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
37223724
{
37233725
USE_OPLINE
@@ -10149,19 +10151,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_C
1014910151
{
1015010152
USE_OPLINE
1015110153
zend_function *func;
10152-
zval *zfunc;
1015310154
zval *object;
1015410155
zend_class_entry *called_scope;
1015510156

10156-
func = CACHED_PTR(opline->extended_value);
10157-
if (UNEXPECTED(func == NULL)) {
10158-
zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
10159-
ZEND_ASSERT(zfunc != NULL);
10160-
func = Z_FUNC_P(zfunc);
10161-
ZEND_ASSERT(func->type == ZEND_USER_FUNCTION);
10162-
CACHE_PTR(opline->extended_value, func);
10163-
}
10164-
10157+
func = (zend_function *) EX(func)->op_array.dynamic_func_defs[opline->op2.num];
1016510158
if (Z_TYPE(EX(This)) == IS_OBJECT) {
1016610159
called_scope = Z_OBJCE(EX(This));
1016710160
if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_STATIC) ||
@@ -53117,7 +53110,7 @@ ZEND_API void execute_ex(zend_execute_data *ex)
5311753110
(void*)&&ZEND_MAKE_REF_SPEC_VAR_UNUSED_LABEL,
5311853111
(void*)&&ZEND_NULL_LABEL,
5311953112
(void*)&&ZEND_MAKE_REF_SPEC_CV_UNUSED_LABEL,
53120-
(void*)&&ZEND_DECLARE_FUNCTION_SPEC_LABEL,
53113+
(void*)&&ZEND_DECLARE_FUNCTION_SPEC_UNUSED_LABEL,
5312153114
(void*)&&ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_LABEL,
5312253115
(void*)&&ZEND_DECLARE_CONST_SPEC_CONST_CONST_LABEL,
5312353116
(void*)&&ZEND_DECLARE_CLASS_SPEC_CONST_LABEL,
@@ -54586,10 +54579,6 @@ ZEND_API void execute_ex(zend_execute_data *ex)
5458654579
VM_TRACE(ZEND_DECLARE_ANON_CLASS_SPEC)
5458754580
ZEND_DECLARE_ANON_CLASS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
5458854581
HYBRID_BREAK();
54589-
HYBRID_CASE(ZEND_DECLARE_FUNCTION_SPEC):
54590-
VM_TRACE(ZEND_DECLARE_FUNCTION_SPEC)
54591-
ZEND_DECLARE_FUNCTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
54592-
HYBRID_BREAK();
5459354582
HYBRID_CASE(ZEND_TICKS_SPEC):
5459454583
VM_TRACE(ZEND_TICKS_SPEC)
5459554584
ZEND_TICKS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
@@ -54670,6 +54659,10 @@ ZEND_API void execute_ex(zend_execute_data *ex)
5467054659
VM_TRACE(ZEND_RECV_VARIADIC_SPEC_UNUSED)
5467154660
ZEND_RECV_VARIADIC_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
5467254661
HYBRID_BREAK();
54662+
HYBRID_CASE(ZEND_DECLARE_FUNCTION_SPEC_UNUSED):
54663+
VM_TRACE(ZEND_DECLARE_FUNCTION_SPEC_UNUSED)
54664+
ZEND_DECLARE_FUNCTION_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
54665+
HYBRID_BREAK();
5467354666
HYBRID_CASE(ZEND_INIT_DYNAMIC_CALL_SPEC_CV):
5467454667
VM_TRACE(ZEND_INIT_DYNAMIC_CALL_SPEC_CV)
5467554668
ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
@@ -61145,7 +61138,7 @@ void zend_vm_init(void)
6114561138
ZEND_MAKE_REF_SPEC_VAR_UNUSED_HANDLER,
6114661139
ZEND_NULL_HANDLER,
6114761140
ZEND_MAKE_REF_SPEC_CV_UNUSED_HANDLER,
61148-
ZEND_DECLARE_FUNCTION_SPEC_HANDLER,
61141+
ZEND_DECLARE_FUNCTION_SPEC_UNUSED_HANDLER,
6114961142
ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER,
6115061143
ZEND_DECLARE_CONST_SPEC_CONST_CONST_HANDLER,
6115161144
ZEND_DECLARE_CLASS_SPEC_CONST_HANDLER,

Zend/zend_vm_handlers.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1157,7 +1157,7 @@
11571157
_(2283, ZEND_GENERATOR_CREATE_SPEC) \
11581158
_(2286, ZEND_MAKE_REF_SPEC_VAR_UNUSED) \
11591159
_(2288, ZEND_MAKE_REF_SPEC_CV_UNUSED) \
1160-
_(2289, ZEND_DECLARE_FUNCTION_SPEC) \
1160+
_(2289, ZEND_DECLARE_FUNCTION_SPEC_UNUSED) \
11611161
_(2290, ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED) \
11621162
_(2291, ZEND_DECLARE_CONST_SPEC_CONST_CONST) \
11631163
_(2292, ZEND_DECLARE_CLASS_SPEC_CONST) \

Zend/zend_vm_opcodes.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,8 @@ static uint32_t zend_vm_opcodes_flags[201] = {
368368
0x00047305,
369369
0x00000000,
370370
0x00000101,
371-
0x00000000,
372-
0x00040103,
371+
0x00000100,
372+
0x00000103,
373373
0x00000303,
374374
0x00000003,
375375
0x00000303,

ext/opcache/Optimizer/compact_literals.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,6 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
241241
case ZEND_RECV_INIT:
242242
LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1);
243243
break;
244-
case ZEND_DECLARE_FUNCTION:
245-
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 2);
246-
break;
247244
case ZEND_DECLARE_CLASS:
248245
case ZEND_DECLARE_CLASS_DELAYED:
249246
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 2);
@@ -776,7 +773,6 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
776773
bind_var_slot[opline->op2.constant] = opline->extended_value;
777774
}
778775
break;
779-
case ZEND_DECLARE_LAMBDA_FUNCTION:
780776
case ZEND_DECLARE_ANON_CLASS:
781777
case ZEND_DECLARE_CLASS_DELAYED:
782778
opline->extended_value = cache_size;

ext/opcache/Optimizer/zend_optimizer.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,16 +1367,24 @@ static bool needs_live_range(zend_op_array *op_array, zend_op *def_opline) {
13671367
return (type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) != 0;
13681368
}
13691369

1370+
static void zend_foreach_op_array_helper(
1371+
zend_op_array *op_array, zend_op_array_func_t func, void *context) {
1372+
func(op_array, context);
1373+
for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
1374+
func(op_array->dynamic_func_defs[i], context);
1375+
}
1376+
}
1377+
13701378
void zend_foreach_op_array(zend_script *script, zend_op_array_func_t func, void *context)
13711379
{
13721380
zend_class_entry *ce;
13731381
zend_string *key;
13741382
zend_op_array *op_array;
13751383

1376-
func(&script->main_op_array, context);
1384+
zend_foreach_op_array_helper(&script->main_op_array, func, context);
13771385

13781386
ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
1379-
func(op_array, context);
1387+
zend_foreach_op_array_helper(op_array, func, context);
13801388
} ZEND_HASH_FOREACH_END();
13811389

13821390
ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
@@ -1387,7 +1395,7 @@ void zend_foreach_op_array(zend_script *script, zend_op_array_func_t func, void
13871395
if (op_array->scope == ce
13881396
&& op_array->type == ZEND_USER_FUNCTION
13891397
&& !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
1390-
func(op_array, context);
1398+
zend_foreach_op_array_helper(op_array, func, context);
13911399
}
13921400
} ZEND_HASH_FOREACH_END();
13931401
} ZEND_HASH_FOREACH_END();

0 commit comments

Comments
 (0)