Skip to content

Commit 01d193f

Browse files
committed
Reference dynamic functions through dynamic_defs
1 parent 8e8e001 commit 01d193f

14 files changed

+177
-125
lines changed

Zend/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;

Zend/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();

Zend/zend_compile.c

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,27 +1091,19 @@ static zend_never_inline ZEND_COLD ZEND_NORETURN void do_bind_function_error(zen
10911091
}
10921092
}
10931093

1094-
ZEND_API zend_result do_bind_function(zval *lcname) /* {{{ */
1094+
ZEND_API zend_result do_bind_function(zend_function *func, zval *lcname) /* {{{ */
10951095
{
1096-
zend_function *function;
1097-
zval *rtd_key, *zv;
1098-
1099-
rtd_key = lcname + 1;
1100-
zv = zend_hash_find_ex(EG(function_table), Z_STR_P(rtd_key), 1);
1101-
if (UNEXPECTED(!zv)) {
1102-
do_bind_function_error(Z_STR_P(lcname), NULL, 0);
1096+
zend_function *added_func = zend_hash_add_ptr(EG(function_table), Z_STR_P(lcname), func);
1097+
if (UNEXPECTED(!added_func)) {
1098+
do_bind_function_error(Z_STR_P(lcname), &func->op_array, 0);
11031099
return FAILURE;
11041100
}
1105-
function = (zend_function*)Z_PTR_P(zv);
1106-
if (UNEXPECTED(function->common.fn_flags & ZEND_ACC_PRELOADED)
1107-
&& !(CG(compiler_options) & ZEND_COMPILE_PRELOAD)) {
1108-
zv = zend_hash_add(EG(function_table), Z_STR_P(lcname), zv);
1109-
} else {
1110-
zv = zend_hash_set_bucket_key(EG(function_table), (Bucket*)zv, Z_STR_P(lcname));
1101+
1102+
if (func->op_array.refcount) {
1103+
++*func->op_array.refcount;
11111104
}
1112-
if (UNEXPECTED(!zv)) {
1113-
do_bind_function_error(Z_STR_P(lcname), &function->op_array, 0);
1114-
return FAILURE;
1105+
if (func->common.function_name) {
1106+
zend_string_addref(func->common.function_name);
11151107
}
11161108
return SUCCESS;
11171109
}
@@ -6954,9 +6946,18 @@ zend_string *zend_begin_method_decl(zend_op_array *op_array, zend_string *name,
69546946
}
69556947
/* }}} */
69566948

6949+
static uint32_t zend_add_dynamic_func_def(zend_op_array *def) {
6950+
zend_op_array *op_array = CG(active_op_array);
6951+
uint32_t def_offset = op_array->num_dynamic_func_defs++;
6952+
op_array->dynamic_func_defs = erealloc(
6953+
op_array->dynamic_func_defs, op_array->num_dynamic_func_defs * sizeof(zend_op_array *));
6954+
op_array->dynamic_func_defs[def_offset] = def;
6955+
return def_offset;
6956+
}
6957+
69576958
static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_ast_decl *decl, bool toplevel) /* {{{ */
69586959
{
6959-
zend_string *unqualified_name, *name, *lcname, *key;
6960+
zend_string *unqualified_name, *name, *lcname;
69606961
zend_op *opline;
69616962

69626963
unqualified_name = decl->name;
@@ -6992,25 +6993,16 @@ static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_as
69926993
return;
69936994
}
69946995

6995-
/* Generate RTD keys until we find one that isn't in use yet. */
6996-
key = NULL;
6997-
do {
6998-
zend_tmp_string_release(key);
6999-
key = zend_build_runtime_definition_key(lcname, decl->start_lineno);
7000-
} while (!zend_hash_add_ptr(CG(function_table), key, op_array));
7001-
6996+
uint32_t func_ref = zend_add_dynamic_func_def(op_array);
70026997
if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
70036998
opline = zend_emit_op_tmp(result, ZEND_DECLARE_LAMBDA_FUNCTION, NULL, NULL);
7004-
opline->extended_value = zend_alloc_cache_slot();
7005-
opline->op1_type = IS_CONST;
7006-
LITERAL_STR(opline->op1, key);
6999+
opline->op2.num = func_ref;
70077000
} else {
70087001
opline = get_next_op();
70097002
opline->opcode = ZEND_DECLARE_FUNCTION;
70107003
opline->op1_type = IS_CONST;
70117004
LITERAL_STR(opline->op1, zend_string_copy(lcname));
7012-
/* RTD key is placed after lcname literal in op1 */
7013-
zend_add_literal_string(&key);
7005+
opline->op2.num = func_ref;
70147006
}
70157007
zend_string_release_ex(lcname, 0);
70167008
}

Zend/zend_compile.h

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

458458
int last_literal;
459+
uint32_t num_dynamic_func_defs;
459460
zval *literals;
460461

462+
/* Functions that are declared dynamically are stored here and
463+
* referenced by index from opcodes. */
464+
zend_op_array **dynamic_func_defs;
465+
461466
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
462467
};
463468

@@ -781,7 +786,7 @@ bool zend_handle_encoding_declaration(zend_ast *ast);
781786
/* parser-driven code generators */
782787
void zend_do_free(znode *op1);
783788

784-
ZEND_API zend_result do_bind_function(zval *lcname);
789+
ZEND_API zend_result do_bind_function(zend_function *func, zval *lcname);
785790
ZEND_API zend_result do_bind_class(zval *lcname, zend_string *lc_parent_name);
786791
ZEND_API uint32_t zend_build_delayed_early_binding_list(const zend_op_array *op_array);
787792
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

@@ -519,6 +522,7 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
519522
HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
520523
if (ht) {
521524
zend_array_destroy(ht);
525+
ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
522526
}
523527
}
524528

@@ -600,6 +604,12 @@ ZEND_API void destroy_op_array(zend_op_array *op_array)
600604
if (op_array->static_variables) {
601605
zend_array_destroy(op_array->static_variables);
602606
}
607+
if (op_array->num_dynamic_func_defs) {
608+
for (i = 0; i < op_array->num_dynamic_func_defs; i++) {
609+
destroy_op_array(op_array->dynamic_func_defs[i]);
610+
}
611+
efree(op_array->dynamic_func_defs);
612+
}
603613
}
604614

605615
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
@@ -7583,12 +7583,14 @@ ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY, CACHE_SLOT)
75837583
ZEND_VM_NEXT_OPCODE();
75847584
}
75857585

7586-
ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, ANY)
7586+
ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, NUM)
75877587
{
7588+
zend_function *func;
75887589
USE_OPLINE
75897590

75907591
SAVE_OPLINE();
7591-
do_bind_function(RT_CONSTANT(opline, opline->op1));
7592+
func = (zend_function *) EX(func)->op_array.dynamic_func_defs[opline->op2.num];
7593+
do_bind_function(func, RT_CONSTANT(opline, opline->op1));
75927594
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
75937595
}
75947596

@@ -7853,23 +7855,14 @@ ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST)
78537855
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
78547856
}
78557857

7856-
ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED, CACHE_SLOT)
7858+
ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, NUM)
78577859
{
78587860
USE_OPLINE
78597861
zend_function *func;
7860-
zval *zfunc;
78617862
zval *object;
78627863
zend_class_entry *called_scope;
78637864

7864-
func = CACHED_PTR(opline->extended_value);
7865-
if (UNEXPECTED(func == NULL)) {
7866-
zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
7867-
ZEND_ASSERT(zfunc != NULL);
7868-
func = Z_FUNC_P(zfunc);
7869-
ZEND_ASSERT(func->type == ZEND_USER_FUNCTION);
7870-
CACHE_PTR(opline->extended_value, func);
7871-
}
7872-
7865+
func = (zend_function *) EX(func)->op_array.dynamic_func_defs[opline->op2.num];
78737866
if (Z_TYPE(EX(This)) == IS_OBJECT) {
78747867
called_scope = Z_OBJCE(EX(This));
78757868
if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_STATIC) ||

Zend/zend_vm_execute.h

Lines changed: 35 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2828,10 +2828,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_ANON_CLASS_SPEC_HANDLE
28282828

28292829
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_FUNCTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
28302830
{
2831+
zend_function *func;
28312832
USE_OPLINE
28322833

28332834
SAVE_OPLINE();
2834-
do_bind_function(RT_CONSTANT(opline, opline->op1));
2835+
func = (zend_function *) EX(func)->op_array.dynamic_func_defs[opline->op2.num];
2836+
do_bind_function(func, RT_CONSTANT(opline, opline->op1));
28352837
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
28362838
}
28372839

@@ -5152,6 +5154,32 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_CLASS_SPEC_CONST_HANDL
51525154
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
51535155
}
51545156

5157+
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
5158+
{
5159+
USE_OPLINE
5160+
zend_function *func;
5161+
zval *object;
5162+
zend_class_entry *called_scope;
5163+
5164+
func = (zend_function *) EX(func)->op_array.dynamic_func_defs[opline->op2.num];
5165+
if (Z_TYPE(EX(This)) == IS_OBJECT) {
5166+
called_scope = Z_OBJCE(EX(This));
5167+
if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_STATIC) ||
5168+
(EX(func)->common.fn_flags & ZEND_ACC_STATIC))) {
5169+
object = NULL;
5170+
} else {
5171+
object = &EX(This);
5172+
}
5173+
} else {
5174+
called_scope = Z_CE(EX(This));
5175+
object = NULL;
5176+
}
5177+
zend_create_closure(EX_VAR(opline->result.var), func,
5178+
EX(func)->op_array.scope, called_scope, object);
5179+
5180+
ZEND_VM_NEXT_OPCODE();
5181+
}
5182+
51555183
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
51565184
{
51575185
USE_OPLINE
@@ -10207,41 +10235,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_U
1020710235
}
1020810236

1020910237
/* No specialization for op_types (CONST|TMPVAR|CV, UNUSED|CLASS_FETCH|CONST|VAR) */
10210-
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
10211-
{
10212-
USE_OPLINE
10213-
zend_function *func;
10214-
zval *zfunc;
10215-
zval *object;
10216-
zend_class_entry *called_scope;
10217-
10218-
func = CACHED_PTR(opline->extended_value);
10219-
if (UNEXPECTED(func == NULL)) {
10220-
zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
10221-
ZEND_ASSERT(zfunc != NULL);
10222-
func = Z_FUNC_P(zfunc);
10223-
ZEND_ASSERT(func->type == ZEND_USER_FUNCTION);
10224-
CACHE_PTR(opline->extended_value, func);
10225-
}
10226-
10227-
if (Z_TYPE(EX(This)) == IS_OBJECT) {
10228-
called_scope = Z_OBJCE(EX(This));
10229-
if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_STATIC) ||
10230-
(EX(func)->common.fn_flags & ZEND_ACC_STATIC))) {
10231-
object = NULL;
10232-
} else {
10233-
object = &EX(This);
10234-
}
10235-
} else {
10236-
called_scope = Z_CE(EX(This));
10237-
object = NULL;
10238-
}
10239-
zend_create_closure(EX_VAR(opline->result.var), func,
10240-
EX(func)->op_array.scope, called_scope, object);
10241-
10242-
ZEND_VM_NEXT_OPCODE();
10243-
}
10244-
1024510238
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
1024610239
{
1024710240
USE_OPLINE
@@ -53314,7 +53307,7 @@ ZEND_API void execute_ex(zend_execute_data *ex)
5331453307
(void*)&&ZEND_NULL_LABEL,
5331553308
(void*)&&ZEND_MAKE_REF_SPEC_CV_UNUSED_LABEL,
5331653309
(void*)&&ZEND_DECLARE_FUNCTION_SPEC_LABEL,
53317-
(void*)&&ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_LABEL,
53310+
(void*)&&ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_LABEL,
5331853311
(void*)&&ZEND_DECLARE_CONST_SPEC_CONST_CONST_LABEL,
5331953312
(void*)&&ZEND_DECLARE_CLASS_SPEC_CONST_LABEL,
5332053313
(void*)&&ZEND_DECLARE_CLASS_DELAYED_SPEC_CONST_CONST_LABEL,
@@ -55133,6 +55126,10 @@ ZEND_API void execute_ex(zend_execute_data *ex)
5513355126
VM_TRACE(ZEND_DECLARE_CLASS_SPEC_CONST)
5513455127
ZEND_DECLARE_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
5513555128
HYBRID_BREAK();
55129+
HYBRID_CASE(ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST):
55130+
VM_TRACE(ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST)
55131+
ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
55132+
HYBRID_BREAK();
5513655133
HYBRID_CASE(ZEND_YIELD_FROM_SPEC_CONST):
5513755134
VM_TRACE(ZEND_YIELD_FROM_SPEC_CONST)
5513855135
ZEND_YIELD_FROM_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
@@ -55609,10 +55606,6 @@ ZEND_API void execute_ex(zend_execute_data *ex)
5560955606
VM_TRACE(ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_UNUSED)
5561055607
ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
5561155608
HYBRID_BREAK();
55612-
HYBRID_CASE(ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED):
55613-
VM_TRACE(ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED)
55614-
ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
55615-
HYBRID_BREAK();
5561655609
HYBRID_CASE(ZEND_YIELD_SPEC_CONST_UNUSED):
5561755610
VM_TRACE(ZEND_YIELD_SPEC_CONST_UNUSED)
5561855611
ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
@@ -61342,7 +61335,7 @@ void zend_vm_init(void)
6134261335
ZEND_NULL_HANDLER,
6134361336
ZEND_MAKE_REF_SPEC_CV_UNUSED_HANDLER,
6134461337
ZEND_DECLARE_FUNCTION_SPEC_HANDLER,
61345-
ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER,
61338+
ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_HANDLER,
6134661339
ZEND_DECLARE_CONST_SPEC_CONST_CONST_HANDLER,
6134761340
ZEND_DECLARE_CLASS_SPEC_CONST_HANDLER,
6134861341
ZEND_DECLARE_CLASS_DELAYED_SPEC_CONST_CONST_HANDLER,

Zend/zend_vm_handlers.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1158,7 +1158,7 @@
11581158
_(2286, ZEND_MAKE_REF_SPEC_VAR_UNUSED) \
11591159
_(2288, ZEND_MAKE_REF_SPEC_CV_UNUSED) \
11601160
_(2289, ZEND_DECLARE_FUNCTION_SPEC) \
1161-
_(2290, ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED) \
1161+
_(2290, ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST) \
11621162
_(2291, ZEND_DECLARE_CONST_SPEC_CONST_CONST) \
11631163
_(2292, ZEND_DECLARE_CLASS_SPEC_CONST) \
11641164
_(2293, ZEND_DECLARE_CLASS_DELAYED_SPEC_CONST_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+
0x00001000,
372+
0x00001003,
373373
0x00000303,
374374
0x00000003,
375375
0x00000303,

0 commit comments

Comments
 (0)