]> granicus.if.org Git - php/commitdiff
Use call_map to avoid linear call lookup
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 16 Mar 2017 00:26:27 +0000 (01:26 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 16 Mar 2017 11:33:57 +0000 (12:33 +0100)
ext/opcache/Optimizer/zend_call_graph.c
ext/opcache/Optimizer/zend_call_graph.h
ext/opcache/Optimizer/zend_inference.c
ext/opcache/Optimizer/zend_optimizer.c

index f022bfc89296eacd89f87e9c474639450a245ca8..5800a220bc4eeee889df104bdc2bf471693130c9 100644 (file)
@@ -266,6 +266,29 @@ int zend_build_call_graph(zend_arena **arena, zend_script *script, uint32_t buil
 }
 /* }}} */
 
+zend_call_info **zend_build_call_map(zend_arena **arena, zend_func_info *info, zend_op_array *op_array) /* {{{ */
+{
+       zend_call_info **map, *call;
+       if (!info->callee_info) {
+               /* Don't build call map if function contains no calls */
+               return NULL;
+       }
+
+       map = zend_arena_calloc(arena, sizeof(zend_call_info *), op_array->last);
+       for (call = info->callee_info; call; call = call->next_callee) {
+               int i;
+               map[call->caller_init_opline - op_array->opcodes] = call;
+               map[call->caller_call_opline - op_array->opcodes] = call;
+               for (i = 0; i < call->num_args; i++) {
+                       if (call->arg_info[i].opline) {
+                               map[call->arg_info[i].opline - op_array->opcodes] = call;
+                       }
+               }
+       }
+       return map;
+}
+/* }}} */
+
 /*
  * Local variables:
  * tab-width: 4
index a59f894472f0f966fdf4787ac0df68cbcb2bc744..49c7217c40e084204cb4aae1014ddb407ac485fd 100644 (file)
@@ -51,6 +51,7 @@ struct _zend_func_info {
        zend_ssa                ssa;          /* Static Single Assignmnt Form  */
        zend_call_info         *caller_info;  /* where this function is called from */
        zend_call_info         *callee_info;  /* which functions are called from this one */
+       zend_call_info        **call_map;     /* Call info associated with init/call/send opnum */
        int                     num_args;     /* (-1 - unknown) */
        zend_recv_arg_info     *arg_info;
        zend_ssa_var_info       return_info;
@@ -69,6 +70,7 @@ typedef struct _zend_call_graph {
 BEGIN_EXTERN_C()
 
 int zend_build_call_graph(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_call_graph *call_graph);
+zend_call_info **zend_build_call_map(zend_arena **arena, zend_func_info *info, zend_op_array *op_array);
 int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_op_array *op_array, zend_func_info *func_info);
 
 END_EXTERN_C()
index 3bdc0310e6f8222062785db607ffe55887ee4031..752108a7fda030174fd42ebe9c8b7c1c4b05e255 100644 (file)
@@ -1357,21 +1357,24 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int
                case ZEND_DO_ICALL:
                case ZEND_DO_UCALL:
                case ZEND_DO_FCALL_BY_NAME:
-                       if (ssa->ops[line].result_def == var && ZEND_FUNC_INFO(op_array)) {
+                       if (ssa->ops[line].result_def == var) {
                                zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
-                               zend_call_info *call_info = func_info->callee_info;
+                               zend_call_info *call_info;
+                               if (!func_info || !func_info->call_map) {
+                                       break;
+                               }
 
-                               while (call_info && call_info->caller_call_opline != opline) {
-                                       call_info = call_info->next_callee;
+                               call_info = func_info->call_map[opline - op_array->opcodes];
+                               if (!call_info) {
+                                       break;
                                }
-                               if (call_info) {
-                                       if (call_info->callee_func->type == ZEND_USER_FUNCTION) {
-                                               func_info = ZEND_FUNC_INFO(&call_info->callee_func->op_array);
-                                               if (func_info && func_info->return_info.has_range) {
-                                                       *tmp = func_info->return_info.range;
-                                                       return 1;
-                                               }
+                               if (call_info->callee_func->type == ZEND_USER_FUNCTION) {
+                                       func_info = ZEND_FUNC_INFO(&call_info->callee_func->op_array);
+                                       if (func_info && func_info->return_info.has_range) {
+                                               *tmp = func_info->return_info.range;
+                                               return 1;
                                        }
+                               }
 //TODO: we can't use type inference for internal functions at this point ???
 #if 0
                                        uint32_t type;
@@ -1394,7 +1397,6 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int
                                                return 1;
                                        }
 #endif
-                               }
                        }
                        break;
                // FIXME: support for more opcodes
@@ -3126,13 +3128,10 @@ static void zend_update_type_info(const zend_op_array *op_array,
                                zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
                                zend_call_info *call_info;
 
-                               if (!func_info) {
+                               if (!func_info || !func_info->call_map) {
                                        goto unknown_opcode;
                                }
-                               call_info = func_info->callee_info;
-                               while (call_info && call_info->caller_call_opline != opline) {
-                                       call_info = call_info->next_callee;
-                               }
+                               call_info = func_info->call_map[opline - op_array->opcodes];
                                if (!call_info) {
                                        goto unknown_opcode;
                                }
@@ -3554,18 +3553,14 @@ static int is_recursive_tail_call(const zend_op_array *op_array,
 {
        zend_func_info *info = ZEND_FUNC_INFO(op_array);
 
-       if (info->ssa.ops && info->ssa.vars &&
+       if (info->ssa.ops && info->ssa.vars && info->call_map &&
            info->ssa.ops[opline - op_array->opcodes].op1_use >= 0 &&
            info->ssa.vars[info->ssa.ops[opline - op_array->opcodes].op1_use].definition >= 0) {
 
                zend_op *op = op_array->opcodes + info->ssa.vars[info->ssa.ops[opline - op_array->opcodes].op1_use].definition;
 
                if (op->opcode == ZEND_DO_UCALL) {
-                       zend_call_info *call_info = info->callee_info;
-
-                       while (call_info && call_info->caller_call_opline != op) {
-                               call_info = call_info->next_callee;
-                       }
+                       zend_call_info *call_info = info->call_map[op - op_array->opcodes];
                        if (call_info && op_array == &call_info->callee_func->op_array) {
                                return 1;
                        }
index fbcb3a2e16fb38c5e6b2318d7ec9babd8a5a8dc8..08ac084713cdd1505623074542b9e57020981275 100644 (file)
@@ -978,9 +978,10 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
                }
 
                for (i = 0; i < call_graph.op_arrays_count; i++) {
-                       if (call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
-                               func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
-                               if (func_info) {
+                       func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
+                       if (func_info) {
+                               func_info->call_map = zend_build_call_map(&ctx.arena, func_info, call_graph.op_arrays[i]);
+                               if (call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
                                        zend_init_func_return_info(call_graph.op_arrays[i], script, &func_info->return_info);
                                }
                        }