com php-src: Use call_map to avoid linear call look up: ext/opcache/Optimizer/zend_call_graph.c ext/opc ache/Optimizer/zend_call_graph.h ext/opcache/Optimizer/ zend_inference.c ext/opcache/Optimizer/zend_optimizer .c

[email protected] (Nikita Popov)
Newsgroups php.cvs
Message-ID <[email protected]>
Commit:    9331be7d6af4ba9ab9945ac1d72812603fdd821c
Author:    Nikita Popov <[email protected]>         Thu, 16 Mar 2017 01:26:27 +0100
Parents:   2bba4a0d7f6d5e5712d60bc1cf2119622d837e55
Branches:  PHP-7.1 master

Link:       http://git.php.net/?p=php-src.git;a=commitdiff;h=9331be7d6af4ba9ab9945ac1d72812603fdd821c

Log:
Use call_map to avoid linear call lookup

Changed paths:
  M  ext/opcache/Optimizer/zend_call_graph.c
  M  ext/opcache/Optimizer/zend_call_graph.h
  M  ext/opcache/Optimizer/zend_inference.c
  M  ext/opcache/Optimizer/zend_optimizer.c


Diff:
diff --git a/ext/opcache/Optimizer/zend_call_graph.c b/ext/opcache/Optimizer/zend_call_graph.c
index f022bfc..5800a22 100644
--- a/ext/opcache/Optimizer/zend_call_graph.c
+++ b/ext/opcache/Optimizer/zend_call_graph.c
@@ -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
diff --git a/ext/opcache/Optimizer/zend_call_graph.h b/ext/opcache/Optimizer/zend_call_graph.h
index a59f894..49c7217 100644
--- a/ext/opcache/Optimizer/zend_call_graph.h
+++ b/ext/opcache/Optimizer/zend_call_graph.h
@@ -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()
diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c
index 3bdc031..752108a 100644
--- a/ext/opcache/Optimizer/zend_inference.c
+++ b/ext/opcache/Optimizer/zend_inference.c
@@ -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;
 			}
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index fbcb3a2..08ac084 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -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);
 				}
 			}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.