summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/opcache/Optimizer/optimize_func_calls.c8
-rw-r--r--ext/opcache/Optimizer/zend_call_graph.c6
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c16
-rw-r--r--ext/opcache/Optimizer/zend_optimizer_internal.h2
4 files changed, 22 insertions, 10 deletions
diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c
index 2894ca89f4..309a140167 100644
--- a/ext/opcache/Optimizer/optimize_func_calls.c
+++ b/ext/opcache/Optimizer/optimize_func_calls.c
@@ -39,6 +39,7 @@
typedef struct _optimizer_call_info {
zend_function *func;
zend_op *opline;
+ zend_bool is_prototype;
zend_bool try_inline;
uint32_t func_arg_num;
} optimizer_call_info;
@@ -172,9 +173,12 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
case ZEND_INIT_METHOD_CALL:
case ZEND_INIT_FCALL:
case ZEND_NEW:
+ /* The argument passing optimizations are valid for prototypes as well,
+ * as inheritance cannot change between ref <-> non-ref arguments. */
call_stack[call].func = zend_optimizer_get_called_func(
- ctx->script, op_array, opline);
- call_stack[call].try_inline = opline->opcode != ZEND_NEW;
+ ctx->script, op_array, opline, &call_stack[call].is_prototype);
+ call_stack[call].try_inline =
+ !call_stack[call].is_prototype && opline->opcode != ZEND_NEW;
/* break missing intentionally */
case ZEND_INIT_DYNAMIC_CALL:
case ZEND_INIT_USER_CALL:
diff --git a/ext/opcache/Optimizer/zend_call_graph.c b/ext/opcache/Optimizer/zend_call_graph.c
index 51b307bf5e..3b79bc445d 100644
--- a/ext/opcache/Optimizer/zend_call_graph.c
+++ b/ext/opcache/Optimizer/zend_call_graph.c
@@ -93,6 +93,7 @@ int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_f
int call = 0;
zend_call_info **call_stack;
ALLOCA_FLAG(use_heap);
+ zend_bool is_prototype;
call_stack = do_alloca((op_array->last / 2) * sizeof(zend_call_info*), use_heap);
call_info = NULL;
@@ -103,8 +104,9 @@ int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_f
case ZEND_INIT_STATIC_METHOD_CALL:
call_stack[call] = call_info;
func = zend_optimizer_get_called_func(
- script, op_array, opline);
- if (func) {
+ script, op_array, opline, &is_prototype);
+ /* TODO: Support prototypes? */
+ if (func && !is_prototype) {
call_info = zend_arena_calloc(arena, 1, sizeof(zend_call_info) + (sizeof(zend_send_arg_info) * ((int)opline->extended_value - 1)));
call_info->caller_op_array = op_array;
call_info->caller_init_opline = opline;
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index facb238c21..6f896af27c 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -777,8 +777,9 @@ static zend_class_entry *get_class_entry_from_op1(
}
zend_function *zend_optimizer_get_called_func(
- zend_script *script, zend_op_array *op_array, zend_op *opline)
+ zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool *is_prototype)
{
+ *is_prototype = 0;
switch (opline->opcode) {
case ZEND_INIT_FCALL:
{
@@ -825,7 +826,7 @@ zend_function *zend_optimizer_get_called_func(
if (fbc) {
zend_bool is_public = (fbc->common.fn_flags & ZEND_ACC_PUBLIC) != 0;
zend_bool same_scope = fbc->common.scope == op_array->scope;
- if (is_public|| same_scope) {
+ if (is_public || same_scope) {
return fbc;
}
}
@@ -843,10 +844,15 @@ zend_function *zend_optimizer_get_called_func(
zend_bool is_private = (fbc->common.fn_flags & ZEND_ACC_PRIVATE) != 0;
zend_bool is_final = (fbc->common.fn_flags & ZEND_ACC_FINAL) != 0;
zend_bool same_scope = fbc->common.scope == op_array->scope;
- if ((is_private && same_scope)
- || (is_final && (!is_private || same_scope))) {
- return fbc;
+ if (is_private) {
+ /* Only use private method if in the same scope. We can't even use it
+ * as a prototype, as it may be overridden with changed signature. */
+ return same_scope ? fbc : NULL;
}
+ /* If the method is non-final, it may be overriden,
+ * but only with a compatible method signature. */
+ *is_prototype = !is_final;
+ return fbc;
}
}
break;
diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h
index 5207e6cb74..ed0dac3e19 100644
--- a/ext/opcache/Optimizer/zend_optimizer_internal.h
+++ b/ext/opcache/Optimizer/zend_optimizer_internal.h
@@ -110,7 +110,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
void zend_optimizer_compact_vars(zend_op_array *op_array);
int zend_optimizer_is_disabled_func(const char *name, size_t len);
zend_function *zend_optimizer_get_called_func(
- zend_script *script, zend_op_array *op_array, zend_op *opline);
+ zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool *is_prototype);
uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args);
void zend_optimizer_migrate_jump(zend_op_array *op_array, zend_op *new_opline, zend_op *opline);
void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_t *shiftlist);