zend_op *new_opcodes;
zend_op *opline;
uint32_t len = 0;
-#if DEBUG_BLOCKPASS
int n;
-#endif
for (b = blocks; b < end; b++) {
if (b->flags & ZEND_BB_REACHABLE) {
*opline_num = -1;
}
-#if DEBUG_BLOCKPASS
/* rebild map (judt for printing) */
memset(cfg->map, -1, sizeof(int) * op_array->last);
for (n = 0; n < cfg->blocks_count; n++) {
cfg->map[cfg->blocks[n].start] = n;
}
}
-#endif
}
static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_array, zend_cfg *cfg, zend_uchar *same_t)
zend_op **Tsource;
zend_uchar *same_t;
-#if DEBUG_BLOCKPASS
- fprintf(stderr, "File %s func %s\n", op_array->filename->val, op_array->function_name ? op_array->function_name->val : "main");
- fflush(stderr);
-#endif
-
/* Build CFG */
checkpoint = zend_arena_checkpoint(ctx->arena);
if (zend_build_cfg(&ctx->arena, op_array, 0, 0, &cfg, NULL) != SUCCESS) {
return;
}
-#if DEBUG_BLOCKPASS
- fprintf(stderr, "\nBEFORE-BLOCK-PASS: %s:\n", op_array->function_name ? op_array->function_name->val : "(null)");
- zend_dump_op_array(op_array, &cfg, 1);
-#endif
+ if (ctx->debug_level & ZEND_DUMP_BEFORE_BLOCK_PASS) {
+ zend_dump_op_array(op_array, &cfg, ZEND_DUMP_UNREACHABLE, "before block pass");
+ }
if (op_array->last_var || op_array->T) {
bitset_len = zend_bitset_len(op_array->last_var + op_array->T);
zend_t_usage(&cfg, op_array, usage, ctx);
assemble_code_blocks(&cfg, op_array);
-#if DEBUG_BLOCKPASS
- fprintf(stderr, "\nAFTER-BLOCK-PASS: %s:\n", op_array->function_name ? op_array->function_name->val : "(null)");
- zend_dump_op_array(op_array, &cfg, 0);
-#endif
+ if (ctx->debug_level & ZEND_DUMP_AFTER_BLOCK_PASS) {
+ zend_dump_op_array(op_array, &cfg, 0, "after block pass");
+ }
/* Destroy CFG */
zend_arena_release(&ctx->arena, checkpoint);
fprintf(stderr, "\n");
}
-void zend_dump_op_array(const zend_op_array *op_array, const zend_cfg *cfg, int all)
+void zend_dump_op_array(const zend_op_array *op_array, const zend_cfg *cfg, uint32_t dump_flags, const char *msg)
{
int i;
+ if (op_array->function_name) {
+ if (op_array->scope && op_array->scope->name) {
+ fprintf(stderr, "\n%s::%s", op_array->scope->name->val, op_array->function_name->val);
+ } else {
+ fprintf(stderr, "\n%s", op_array->function_name->val);
+ }
+ } else {
+ fprintf(stderr, "\n%s", "$_main");
+ }
+ fprintf(stderr, ": ; (lines=%d, args=%d, vars=%d, tmps=%d)\n",
+ op_array->last,
+ op_array->num_args,
+ op_array->last_var,
+ op_array->T);
+ if (msg) {
+ fprintf(stderr, " ; (%s)\n", msg);
+ }
+ fprintf(stderr, " ; %s:%u-%u\n", op_array->filename->val, op_array->line_start, op_array->line_end);
+
if (cfg) {
int n;
zend_basic_block *b;
for (n = 0; n < cfg->blocks_count; n++) {
b = cfg->blocks + n;
- if (all || (b->flags & ZEND_BB_REACHABLE)) {
+ if ((dump_flags & ZEND_DUMP_UNREACHABLE) || (b->flags & ZEND_BB_REACHABLE)) {
const zend_op *opline;
const zend_op *end;
int printed = 0;
if (b->flags & ZEND_BB_KILL_VAR) {
fprintf(stderr, " kill_var");
}
- if (all & !(b->flags & ZEND_BB_REACHABLE)) {
+ if ((dump_flags & ZEND_DUMP_UNREACHABLE) & !(b->flags & ZEND_BB_REACHABLE)) {
fprintf(stderr, " unreachable");
}
#ifndef ZEND_DUMP_H
#define ZEND_DUMP_H
+#define ZEND_DUMP_UNREACHABLE (1<<0)
+
BEGIN_EXTERN_C()
-void zend_dump_op_array(const zend_op_array *op_array, const zend_cfg *cfg, int all);
+void zend_dump_op_array(const zend_op_array *op_array, const zend_cfg *cfg, uint32_t dump_flags, const char *msg);
END_EXTERN_C()
#include "zend_constants.h"
#include "zend_execute.h"
#include "zend_vm.h"
+#include "zend_cfg.h"
+#include "zend_dump.h"
static void zend_optimizer_zval_dtor_wrapper(zval *zvalue)
{
return;
}
+ if (ctx->debug_level & ZEND_DUMP_BEFORE_OPTIMIZER) {
+ zend_dump_op_array(op_array, NULL, 1, "before optimizer");
+ }
+
/* pass 1
* - substitute persistent constants (true, false, null, etc)
* - perform compile-time evaluation of constant binary and unary operations
*/
if (ZEND_OPTIMIZER_PASS_1 & ctx->optimization_level) {
zend_optimizer_pass1(op_array, ctx);
+ if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_1) {
+ zend_dump_op_array(op_array, NULL, 1, "after pass 1");
+ }
}
/* pass 2:
*/
if (ZEND_OPTIMIZER_PASS_2 & ctx->optimization_level) {
zend_optimizer_pass2(op_array);
+ if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_2) {
+ zend_dump_op_array(op_array, NULL, 1, "after pass 2");
+ }
}
/* pass 3:
*/
if (ZEND_OPTIMIZER_PASS_3 & ctx->optimization_level) {
zend_optimizer_pass3(op_array);
+ if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_3) {
+ zend_dump_op_array(op_array, NULL, 1, "after pass 1");
+ }
}
/* pass 4:
*/
if (ZEND_OPTIMIZER_PASS_4 & ctx->optimization_level) {
optimize_func_calls(op_array, ctx);
+ if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_4) {
+ zend_dump_op_array(op_array, NULL, 1, "after pass 1");
+ }
}
/* pass 5:
*/
if (ZEND_OPTIMIZER_PASS_5 & ctx->optimization_level) {
optimize_cfg(op_array, ctx);
+ if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_5) {
+ zend_dump_op_array(op_array, NULL, 1, "after pass 5");
+ }
}
/* pass 9:
*/
if (ZEND_OPTIMIZER_PASS_9 & ctx->optimization_level) {
optimize_temporary_variables(op_array, ctx);
+ if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_9) {
+ zend_dump_op_array(op_array, NULL, 1, "after pass 9");
+ }
}
/* pass 10:
*/
if (((ZEND_OPTIMIZER_PASS_10|ZEND_OPTIMIZER_PASS_5) & ctx->optimization_level) == ZEND_OPTIMIZER_PASS_10) {
zend_optimizer_nop_removal(op_array);
+ if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_10) {
+ zend_dump_op_array(op_array, NULL, 1, "after pass 10");
+ }
}
/* pass 11:
*/
if (ZEND_OPTIMIZER_PASS_11 & ctx->optimization_level) {
zend_optimizer_compact_literals(op_array, ctx);
+ if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_11) {
+ zend_dump_op_array(op_array, NULL, 1, "after pass 11");
+ }
+ }
+
+ if (ctx->debug_level & ZEND_DUMP_AFTER_OPTIMIZER) {
+ zend_dump_op_array(op_array, NULL, 1, "after optimizer");
}
}
}
}
-int zend_optimize_script(zend_script *script, zend_long optimization_level)
+int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level)
{
uint idx, j;
Bucket *p, *q;
ctx.script = script;
ctx.constants = NULL;
ctx.optimization_level = optimization_level;
+ ctx.debug_level = debug_level;
zend_optimize_op_array(&script->main_op_array, &ctx);
#define DEFAULT_OPTIMIZATION_LEVEL "0xFFFFFFFF"
+
+#define ZEND_DUMP_AFTER_PASS_1 ZEND_OPTIMIZER_PASS_1
+#define ZEND_DUMP_AFTER_PASS_2 ZEND_OPTIMIZER_PASS_2
+#define ZEND_DUMP_AFTER_PASS_3 ZEND_OPTIMIZER_PASS_3
+#define ZEND_DUMP_AFTER_PASS_4 ZEND_OPTIMIZER_PASS_4
+#define ZEND_DUMP_AFTER_PASS_5 ZEND_OPTIMIZER_PASS_5
+#define ZEND_DUMP_AFTER_PASS_6 ZEND_OPTIMIZER_PASS_6
+#define ZEND_DUMP_AFTER_PASS_7 ZEND_OPTIMIZER_PASS_7
+#define ZEND_DUMP_AFTER_PASS_8 ZEND_OPTIMIZER_PASS_8
+#define ZEND_DUMP_AFTER_PASS_9 ZEND_OPTIMIZER_PASS_9
+#define ZEND_DUMP_AFTER_PASS_10 ZEND_OPTIMIZER_PASS_10
+#define ZEND_DUMP_AFTER_PASS_11 ZEND_OPTIMIZER_PASS_11
+#define ZEND_DUMP_AFTER_PASS_12 ZEND_OPTIMIZER_PASS_12
+#define ZEND_DUMP_AFTER_PASS_13 ZEND_OPTIMIZER_PASS_13
+#define ZEND_DUMP_AFTER_PASS_14 ZEND_OPTIMIZER_PASS_14
+
+#define ZEND_DUMP_BEFORE_OPTIMIZER (1<<16)
+#define ZEND_DUMP_AFTER_OPTIMIZER (1<<17)
+#define ZEND_DUMP_BEFORE_BLOCK_PASS (1<<18)
+#define ZEND_DUMP_AFTER_BLOCK_PASS (1<<19)
+
typedef struct _zend_script {
zend_string *filename;
zend_op_array main_op_array;
HashTable class_table;
} zend_script;
-int zend_optimize_script(zend_script *script, zend_long optimization_level);
+int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level);
#endif
zend_script *script;
HashTable *constants;
zend_long optimization_level;
+ zend_long debug_level;
} zend_optimizer_ctx;
#define LITERAL_LONG(op, val) do { \
return new_persistent_script;
}
- if (!zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level)) {
+ if (!zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level)) {
return new_persistent_script;
}
return new_persistent_script;
}
- if (!zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level)) {
+ if (!zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level)) {
return new_persistent_script;
}
zend_long log_verbosity_level;
zend_long optimization_level;
+ zend_long opt_debug_level;
zend_long max_file_size;
zend_long interned_strings_buffer;
char *restrict_api;
STD_PHP_INI_ENTRY("opcache.fast_shutdown" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.fast_shutdown, zend_accel_globals, accel_globals)
STD_PHP_INI_ENTRY("opcache.optimization_level" , DEFAULT_OPTIMIZATION_LEVEL , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.optimization_level, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.opt_debug_level" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.opt_debug_level, zend_accel_globals, accel_globals)
STD_PHP_INI_BOOLEAN("opcache.enable_file_override" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_override_enabled, zend_accel_globals, accel_globals)
STD_PHP_INI_BOOLEAN("opcache.enable_cli" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.enable_cli, zend_accel_globals, accel_globals)
STD_PHP_INI_ENTRY("opcache.error_log" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.error_log, zend_accel_globals, accel_globals)