Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Zend/Optimizer/compact_literals.c
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
}
break;
case ZEND_CALLABLE_CONVERT:
case ZEND_DECLARE_LAMBDA_FUNCTION:
if (opline->extended_value != (uint32_t)-1) {
opline->extended_value = cache_size;
cache_size += sizeof(void *);
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/partial_application/pipe_optimization_004.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ $_main:
; (lines=3, args=0, vars=0, tmps=%d)
; (after optimizer)
; %s:1-10
0000 T0 = DECLARE_LAMBDA_FUNCTION 0
0000 T0 = DECLARE_LAMBDA_FUNCTION %d 0
0001 FREE T0
0002 RETURN int(1)

Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/partial_application/pipe_optimization_007.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ $_main:
; (lines=3, args=0, vars=0, tmps=%d)
; (after optimizer)
; %s:1-10
0000 T0 = DECLARE_LAMBDA_FUNCTION 0
0000 T0 = DECLARE_LAMBDA_FUNCTION %d 0
0001 FREE T0
0002 RETURN int(1)

Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/partial_application/pipe_optimization_008.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ $_main:
; (lines=4, args=0, vars=1, tmps=%d)
; (after optimizer)
; %s:1-10
0000 T1 = DECLARE_LAMBDA_FUNCTION 0
0000 T1 = DECLARE_LAMBDA_FUNCTION %d 0
0001 BIND_LEXICAL T1 CV0($a)
0002 FREE T1
0003 RETURN int(1)
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/partial_application/pipe_optimization_013.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ $_main:
; (lines=4, args=0, vars=1, tmps=%d)
; (after optimizer)
; %s:1-9
0000 T1 = DECLARE_LAMBDA_FUNCTION 0
0000 T1 = DECLARE_LAMBDA_FUNCTION %d 0
0001 BIND_LEXICAL T1 CV0($b)
0002 FREE T1
0003 RETURN int(1)
Expand Down
18 changes: 18 additions & 0 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -8942,6 +8942,7 @@ static zend_string *zend_begin_func_decl(znode *result, zend_op_array *op_array,
if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
opline = zend_emit_op_tmp(result, ZEND_DECLARE_LAMBDA_FUNCTION, NULL, NULL);
opline->op2.num = func_ref;
opline->extended_value = (uint32_t)-1;
} else {
opline = get_next_op();
opline->opcode = ZEND_DECLARE_FUNCTION;
Expand Down Expand Up @@ -9131,6 +9132,23 @@ static zend_op_array *zend_compile_func_decl_ex(

zend_compile_stmt(stmt_ast);

if (decl->kind == ZEND_AST_CLOSURE || decl->kind == ZEND_AST_ARROW_FUNC) {
zend_op_array *declaring_op_array = orig_oparray_context.op_array;

if ((op_array->fn_flags & ZEND_ACC_STATIC)
&& !op_array->static_variables
/* Don't cache closures in main, as those would leak without a proper
* cleanup mechanism. */
&& declaring_op_array->function_name
&& declaring_op_array->last) {
zend_op *declare_lambda_op = &declaring_op_array->opcodes[declaring_op_array->last - 1];
if (declare_lambda_op->opcode == ZEND_DECLARE_LAMBDA_FUNCTION) {
declare_lambda_op->extended_value = declaring_op_array->cache_size;
declaring_op_array->cache_size += sizeof(void *);
}
}
}

if (is_method) {
CG(zend_lineno) = decl->start_lineno;
zend_check_magic_method_implementation(
Expand Down
10 changes: 10 additions & 0 deletions Zend/zend_execute_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ void init_executor(void) /* {{{ */

zend_hash_init(&EG(callable_convert_cache), 8, NULL, ZVAL_PTR_DTOR, 0);
zend_hash_init(&EG(partial_function_application_cache), 8, NULL, zend_partial_op_array_dtor, 0);
zend_stack_init(&EG(lambda_cache), sizeof(zend_object *));

EG(active) = 1;
}
Expand Down Expand Up @@ -268,6 +269,14 @@ void shutdown_destructors(void) /* {{{ */
}
/* }}} */

static void lambda_dtor(zend_object **closure_ptr)
{
zend_object *closure = *closure_ptr;
if (GC_DELREF(closure) == 0) {
zend_objects_store_del(closure);
}
}

/* Free values held by the executor. */
ZEND_API void zend_shutdown_executor_values(bool fast_shutdown)
{
Expand Down Expand Up @@ -421,6 +430,7 @@ ZEND_API void zend_shutdown_executor_values(bool fast_shutdown)

zend_hash_clean(&EG(callable_convert_cache));
zend_hash_clean(&EG(partial_function_application_cache));
zend_stack_clean(&EG(lambda_cache), (void (*)(void *)) lambda_dtor, 1);

#if ZEND_DEBUG
if (!CG(unclean_shutdown)) {
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ struct _zend_executor_globals {

HashTable callable_convert_cache;
HashTable partial_function_application_cache;
zend_stack lambda_cache;

void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};
Expand Down
17 changes: 15 additions & 2 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -8409,13 +8409,21 @@ ZEND_VM_HANDLER(210, ZEND_DECLARE_ATTRIBUTED_CONST, CONST, CONST)
ZEND_VM_NEXT_OPCODE_EX(1, 2);
}

ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, NUM)
ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, UNUSED, NUM, NUM|CACHE_SLOT)
{
USE_OPLINE
zend_function *func;
zval *object;
zend_class_entry *called_scope;

if (opline->extended_value != (uint32_t)-1) {
zend_object *closure = CACHED_PTR(opline->extended_value);
if (closure) {
ZVAL_OBJ_COPY(EX_VAR(opline->result.var), closure);
ZEND_VM_NEXT_OPCODE();
}
}

func = (zend_function *) EX(func)->op_array.dynamic_func_defs[opline->op2.num];
if (Z_TYPE(EX(This)) == IS_OBJECT) {
called_scope = Z_OBJCE(EX(This));
Expand All @@ -8432,7 +8440,12 @@ ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, NUM)
SAVE_OPLINE();
zend_create_closure(EX_VAR(opline->result.var), func,
EX(func)->op_array.scope, called_scope, object);

if (opline->extended_value != (uint32_t)-1) {
zend_object *closure = Z_OBJ_P(EX_VAR(opline->result.var));
GC_ADDREF(closure);
CACHE_PTR(opline->extended_value, closure);
zend_stack_push(&EG(lambda_cache), &closure);
}
ZEND_VM_NEXT_OPCODE();
}

Expand Down
150 changes: 88 additions & 62 deletions Zend/zend_vm_execute.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Zend/zend_vm_handlers.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Zend/zend_vm_opcodes.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ $_main:
; (lines=4, args=0, vars=1, tmps=%d)
; (after optimizer)
; %s:1-9
0000 T1 = DECLARE_LAMBDA_FUNCTION 0
0000 T1 = DECLARE_LAMBDA_FUNCTION %d 0
0001 BIND_LEXICAL T1 CV0($n)
0002 FREE T1
0003 RETURN int(1)
Expand Down
Loading
Loading