summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-12-24 14:30:41 +0300
committerDmitry Stogov <dmitry@zend.com>2015-12-24 14:30:41 +0300
commitb4def0ee884a32c5169123b9feed630e4906b366 (patch)
treeb489952a01ebb047b42c49507dd5fbe73897b1c8
parenta882d0fd7bc3238f59a4bb3d3f3d9e86ec5c3fe1 (diff)
downloadphp-git-b4def0ee884a32c5169123b9feed630e4906b366.tar.gz
Added call-graph analyses
-rw-r--r--ext/opcache/Optimizer/dfa_pass.c8
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c68
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.h2
-rw-r--r--ext/opcache/ZendAccelerator.c4
4 files changed, 66 insertions, 16 deletions
diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c
index ac7a193675..a2a94af073 100644
--- a/ext/opcache/Optimizer/dfa_pass.c
+++ b/ext/opcache/Optimizer/dfa_pass.c
@@ -30,10 +30,6 @@
#include "zend_inference.h"
#include "zend_dump.h"
-#ifndef HAVE_DFA_PASS
-# define HAVE_DFA_PASS 0
-#endif
-
void optimize_dfa(zend_op_array *op_array, zend_optimizer_ctx *ctx)
{
void *checkpoint;
@@ -41,10 +37,6 @@ void optimize_dfa(zend_op_array *op_array, zend_optimizer_ctx *ctx)
uint32_t flags = 0;
zend_ssa ssa;
-#if !HAVE_DFA_PASS
- return;
-#endif
-
/* Build SSA */
memset(&ssa, 0, sizeof(ssa));
checkpoint = zend_arena_checkpoint(ctx->arena);
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index 4434101081..01d56b3c33 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -28,8 +28,13 @@
#include "zend_vm.h"
#include "zend_cfg.h"
#include "zend_func_info.h"
+#include "zend_call_graph.h"
#include "zend_dump.h"
+#ifndef HAVE_DFA_PASS
+# define HAVE_DFA_PASS 0
+#endif
+
static void zend_optimizer_zval_dtor_wrapper(zval *zvalue)
{
zval_dtor(zvalue);
@@ -606,15 +611,18 @@ static void zend_optimize(zend_op_array *op_array,
}
}
+#if HAVE_DFA_PASS
/* pass 6:
* - DFA optimization
*/
- if (ZEND_OPTIMIZER_PASS_6 & ctx->optimization_level) {
+ if ((ZEND_OPTIMIZER_PASS_6 & ctx->optimization_level) &&
+ !(ZEND_OPTIMIZER_PASS_7 & ctx->optimization_level)) {
optimize_dfa(op_array, ctx);
if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_6) {
zend_dump_op_array(op_array, 0, "after pass 6", NULL);
}
}
+#endif
/* pass 9:
* - Optimize temp variables usage
@@ -651,12 +659,10 @@ static void zend_optimize(zend_op_array *op_array,
}
}
-static void zend_optimize_op_array(zend_op_array *op_array,
- zend_optimizer_ctx *ctx)
+static void zend_revert_pass_two(zend_op_array *op_array)
{
zend_op *opline, *end;
- /* Revert pass_two() */
opline = op_array->opcodes;
end = opline + op_array->last;
while (opline < end) {
@@ -668,11 +674,12 @@ static void zend_optimize_op_array(zend_op_array *op_array,
}
opline++;
}
+}
- /* Do actual optimizations */
- zend_optimize(op_array, ctx);
+static void zend_redo_pass_two(zend_op_array *op_array)
+{
+ zend_op *opline, *end;
- /* Redo pass_two() */
opline = op_array->opcodes;
end = opline + op_array->last;
while (opline < end) {
@@ -687,6 +694,19 @@ static void zend_optimize_op_array(zend_op_array *op_array,
}
}
+static void zend_optimize_op_array(zend_op_array *op_array,
+ zend_optimizer_ctx *ctx)
+{
+ /* Revert pass_two() */
+ zend_revert_pass_two(op_array);
+
+ /* Do actual optimizations */
+ zend_optimize(op_array, ctx);
+
+ /* Redo pass_two() */
+ zend_redo_pass_two(op_array);
+}
+
static void zend_adjust_fcall_stack_size(zend_op_array *op_array, zend_optimizer_ctx *ctx)
{
zend_function *func;
@@ -714,6 +734,7 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
zend_class_entry *ce;
zend_op_array *op_array;
zend_optimizer_ctx ctx;
+ zend_call_graph call_graph;
ctx.arena = zend_arena_create(64 * 1024);
ctx.script = script;
@@ -751,6 +772,39 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
}
}
+#if HAVE_DFA_PASS
+ if ((ZEND_OPTIMIZER_PASS_6 & optimization_level) &&
+ (ZEND_OPTIMIZER_PASS_7 & optimization_level) &&
+ zend_build_call_graph(&ctx.arena, script, ZEND_RT_CONSTANTS, &call_graph) == SUCCESS) {
+ /* Optimize using call-graph */
+ uint32_t i;
+ zend_func_info *func_info;
+
+ for (i = 0; i < call_graph.op_arrays_count; i++) {
+ zend_revert_pass_two(call_graph.op_arrays[i]);
+ func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
+ if (func_info) {
+ func_info->ssa.rt_constants = 0;
+ }
+ }
+
+ for (i = 0; i < call_graph.op_arrays_count; i++) {
+ optimize_dfa(call_graph.op_arrays[i], &ctx);
+ }
+
+ if (debug_level & ZEND_DUMP_AFTER_PASS_7) {
+ for (i = 0; i < call_graph.op_arrays_count; i++) {
+ zend_dump_op_array(call_graph.op_arrays[i], 0, "after pass 7", NULL);
+ }
+ }
+
+ for (i = 0; i < call_graph.op_arrays_count; i++) {
+ zend_redo_pass_two(call_graph.op_arrays[i]);
+ ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
+ }
+ }
+#endif
+
if (ZEND_OPTIMIZER_PASS_12 & optimization_level) {
zend_adjust_fcall_stack_size(&script->main_op_array, &ctx);
diff --git a/ext/opcache/Optimizer/zend_optimizer.h b/ext/opcache/Optimizer/zend_optimizer.h
index 5ec7d8fd8d..5743ab6e3e 100644
--- a/ext/opcache/Optimizer/zend_optimizer.h
+++ b/ext/opcache/Optimizer/zend_optimizer.h
@@ -31,7 +31,7 @@
#define ZEND_OPTIMIZER_PASS_4 (1<<3) /* INIT_FCALL_BY_NAME -> DO_FCALL */
#define ZEND_OPTIMIZER_PASS_5 (1<<4) /* CFG based optimization */
#define ZEND_OPTIMIZER_PASS_6 (1<<5) /* DFA based optimization */
-#define ZEND_OPTIMIZER_PASS_7 (1<<6)
+#define ZEND_OPTIMIZER_PASS_7 (1<<6) /* CALL GRAPH optimization */
#define ZEND_OPTIMIZER_PASS_8 (1<<7)
#define ZEND_OPTIMIZER_PASS_9 (1<<8) /* TMP VAR usage */
#define ZEND_OPTIMIZER_PASS_10 (1<<9) /* NOP removal */
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index 51500a95ff..ca7ad67fd0 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -2768,6 +2768,8 @@ file_cache_fallback:
zend_accel_blacklist_load(&accel_blacklist, ZCG(accel_directives.user_blacklist_filename));
}
+ zend_optimizer_startup();
+
return SUCCESS;
}
@@ -2785,6 +2787,8 @@ void accel_shutdown(void)
zend_ini_entry *ini_entry;
zend_bool file_cache_only = 0;
+ zend_optimizer_shutdown();
+
zend_accel_blacklist_shutdown(&accel_blacklist);
if (!ZCG(enabled) || !accel_startup_ok) {