Skip to content

Commit d5943f5

Browse files
committed
Use run-time cache to avoid repeatable hash lookups when creating anonymous functions and classes
1 parent b065fbd commit d5943f5

File tree

5 files changed

+63
-34
lines changed

5 files changed

+63
-34
lines changed

Zend/zend_compile.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5851,6 +5851,7 @@ static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_as
58515851

58525852
if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
58535853
opline = zend_emit_op_tmp(result, ZEND_DECLARE_LAMBDA_FUNCTION, NULL, NULL);
5854+
opline->extended_value = zend_alloc_cache_slot();
58545855
opline->op1_type = IS_CONST;
58555856
LITERAL_STR(opline->op1, key);
58565857
} else {
@@ -6470,6 +6471,7 @@ zend_op *zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
64706471

64716472
if (decl->flags & ZEND_ACC_ANON_CLASS) {
64726473
opline->opcode = ZEND_DECLARE_ANON_CLASS;
6474+
opline->extended_value = zend_alloc_cache_slot();
64736475
opline->result_type = IS_VAR;
64746476
opline->result.var = get_temporary_variable();
64756477

Zend/zend_vm_def.h

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7264,24 +7264,28 @@ ZEND_VM_HANDLER(145, ZEND_DECLARE_CLASS_DELAYED, CONST, CONST)
72647264
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
72657265
}
72667266

7267-
ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY)
7267+
ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY, CACHE_SLOT)
72687268
{
72697269
zval *zv;
72707270
zend_class_entry *ce;
72717271
USE_OPLINE
72727272

7273-
zv = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
7274-
ZEND_ASSERT(zv != NULL);
7275-
ce = Z_CE_P(zv);
7276-
Z_CE_P(EX_VAR(opline->result.var)) = ce;
7277-
7278-
if (ce->ce_flags & ZEND_ACC_LINKED) {
7279-
ZEND_VM_NEXT_OPCODE();
7280-
} else {
7281-
SAVE_OPLINE();
7282-
zend_do_link_class(ce, (OP2_TYPE == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL);
7283-
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
7273+
ce = CACHED_PTR(opline->extended_value);
7274+
if (UNEXPECTED(ce == NULL)) {
7275+
zv = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
7276+
ZEND_ASSERT(zv != NULL);
7277+
ce = Z_CE_P(zv);
7278+
if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
7279+
SAVE_OPLINE();
7280+
zend_do_link_class(ce, (OP2_TYPE == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL);
7281+
if (UNEXPECTED(EG(exception))) {
7282+
HANDLE_EXCEPTION();
7283+
}
7284+
}
7285+
CACHE_PTR(opline->extended_value, ce);
72847286
}
7287+
Z_CE_P(EX_VAR(opline->result.var)) = ce;
7288+
ZEND_VM_NEXT_OPCODE();
72857289
}
72867290

72877291
ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, ANY)
@@ -7550,19 +7554,26 @@ ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST)
75507554
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
75517555
}
75527556

7553-
ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED)
7557+
ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED, CACHE_SLOT)
75547558
{
75557559
USE_OPLINE
7560+
zend_function *func;
75567561
zval *zfunc;
75577562
zval *object;
75587563
zend_class_entry *called_scope;
75597564

7560-
zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
7561-
ZEND_ASSERT(zfunc != NULL && Z_FUNC_P(zfunc)->type == ZEND_USER_FUNCTION);
7565+
func = CACHED_PTR(opline->extended_value);
7566+
if (UNEXPECTED(func == NULL)) {
7567+
zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
7568+
ZEND_ASSERT(zfunc != NULL);
7569+
func = Z_FUNC_P(zfunc);
7570+
ZEND_ASSERT(func->type == ZEND_USER_FUNCTION);
7571+
CACHE_PTR(opline->extended_value, func);
7572+
}
75627573

75637574
if (Z_TYPE(EX(This)) == IS_OBJECT) {
75647575
called_scope = Z_OBJCE(EX(This));
7565-
if (UNEXPECTED((Z_FUNC_P(zfunc)->common.fn_flags & ZEND_ACC_STATIC) ||
7576+
if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_STATIC) ||
75667577
(EX(func)->common.fn_flags & ZEND_ACC_STATIC))) {
75677578
object = NULL;
75687579
} else {
@@ -7572,7 +7583,7 @@ ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED)
75727583
called_scope = Z_CE(EX(This));
75737584
object = NULL;
75747585
}
7575-
zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc),
7586+
zend_create_closure(EX_VAR(opline->result.var), func,
75767587
EX(func)->op_array.scope, called_scope, object);
75777588

75787589
ZEND_VM_NEXT_OPCODE();

Zend/zend_vm_execute.h

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2430,18 +2430,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_ANON_CLASS_SPEC_HANDLE
24302430
zend_class_entry *ce;
24312431
USE_OPLINE
24322432

2433-
zv = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
2434-
ZEND_ASSERT(zv != NULL);
2435-
ce = Z_CE_P(zv);
2436-
Z_CE_P(EX_VAR(opline->result.var)) = ce;
2437-
2438-
if (ce->ce_flags & ZEND_ACC_LINKED) {
2439-
ZEND_VM_NEXT_OPCODE();
2440-
} else {
2441-
SAVE_OPLINE();
2442-
zend_do_link_class(ce, (opline->op2_type == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL);
2443-
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
2433+
ce = CACHED_PTR(opline->extended_value);
2434+
if (UNEXPECTED(ce == NULL)) {
2435+
zv = zend_hash_find_ex(EG(class_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
2436+
ZEND_ASSERT(zv != NULL);
2437+
ce = Z_CE_P(zv);
2438+
if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
2439+
SAVE_OPLINE();
2440+
zend_do_link_class(ce, (opline->op2_type == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL);
2441+
if (UNEXPECTED(EG(exception))) {
2442+
HANDLE_EXCEPTION();
2443+
}
2444+
}
2445+
CACHE_PTR(opline->extended_value, ce);
24442446
}
2447+
Z_CE_P(EX_VAR(opline->result.var)) = ce;
2448+
ZEND_VM_NEXT_OPCODE();
24452449
}
24462450

24472451
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_FUNCTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
@@ -9395,16 +9399,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_U
93959399
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
93969400
{
93979401
USE_OPLINE
9402+
zend_function *func;
93989403
zval *zfunc;
93999404
zval *object;
94009405
zend_class_entry *called_scope;
94019406

9402-
zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
9403-
ZEND_ASSERT(zfunc != NULL && Z_FUNC_P(zfunc)->type == ZEND_USER_FUNCTION);
9407+
func = CACHED_PTR(opline->extended_value);
9408+
if (UNEXPECTED(func == NULL)) {
9409+
zfunc = zend_hash_find_ex(EG(function_table), Z_STR_P(RT_CONSTANT(opline, opline->op1)), 1);
9410+
ZEND_ASSERT(zfunc != NULL);
9411+
func = Z_FUNC_P(zfunc);
9412+
ZEND_ASSERT(func->type == ZEND_USER_FUNCTION);
9413+
CACHE_PTR(opline->extended_value, func);
9414+
}
94049415

94059416
if (Z_TYPE(EX(This)) == IS_OBJECT) {
94069417
called_scope = Z_OBJCE(EX(This));
9407-
if (UNEXPECTED((Z_FUNC_P(zfunc)->common.fn_flags & ZEND_ACC_STATIC) ||
9418+
if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_STATIC) ||
94089419
(EX(func)->common.fn_flags & ZEND_ACC_STATIC))) {
94099420
object = NULL;
94109421
} else {
@@ -9414,7 +9425,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_C
94149425
called_scope = Z_CE(EX(This));
94159426
object = NULL;
94169427
}
9417-
zend_create_closure(EX_VAR(opline->result.var), Z_FUNC_P(zfunc),
9428+
zend_create_closure(EX_VAR(opline->result.var), func,
94189429
EX(func)->op_array.scope, called_scope, object);
94199430

94209431
ZEND_VM_NEXT_OPCODE();

Zend/zend_vm_opcodes.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,11 +363,11 @@ static uint32_t zend_vm_opcodes_flags[195] = {
363363
0x00000000,
364364
0x00000101,
365365
0x00000000,
366-
0x00000103,
366+
0x00040103,
367367
0x00000303,
368368
0x00000003,
369369
0x00000303,
370-
0x00000000,
370+
0x00040000,
371371
0x00000000,
372372
0x00060757,
373373
0x00000000,

ext/opcache/Optimizer/compact_literals.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,11 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
770770
bind_var_slot[opline->op2.constant] = opline->extended_value;
771771
}
772772
break;
773+
case ZEND_DECLARE_LAMBDA_FUNCTION:
774+
case ZEND_DECLARE_ANON_CLASS:
775+
opline->extended_value = cache_size;
776+
cache_size += sizeof(void *);
777+
break;
773778
}
774779
opline++;
775780
}

0 commit comments

Comments
 (0)