Skip to content

Commit 36ef123

Browse files
committed
Also cache the computed stack size in INIT_FCALL_BY_NAME
The computed stack size only depends on the function definition fbc and the number of opcodes in extended_value, and that doesn't change. INIT_FCALL_BY_NAME is used when the function definition is not available when a file is being compiled, commonly due to the function being declared in a different file. Precomputing the stack size is an optimization already done by INIT_FCALL used when the function is known. Replacing `hallo` in Zend/micro_bench.php with a require_once to load `hallo` from a different file in a build with opcache enabled (but not the jit): ``` Before (best run) - total time and subtracting time needed for an empty loop empty_loop 0.162 func_elsewhere() 0.615 0.475 After (best run): empty_loop 0.159 (unaffected, just noise) func_elsewhere() 0.579 0.420 ```
1 parent 443a420 commit 36ef123

File tree

5 files changed

+20
-10
lines changed

5 files changed

+20
-10
lines changed

Zend/Optimizer/compact_literals.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
634634
opline->result.num = func_slot[opline->op2.constant];
635635
} else {
636636
opline->result.num = cache_size;
637-
cache_size += sizeof(void *);
637+
cache_size += opline->opcode == ZEND_INIT_FCALL_BY_NAME ? 2 * sizeof(void *) : sizeof(void *);
638638
func_slot[opline->op2.constant] = opline->result.num;
639639
}
640640
break;

Zend/Optimizer/zend_optimizer.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ bool zend_optimizer_update_op2_const(zend_op_array *op_array,
369369
drop_leading_backslash(val);
370370
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
371371
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
372-
opline->result.num = alloc_cache_slots(op_array, 1);
372+
opline->result.num = alloc_cache_slots(op_array, 2);
373373
break;
374374
case ZEND_ASSIGN_STATIC_PROP:
375375
case ZEND_ASSIGN_STATIC_PROP_REF:
@@ -422,7 +422,7 @@ bool zend_optimizer_update_op2_const(zend_op_array *op_array,
422422
drop_leading_backslash(val);
423423
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
424424
zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
425-
opline->result.num = alloc_cache_slots(op_array, 1);
425+
opline->result.num = alloc_cache_slots(op_array, 2);
426426
} else {
427427
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
428428
}

Zend/zend_compile.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3706,7 +3706,7 @@ static void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast
37063706
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
37073707
opline->op2_type = IS_CONST;
37083708
opline->op2.constant = zend_add_func_name_literal(str);
3709-
opline->result.num = zend_alloc_cache_slot();
3709+
opline->result.num = zend_alloc_cache_slots(2);
37103710
}
37113711
} else {
37123712
zend_emit_op(NULL, ZEND_INIT_DYNAMIC_CALL, NULL, name_node);

Zend/zend_vm_def.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3749,7 +3749,8 @@ ZEND_VM_HOT_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
37493749
zval *function_name, *func;
37503750
zend_execute_data *call;
37513751

3752-
fbc = CACHED_PTR(opline->result.num);
3752+
int num = opline->result.num;
3753+
fbc = CACHED_PTR(num);
37533754
if (UNEXPECTED(fbc == NULL)) {
37543755
function_name = (zval*)RT_CONSTANT(opline, opline->op2);
37553756
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(function_name+1));
@@ -3760,9 +3761,13 @@ ZEND_VM_HOT_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
37603761
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
37613762
init_func_run_time_cache(&fbc->op_array);
37623763
}
3763-
CACHE_PTR(opline->result.num, fbc);
3764+
CACHE_PTR(num, fbc);
3765+
CACHE_PTR(num + sizeof(void*), (void*)(uintptr_t)zend_vm_calc_used_stack(opline->extended_value, fbc));
37643766
}
3765-
call = _zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
3767+
/* Because zend_vm_calc_used_stack depends only on the number of arguments and the function definition fbc,
3768+
* it can be cached in the run time cache. */
3769+
call = _zend_vm_stack_push_call_frame_ex(
3770+
(uint32_t)(uintptr_t)CACHED_PTR(num + sizeof(void*)), ZEND_CALL_NESTED_FUNCTION,
37663771
fbc, opline->extended_value, NULL);
37673772
call->prev_execute_data = EX(call);
37683773
EX(call) = call;

Zend/zend_vm_execute.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3574,7 +3574,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME
35743574
zval *function_name, *func;
35753575
zend_execute_data *call;
35763576

3577-
fbc = CACHED_PTR(opline->result.num);
3577+
int num = opline->result.num;
3578+
fbc = CACHED_PTR(num);
35783579
if (UNEXPECTED(fbc == NULL)) {
35793580
function_name = (zval*)RT_CONSTANT(opline, opline->op2);
35803581
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(function_name+1));
@@ -3585,9 +3586,13 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME
35853586
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
35863587
init_func_run_time_cache(&fbc->op_array);
35873588
}
3588-
CACHE_PTR(opline->result.num, fbc);
3589+
CACHE_PTR(num, fbc);
3590+
CACHE_PTR(num + sizeof(void*), (void*)(uintptr_t)zend_vm_calc_used_stack(opline->extended_value, fbc));
35893591
}
3590-
call = _zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
3592+
/* Because zend_vm_calc_used_stack depends only on the number of arguments and the function definition fbc,
3593+
* it can be cached in the run time cache. */
3594+
call = _zend_vm_stack_push_call_frame_ex(
3595+
(uint32_t)(uintptr_t)CACHED_PTR(num + sizeof(void*)), ZEND_CALL_NESTED_FUNCTION,
35913596
fbc, opline->extended_value, NULL);
35923597
call->prev_execute_data = EX(call);
35933598
EX(call) = call;

0 commit comments

Comments
 (0)