Skip to content

Commit 9331be7

Browse files
committed
Use call_map to avoid linear call lookup
1 parent 2bba4a0 commit 9331be7

File tree

4 files changed

+47
-26
lines changed

4 files changed

+47
-26
lines changed

ext/opcache/Optimizer/zend_call_graph.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,29 @@ int zend_build_call_graph(zend_arena **arena, zend_script *script, uint32_t buil
266266
}
267267
/* }}} */
268268

269+
zend_call_info **zend_build_call_map(zend_arena **arena, zend_func_info *info, zend_op_array *op_array) /* {{{ */
270+
{
271+
zend_call_info **map, *call;
272+
if (!info->callee_info) {
273+
/* Don't build call map if function contains no calls */
274+
return NULL;
275+
}
276+
277+
map = zend_arena_calloc(arena, sizeof(zend_call_info *), op_array->last);
278+
for (call = info->callee_info; call; call = call->next_callee) {
279+
int i;
280+
map[call->caller_init_opline - op_array->opcodes] = call;
281+
map[call->caller_call_opline - op_array->opcodes] = call;
282+
for (i = 0; i < call->num_args; i++) {
283+
if (call->arg_info[i].opline) {
284+
map[call->arg_info[i].opline - op_array->opcodes] = call;
285+
}
286+
}
287+
}
288+
return map;
289+
}
290+
/* }}} */
291+
269292
/*
270293
* Local variables:
271294
* tab-width: 4

ext/opcache/Optimizer/zend_call_graph.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ struct _zend_func_info {
5151
zend_ssa ssa; /* Static Single Assignmnt Form */
5252
zend_call_info *caller_info; /* where this function is called from */
5353
zend_call_info *callee_info; /* which functions are called from this one */
54+
zend_call_info **call_map; /* Call info associated with init/call/send opnum */
5455
int num_args; /* (-1 - unknown) */
5556
zend_recv_arg_info *arg_info;
5657
zend_ssa_var_info return_info;
@@ -69,6 +70,7 @@ typedef struct _zend_call_graph {
6970
BEGIN_EXTERN_C()
7071

7172
int zend_build_call_graph(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_call_graph *call_graph);
73+
zend_call_info **zend_build_call_map(zend_arena **arena, zend_func_info *info, zend_op_array *op_array);
7274
int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_op_array *op_array, zend_func_info *func_info);
7375

7476
END_EXTERN_C()

ext/opcache/Optimizer/zend_inference.c

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1357,21 +1357,24 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int
13571357
case ZEND_DO_ICALL:
13581358
case ZEND_DO_UCALL:
13591359
case ZEND_DO_FCALL_BY_NAME:
1360-
if (ssa->ops[line].result_def == var && ZEND_FUNC_INFO(op_array)) {
1360+
if (ssa->ops[line].result_def == var) {
13611361
zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
1362-
zend_call_info *call_info = func_info->callee_info;
1362+
zend_call_info *call_info;
1363+
if (!func_info || !func_info->call_map) {
1364+
break;
1365+
}
13631366

1364-
while (call_info && call_info->caller_call_opline != opline) {
1365-
call_info = call_info->next_callee;
1367+
call_info = func_info->call_map[opline - op_array->opcodes];
1368+
if (!call_info) {
1369+
break;
13661370
}
1367-
if (call_info) {
1368-
if (call_info->callee_func->type == ZEND_USER_FUNCTION) {
1369-
func_info = ZEND_FUNC_INFO(&call_info->callee_func->op_array);
1370-
if (func_info && func_info->return_info.has_range) {
1371-
*tmp = func_info->return_info.range;
1372-
return 1;
1373-
}
1371+
if (call_info->callee_func->type == ZEND_USER_FUNCTION) {
1372+
func_info = ZEND_FUNC_INFO(&call_info->callee_func->op_array);
1373+
if (func_info && func_info->return_info.has_range) {
1374+
*tmp = func_info->return_info.range;
1375+
return 1;
13741376
}
1377+
}
13751378
//TODO: we can't use type inference for internal functions at this point ???
13761379
#if 0
13771380
uint32_t type;
@@ -1394,7 +1397,6 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int
13941397
return 1;
13951398
}
13961399
#endif
1397-
}
13981400
}
13991401
break;
14001402
// FIXME: support for more opcodes
@@ -3126,13 +3128,10 @@ static void zend_update_type_info(const zend_op_array *op_array,
31263128
zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
31273129
zend_call_info *call_info;
31283130

3129-
if (!func_info) {
3131+
if (!func_info || !func_info->call_map) {
31303132
goto unknown_opcode;
31313133
}
3132-
call_info = func_info->callee_info;
3133-
while (call_info && call_info->caller_call_opline != opline) {
3134-
call_info = call_info->next_callee;
3135-
}
3134+
call_info = func_info->call_map[opline - op_array->opcodes];
31363135
if (!call_info) {
31373136
goto unknown_opcode;
31383137
}
@@ -3554,18 +3553,14 @@ static int is_recursive_tail_call(const zend_op_array *op_array,
35543553
{
35553554
zend_func_info *info = ZEND_FUNC_INFO(op_array);
35563555

3557-
if (info->ssa.ops && info->ssa.vars &&
3556+
if (info->ssa.ops && info->ssa.vars && info->call_map &&
35583557
info->ssa.ops[opline - op_array->opcodes].op1_use >= 0 &&
35593558
info->ssa.vars[info->ssa.ops[opline - op_array->opcodes].op1_use].definition >= 0) {
35603559

35613560
zend_op *op = op_array->opcodes + info->ssa.vars[info->ssa.ops[opline - op_array->opcodes].op1_use].definition;
35623561

35633562
if (op->opcode == ZEND_DO_UCALL) {
3564-
zend_call_info *call_info = info->callee_info;
3565-
3566-
while (call_info && call_info->caller_call_opline != op) {
3567-
call_info = call_info->next_callee;
3568-
}
3563+
zend_call_info *call_info = info->call_map[op - op_array->opcodes];
35693564
if (call_info && op_array == &call_info->callee_func->op_array) {
35703565
return 1;
35713566
}

ext/opcache/Optimizer/zend_optimizer.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -978,9 +978,10 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
978978
}
979979

980980
for (i = 0; i < call_graph.op_arrays_count; i++) {
981-
if (call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
982-
func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
983-
if (func_info) {
981+
func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
982+
if (func_info) {
983+
func_info->call_map = zend_build_call_map(&ctx.arena, func_info, call_graph.op_arrays[i]);
984+
if (call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
984985
zend_init_func_return_info(call_graph.op_arrays[i], script, &func_info->return_info);
985986
}
986987
}

0 commit comments

Comments
 (0)