Skip to content

Commit 0001340

Browse files
committed
Allow using prototypes when optimizing arg passing
Closes GH-5193.
1 parent bd7a52c commit 0001340

File tree

4 files changed

+22
-10
lines changed

4 files changed

+22
-10
lines changed

ext/opcache/Optimizer/optimize_func_calls.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
typedef struct _optimizer_call_info {
4040
zend_function *func;
4141
zend_op *opline;
42+
zend_bool is_prototype;
4243
zend_bool try_inline;
4344
uint32_t func_arg_num;
4445
} optimizer_call_info;
@@ -172,9 +173,12 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
172173
case ZEND_INIT_METHOD_CALL:
173174
case ZEND_INIT_FCALL:
174175
case ZEND_NEW:
176+
/* The argument passing optimizations are valid for prototypes as well,
177+
* as inheritance cannot change between ref <-> non-ref arguments. */
175178
call_stack[call].func = zend_optimizer_get_called_func(
176-
ctx->script, op_array, opline);
177-
call_stack[call].try_inline = opline->opcode != ZEND_NEW;
179+
ctx->script, op_array, opline, &call_stack[call].is_prototype);
180+
call_stack[call].try_inline =
181+
!call_stack[call].is_prototype && opline->opcode != ZEND_NEW;
178182
/* break missing intentionally */
179183
case ZEND_INIT_DYNAMIC_CALL:
180184
case ZEND_INIT_USER_CALL:

ext/opcache/Optimizer/zend_call_graph.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_f
9393
int call = 0;
9494
zend_call_info **call_stack;
9595
ALLOCA_FLAG(use_heap);
96+
zend_bool is_prototype;
9697

9798
call_stack = do_alloca((op_array->last / 2) * sizeof(zend_call_info*), use_heap);
9899
call_info = NULL;
@@ -103,8 +104,9 @@ int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_f
103104
case ZEND_INIT_STATIC_METHOD_CALL:
104105
call_stack[call] = call_info;
105106
func = zend_optimizer_get_called_func(
106-
script, op_array, opline);
107-
if (func) {
107+
script, op_array, opline, &is_prototype);
108+
/* TODO: Support prototypes? */
109+
if (func && !is_prototype) {
108110
call_info = zend_arena_calloc(arena, 1, sizeof(zend_call_info) + (sizeof(zend_send_arg_info) * ((int)opline->extended_value - 1)));
109111
call_info->caller_op_array = op_array;
110112
call_info->caller_init_opline = opline;

ext/opcache/Optimizer/zend_optimizer.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -777,8 +777,9 @@ static zend_class_entry *get_class_entry_from_op1(
777777
}
778778

779779
zend_function *zend_optimizer_get_called_func(
780-
zend_script *script, zend_op_array *op_array, zend_op *opline)
780+
zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool *is_prototype)
781781
{
782+
*is_prototype = 0;
782783
switch (opline->opcode) {
783784
case ZEND_INIT_FCALL:
784785
{
@@ -825,7 +826,7 @@ zend_function *zend_optimizer_get_called_func(
825826
if (fbc) {
826827
zend_bool is_public = (fbc->common.fn_flags & ZEND_ACC_PUBLIC) != 0;
827828
zend_bool same_scope = fbc->common.scope == op_array->scope;
828-
if (is_public|| same_scope) {
829+
if (is_public || same_scope) {
829830
return fbc;
830831
}
831832
}
@@ -843,10 +844,15 @@ zend_function *zend_optimizer_get_called_func(
843844
zend_bool is_private = (fbc->common.fn_flags & ZEND_ACC_PRIVATE) != 0;
844845
zend_bool is_final = (fbc->common.fn_flags & ZEND_ACC_FINAL) != 0;
845846
zend_bool same_scope = fbc->common.scope == op_array->scope;
846-
if ((is_private && same_scope)
847-
|| (is_final && (!is_private || same_scope))) {
848-
return fbc;
847+
if (is_private) {
848+
/* Only use private method if in the same scope. We can't even use it
849+
* as a prototype, as it may be overridden with changed signature. */
850+
return same_scope ? fbc : NULL;
849851
}
852+
/* If the method is non-final, it may be overriden,
853+
* but only with a compatible method signature. */
854+
*is_prototype = !is_final;
855+
return fbc;
850856
}
851857
}
852858
break;

ext/opcache/Optimizer/zend_optimizer_internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
110110
void zend_optimizer_compact_vars(zend_op_array *op_array);
111111
int zend_optimizer_is_disabled_func(const char *name, size_t len);
112112
zend_function *zend_optimizer_get_called_func(
113-
zend_script *script, zend_op_array *op_array, zend_op *opline);
113+
zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool *is_prototype);
114114
uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args);
115115
void zend_optimizer_migrate_jump(zend_op_array *op_array, zend_op *new_opline, zend_op *opline);
116116
void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_t *shiftlist);

0 commit comments

Comments
 (0)