#include "zend_inference.h"
#include "zend_call_graph.h"
-typedef int (*zend_op_array_func_t)(zend_call_graph *call_graph, zend_op_array *op_array);
-
-static int zend_op_array_calc(zend_call_graph *call_graph, zend_op_array *op_array)
+static void zend_op_array_calc(zend_op_array *op_array, void *context)
{
- (void) op_array;
-
+ zend_call_graph *call_graph = context;
call_graph->op_arrays_count++;
- return SUCCESS;
}
-static int zend_op_array_collect(zend_call_graph *call_graph, zend_op_array *op_array)
+static void zend_op_array_collect(zend_op_array *op_array, void *context)
{
+ zend_call_graph *call_graph = context;
zend_func_info *func_info = call_graph->func_infos + call_graph->op_arrays_count;
ZEND_SET_FUNC_INFO(op_array, func_info);
func_info->num_args = -1;
func_info->return_value_used = -1;
call_graph->op_arrays_count++;
- return SUCCESS;
-}
-
-static int zend_foreach_op_array(zend_call_graph *call_graph, zend_script *script, zend_op_array_func_t func)
-{
- zend_class_entry *ce;
- zend_string *key;
- zend_op_array *op_array;
-
- if (func(call_graph, &script->main_op_array) != SUCCESS) {
- return FAILURE;
- }
-
- ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
- if (func(call_graph, op_array) != SUCCESS) {
- return FAILURE;
- }
- } ZEND_HASH_FOREACH_END();
-
- ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
- if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
- continue;
- }
- ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
- if (op_array->scope == ce
- && op_array->type == ZEND_USER_FUNCTION
- && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
- if (func(call_graph, op_array) != SUCCESS) {
- return FAILURE;
- }
- }
- } ZEND_HASH_FOREACH_END();
- } ZEND_HASH_FOREACH_END();
-
- return SUCCESS;
}
int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_op_array *op_array, zend_func_info *func_info)
int zend_build_call_graph(zend_arena **arena, zend_script *script, zend_call_graph *call_graph) /* {{{ */
{
call_graph->op_arrays_count = 0;
- if (zend_foreach_op_array(call_graph, script, zend_op_array_calc) != SUCCESS) {
- return FAILURE;
- }
+ zend_foreach_op_array(script, zend_op_array_calc, call_graph);
+
call_graph->op_arrays = (zend_op_array**)zend_arena_calloc(arena, call_graph->op_arrays_count, sizeof(zend_op_array*));
call_graph->func_infos = (zend_func_info*)zend_arena_calloc(arena, call_graph->op_arrays_count, sizeof(zend_func_info));
call_graph->op_arrays_count = 0;
- if (zend_foreach_op_array(call_graph, script, zend_op_array_collect) != SUCCESS) {
- return FAILURE;
- }
+ zend_foreach_op_array(script, zend_op_array_collect, call_graph);
return SUCCESS;
}
return 1;
}
+void zend_foreach_op_array(zend_script *script, zend_op_array_func_t func, void *context)
+{
+ zend_class_entry *ce;
+ zend_string *key;
+ zend_op_array *op_array;
+
+ func(&script->main_op_array, context);
+
+ ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
+ func(op_array, context);
+ } ZEND_HASH_FOREACH_END();
+
+ ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
+ if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
+ continue;
+ }
+ ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
+ if (op_array->scope == ce
+ && op_array->type == ZEND_USER_FUNCTION
+ && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
+ func(op_array, context);
+ }
+ } ZEND_HASH_FOREACH_END();
+ } ZEND_HASH_FOREACH_END();
+}
+
+static void step_optimize_op_array(zend_op_array *op_array, void *context) {
+ zend_optimize_op_array(op_array, (zend_optimizer_ctx *) context);
+}
+
+static void step_adjust_fcall_stack_size(zend_op_array *op_array, void *context) {
+ zend_adjust_fcall_stack_size(op_array, (zend_optimizer_ctx *) context);
+}
+
+static void step_dump_after_optimizer(zend_op_array *op_array, void *context) {
+ zend_dump_op_array(op_array, ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
+}
+
int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level)
{
zend_class_entry *ce;
ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
}
} else {
- zend_optimize_op_array(&script->main_op_array, &ctx);
-
- ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
- zend_optimize_op_array(op_array, &ctx);
- } ZEND_HASH_FOREACH_END();
-
- ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
- if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
- continue;
- }
- ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
- if (op_array->scope == ce
- && op_array->type == ZEND_USER_FUNCTION
- && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
- zend_optimize_op_array(op_array, &ctx);
- }
- } ZEND_HASH_FOREACH_END();
- } ZEND_HASH_FOREACH_END();
+ zend_foreach_op_array(script, step_optimize_op_array, &ctx);
if (ZEND_OPTIMIZER_PASS_12 & optimization_level) {
- zend_adjust_fcall_stack_size(&script->main_op_array, &ctx);
-
- ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
- zend_adjust_fcall_stack_size(op_array, &ctx);
- } ZEND_HASH_FOREACH_END();
-
- ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
- if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
- continue;
- }
- ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
- if (op_array->scope == ce
- && op_array->type == ZEND_USER_FUNCTION
- && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
- zend_adjust_fcall_stack_size(op_array, &ctx);
- }
- } ZEND_HASH_FOREACH_END();
- } ZEND_HASH_FOREACH_END();
+ zend_foreach_op_array(script, step_adjust_fcall_stack_size, &ctx);
}
}
} ZEND_HASH_FOREACH_END();
if ((debug_level & ZEND_DUMP_AFTER_OPTIMIZER) &&
- (ZEND_OPTIMIZER_PASS_7 & optimization_level)) {
- zend_dump_op_array(&script->main_op_array,
- ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
-
- ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
- zend_dump_op_array(op_array,
- ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
- } ZEND_HASH_FOREACH_END();
-
- ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
- ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
- if (op_array->scope == ce
- && op_array->type == ZEND_USER_FUNCTION
- && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
- zend_dump_op_array(op_array,
- ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
- }
- } ZEND_HASH_FOREACH_END();
- } ZEND_HASH_FOREACH_END();
+ (ZEND_OPTIMIZER_PASS_7 & optimization_level)) {
+ zend_foreach_op_array(script, step_dump_after_optimizer, NULL);
}
if (ctx.constants) {