From cba1a8498cf1299676279ffab04cfe79d285244d Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 11 Dec 2015 00:47:02 +0300 Subject: [PATCH] Improve Optimizer debugging facility (print the meaning of extended_value) --- Zend/zend_vm_def.h | 22 +-- Zend/zend_vm_gen.php | 6 + Zend/zend_vm_opcodes.c | 22 +-- Zend/zend_vm_opcodes.h | 3 + ext/opcache/Optimizer/zend_dump.c | 227 +++++++++++++++++++++++++++++- 5 files changed, 252 insertions(+), 28 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 0fc70a307d..eef2fab51c 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1579,7 +1579,7 @@ ZEND_VM_HANDLER(86, ZEND_FETCH_RW, CONST|TMPVAR|CV, UNUSED, VAR_FETCH) ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_var_address_helper, type, BP_VAR_RW); } -ZEND_VM_HANDLER(92, ZEND_FETCH_FUNC_ARG, CONST|TMPVAR|CV, UNUSED, VAR_FETCH) +ZEND_VM_HANDLER(92, ZEND_FETCH_FUNC_ARG, CONST|TMPVAR|CV, UNUSED, VAR_FETCH|ARG_NUM) { USE_OPLINE @@ -1716,7 +1716,7 @@ ZEND_VM_HANDLER(175, ZEND_FETCH_STATIC_PROP_RW, CONST|TMPVAR|CV, UNUSED|CONST|VA ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_static_prop_helper, type, BP_VAR_RW); } -ZEND_VM_HANDLER(177, ZEND_FETCH_STATIC_PROP_FUNC_ARG, CONST|TMPVAR|CV, UNUSED|CONST|VAR) +ZEND_VM_HANDLER(177, ZEND_FETCH_STATIC_PROP_FUNC_ARG, CONST|TMPVAR|CV, UNUSED|CONST|VAR, NUM) { USE_OPLINE @@ -1809,7 +1809,7 @@ ZEND_VM_HANDLER(90, ZEND_FETCH_DIM_IS, CONST|TMPVAR|CV, CONST|TMPVAR|CV) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUSED|CV) +ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUSED|CV, NUM) { USE_OPLINE zval *container; @@ -2081,7 +2081,7 @@ ZEND_VM_C_LABEL(fetch_obj_is_no_object): ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, CONST|TMP|VAR|UNUSED|CV, CONST|TMPVAR|CV) +ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, CONST|TMP|VAR|UNUSED|CV, CONST|TMPVAR|CV, NUM) { USE_OPLINE zval *container; @@ -2362,7 +2362,7 @@ ZEND_VM_HANDLER(38, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV) +ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV, SRC) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -4067,7 +4067,7 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); } -ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY) +ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY, SRC) { USE_OPLINE zval *retval_ptr; @@ -4351,7 +4351,7 @@ ZEND_VM_HANDLER(117, ZEND_SEND_VAR, VAR|CV, NUM) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR, NUM) +ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR, NUM, NUM) { USE_OPLINE zend_free_op free_op1; @@ -5245,7 +5245,7 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED, CONST) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(72, ZEND_ADD_ARRAY_ELEMENT, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUSED|CV, NUM) +ZEND_VM_HANDLER(72, ZEND_ADD_ARRAY_ELEMENT, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUSED|CV, REF) { USE_OPLINE zend_free_op free_op1; @@ -5344,7 +5344,7 @@ ZEND_VM_C_LABEL(num_index): ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(71, ZEND_INIT_ARRAY, CONST|TMP|VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV, ARRAY_INIT) +ZEND_VM_HANDLER(71, ZEND_INIT_ARRAY, CONST|TMP|VAR|UNUSED|CV, CONST|TMPVAR|UNUSED|CV, ARRAY_INIT|REF) { zval *array; uint32_t size; @@ -5606,7 +5606,7 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY, EVAL) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMPVAR|CV, UNUSED, VAR_FETCH) +ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMPVAR|CV, UNUSED, VAR_FETCH|ISSET) { USE_OPLINE zval tmp, *varname; @@ -7455,7 +7455,7 @@ ZEND_VM_HANDLER(156, ZEND_SEPARATE, VAR, UNUSED) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSED) +ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSED, SRC) { USE_OPLINE diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 3fdf3be7fc..e2e1859172 100644 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -84,6 +84,9 @@ $vm_op_flags = array( "ZEND_VM_EXT_FAST_CALL" => 1<<26, "ZEND_VM_EXT_FAST_RET" => 1<<27, "ZEND_VM_EXT_ISSET" => 1<<28, + "ZEND_VM_EXT_ARG_NUM" => 1<<29, + "ZEND_VM_EXT_REF" => 1<<30, + "ZEND_VM_EXT_SRC" => 1<<31, ); foreach ($vm_op_flags as $name => $val) { @@ -118,6 +121,9 @@ $vm_ext_decode = array( "FAST_CALL" => ZEND_VM_EXT_FAST_CALL, "FAST_RET" => ZEND_VM_EXT_FAST_RET, "ISSET" => ZEND_VM_EXT_ISSET, + "ARG_NUM" => ZEND_VM_EXT_ARG_NUM, + "REF" => ZEND_VM_EXT_REF, + "SRC" => ZEND_VM_EXT_SRC, ); $vm_kind_name = array( diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index b56cd930ff..2e9a13f6a4 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -246,7 +246,7 @@ static uint32_t zend_vm_opcodes_flags[182] = { 0x00000001, 0x00000001, 0x00000301, - 0x00000101, + 0x80000101, 0x00000007, 0x00000000, 0x00000010, @@ -278,10 +278,10 @@ static uint32_t zend_vm_opcodes_flags[182] = { 0x00011003, 0x00010300, 0x00004005, - 0x00800703, - 0x00010703, + 0x40800703, + 0x40000703, 0x02000007, - 0x00400107, + 0x10400107, 0x00000701, 0x00000701, 0x00001003, @@ -299,9 +299,9 @@ static uint32_t zend_vm_opcodes_flags[182] = { 0x00400107, 0x00000707, 0x00000707, - 0x00400107, - 0x00000703, - 0x00000703, + 0x20400107, + 0x00010703, + 0x00010703, 0x00400107, 0x00000701, 0x00000701, @@ -313,12 +313,12 @@ static uint32_t zend_vm_opcodes_flags[182] = { 0x00000000, 0x00000000, 0x00010000, - 0x00000801, + 0x00010801, 0x00040103, 0x00000003, 0x00100700, 0x00000007, - 0x00000003, + 0x80000003, 0x00010707, 0x00010703, 0x10400107, @@ -367,7 +367,7 @@ static uint32_t zend_vm_opcodes_flags[182] = { 0x00100000, 0x00000000, 0x00000000, - 0x00000303, + 0x80000303, 0x00000003, 0x04002010, 0x08002000, @@ -384,7 +384,7 @@ static uint32_t zend_vm_opcodes_flags[182] = { 0x00000307, 0x00000307, 0x00000307, - 0x00000307, + 0x00010307, 0x00000307, 0x00000307, 0x10000307, diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 52b4d0b5aa..8d156a98d2 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -55,6 +55,9 @@ #define ZEND_VM_EXT_FAST_CALL 0x04000000 #define ZEND_VM_EXT_FAST_RET 0x08000000 #define ZEND_VM_EXT_ISSET 0x10000000 +#define ZEND_VM_EXT_ARG_NUM 0x20000000 +#define ZEND_VM_EXT_REF 0x40000000 +#define ZEND_VM_EXT_SRC 0x80000000 BEGIN_EXTERN_C() diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c index e73d8567ff..66a28e31a3 100644 --- a/ext/opcache/Optimizer/zend_dump.c +++ b/ext/opcache/Optimizer/zend_dump.c @@ -56,11 +56,184 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block * const char *name = zend_get_opcode_name(opline->opcode); uint32_t flags = zend_get_opcode_flags(opline->opcode); uint32_t n = 0; + int len = 0; if (!b) { - fprintf(stderr, "L%u:", (uint32_t)(opline - op_array->opcodes)); + len = fprintf(stderr, "L%u:", (uint32_t)(opline - op_array->opcodes)); + } + fprintf(stderr, "%*c%s", 8-len, ' ', name ? (name + 5) : "???"); + if (ZEND_VM_EXT_NUM & flags) { + fprintf(stderr, " %u", opline->extended_value); + } else if (ZEND_VM_EXT_DIM_OBJ & flags) { + if (opline->extended_value == ZEND_ASSIGN_DIM) { + fprintf(stderr, " (dim)"); + } else if (opline->extended_value == ZEND_ASSIGN_OBJ) { + fprintf(stderr, " (obj)"); + } + } else if (ZEND_VM_EXT_CLASS_FETCH & flags) { + switch (opline->extended_value & ZEND_FETCH_CLASS_MASK) { + case ZEND_FETCH_CLASS_SELF: + fprintf(stderr, " (self)"); + break; + case ZEND_FETCH_CLASS_PARENT: + fprintf(stderr, " (parent)"); + break; + case ZEND_FETCH_CLASS_STATIC: + fprintf(stderr, " (static)"); + break; + case ZEND_FETCH_CLASS_AUTO: + fprintf(stderr, " (auto)"); + break; + case ZEND_FETCH_CLASS_INTERFACE: + fprintf(stderr, " (interface)"); + break; + case ZEND_FETCH_CLASS_TRAIT: + fprintf(stderr, " (trait)"); + break; + } + if (opline->extended_value & ZEND_FETCH_CLASS_NO_AUTOLOAD) { + fprintf(stderr, " (no-autolod)"); + } + if (opline->extended_value & ZEND_FETCH_CLASS_SILENT) { + fprintf(stderr, " (silent)"); + } + if (opline->extended_value & ZEND_FETCH_CLASS_EXCEPTION) { + fprintf(stderr, " (exception)"); + } + } else if (ZEND_VM_EXT_CONST_FETCH & flags) { + if (opline->extended_value & IS_CONSTANT_UNQUALIFIED) { + fprintf(stderr, " (unqualified)"); + } + if (opline->extended_value & IS_CONSTANT_CLASS) { + fprintf(stderr, " (__class__)"); + } + if (opline->extended_value & IS_CONSTANT_IN_NAMESPACE) { + fprintf(stderr, " (in-namespace)"); + } + } else if (ZEND_VM_EXT_TYPE & flags) { + switch (opline->extended_value) { + case IS_NULL: + fprintf(stderr, " (null)"); + break; + case IS_FALSE: + fprintf(stderr, " (false)"); + break; + case IS_TRUE: + fprintf(stderr, " (true)"); + break; + case IS_LONG: + fprintf(stderr, " (long)"); + break; + case IS_DOUBLE: + fprintf(stderr, " (double)"); + break; + case IS_STRING: + fprintf(stderr, " (string)"); + break; + case IS_ARRAY: + fprintf(stderr, " (array)"); + break; + case IS_OBJECT: + fprintf(stderr, " (object)"); + break; + case IS_RESOURCE: + fprintf(stderr, " (resource)"); + break; + case _IS_BOOL: + fprintf(stderr, " (bool)"); + break; + case IS_CALLABLE: + fprintf(stderr, " (callable)"); + break; + case IS_VOID: + fprintf(stderr, " (void)"); + break; + default: + fprintf(stderr, " (\?\?\?)"); + break; + } + } else if (ZEND_VM_EXT_EVAL & flags) { + switch (opline->extended_value) { + case ZEND_EVAL: + fprintf(stderr, " (eval)"); + break; + case ZEND_INCLUDE: + fprintf(stderr, " (include)"); + break; + case ZEND_INCLUDE_ONCE: + fprintf(stderr, " (include_once)"); + break; + case ZEND_REQUIRE: + fprintf(stderr, " (require)"); + break; + case ZEND_REQUIRE_ONCE: + fprintf(stderr, " (require_once)"); + break; + default: + fprintf(stderr, " (\?\?\?)"); + break; + } + } else if (ZEND_VM_EXT_FAST_CALL & flags) { + if (opline->extended_value == ZEND_FAST_CALL_FROM_FINALLY) { + fprintf(stderr, " (from-finally)"); + } + } else if (ZEND_VM_EXT_FAST_RET & flags) { + if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) { + fprintf(stderr, " (to-catch)"); + } else if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) { + fprintf(stderr, " (to-finally)"); + } + } else if (ZEND_VM_EXT_SRC & flags) { + if (opline->extended_value == ZEND_RETURNS_VALUE) { + fprintf(stderr, " (value)"); + } else if (opline->extended_value == ZEND_RETURNS_FUNCTION) { + fprintf(stderr, " (function)"); + } + } else { + if (ZEND_VM_EXT_VAR_FETCH & flags) { + switch (opline->extended_value & ZEND_FETCH_TYPE_MASK) { + case ZEND_FETCH_GLOBAL: + fprintf(stderr, " (global)"); + break; + case ZEND_FETCH_LOCAL: + fprintf(stderr, " (local)"); + break; + case ZEND_FETCH_STATIC: + fprintf(stderr, " (static)"); + break; + case ZEND_FETCH_GLOBAL_LOCK: + fprintf(stderr, " (global+lock)"); + break; + case ZEND_FETCH_LEXICAL: + fprintf(stderr, " (lexical)"); + break; + } + } + if (ZEND_VM_EXT_ISSET & flags) { + if (opline->extended_value & ZEND_QUICK_SET) { + fprintf(stderr, " (quick)"); + } + if (opline->extended_value & ZEND_ISSET) { + fprintf(stderr, " (isset)"); + } else if (opline->extended_value & ZEND_ISEMPTY) { + fprintf(stderr, " (empty)"); + } + } + if (ZEND_VM_EXT_ARG_NUM & flags) { + fprintf(stderr, " %u", opline->extended_value & ZEND_FETCH_ARG_MASK); + } + if (ZEND_VM_EXT_ARRAY_INIT & flags) { + fprintf(stderr, " %u", opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT); + if (!(opline->extended_value & ZEND_ARRAY_NOT_PACKED)) { + fprintf(stderr, " (packed)"); + } + } + if (ZEND_VM_EXT_REF & flags) { + if (opline->extended_value & ZEND_ARRAY_ELEMENT_REF) { + fprintf(stderr, " (ref)"); + } + } } - fprintf(stderr, "\t%s", name ? (name + 5) : "???"); if (ZEND_VM_OP1_JMP_ADDR & flags) { if (b) { fprintf(stderr, " BB%d", b->successors[n++]); @@ -69,6 +242,12 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block * } } else if (ZEND_VM_OP1_NUM & flags) { fprintf(stderr, " %u", opline->op1.num); + } else if (ZEND_VM_OP1_TRY_CATCH & flags) { + fprintf(stderr, " try-catch(%u)", opline->op1.num); + } else if (ZEND_VM_OP1_LIVE_RANGE & flags) { + if (opline->extended_value & ZEND_FREE_ON_RETURN) { + fprintf(stderr, " live-range(%u)", opline->op1.num); + } } else if (opline->op1_type == IS_CONST) { zend_dump_const(CT_CONSTANT_EX(op_array, opline->op1.constant)); } else if (opline->op1_type == IS_CV) { @@ -86,6 +265,12 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block * } } else if (ZEND_VM_OP2_NUM & flags) { fprintf(stderr, " %u", opline->op2.num); + } else if (ZEND_VM_OP2_TRY_CATCH & flags) { + fprintf(stderr, " try-catch(%u)", opline->op2.num); + } else if (ZEND_VM_OP2_LIVE_RANGE & flags) { + if (opline->extended_value & ZEND_FREE_ON_RETURN) { + fprintf(stderr, " live-range(%u)", opline->op2.num); + } } else if (opline->op2_type == IS_CONST) { zend_dump_const(CT_CONSTANT_EX(op_array, opline->op2.constant)); } else if (opline->op2_type == IS_CV) { @@ -103,6 +288,8 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block * fprintf(stderr, " L%u", (uint32_t)ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)); } } + } else if (ZEND_VM_EXT_VAR & flags) { + fprintf(stderr, " V%u", EX_VAR_TO_NUM(opline->extended_value)); } if (opline->result_type == IS_CONST) { zend_dump_const(CT_CONSTANT_EX(op_array, opline->result.constant)); @@ -228,16 +415,30 @@ void zend_dump_op_array(const zend_op_array *op_array, const zend_cfg *cfg, uint if (op_array->last_live_range) { fprintf(stderr, "LIVE RANGES:\n"); for (i = 0; i < op_array->last_live_range; i++) { - fprintf(stderr, "\t%u: BB%u - BB%u\n", + fprintf(stderr, " %u: BB%u - BB%u ", EX_VAR_TO_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK), cfg->map[op_array->live_range[i].start], cfg->map[op_array->live_range[i].end]); + switch (op_array->live_range[i].var & ZEND_LIVE_MASK) { + case ZEND_LIVE_TMPVAR: + fprintf(stderr, "(tmp/var)\n"); + break; + case ZEND_LIVE_LOOP: + fprintf(stderr, "(loop)\n"); + break; + case ZEND_LIVE_SILENCE: + fprintf(stderr, "(silence)\n"); + break; + case ZEND_LIVE_ROPE: + fprintf(stderr, "(rope)\n"); + break; + } } } if (op_array->last_try_catch) { fprintf(stderr, "EXCEPTION TABLE:\n"); for (i = 0; i < op_array->last_try_catch; i++) { - fprintf(stderr, "\tBB%u", + fprintf(stderr, " BB%u", cfg->map[op_array->try_catch_array[i].try_op]); if (op_array->try_catch_array[i].catch_op) { fprintf(stderr, ", BB%u", @@ -270,16 +471,30 @@ void zend_dump_op_array(const zend_op_array *op_array, const zend_cfg *cfg, uint if (op_array->last_live_range) { fprintf(stderr, "LIVE RANGES:\n"); for (i = 0; i < op_array->last_live_range; i++) { - fprintf(stderr, "\t%u: L%u - L%u\n", + fprintf(stderr, " %u: L%u - L%u\n", EX_VAR_TO_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK), op_array->live_range[i].start, op_array->live_range[i].end); + switch (op_array->live_range[i].var & ZEND_LIVE_MASK) { + case ZEND_LIVE_TMPVAR: + fprintf(stderr, "(tmp/var)\n"); + break; + case ZEND_LIVE_LOOP: + fprintf(stderr, "(loop)\n"); + break; + case ZEND_LIVE_SILENCE: + fprintf(stderr, "(silence)\n"); + break; + case ZEND_LIVE_ROPE: + fprintf(stderr, "(rope)\n"); + break; + } } } if (op_array->last_try_catch) { fprintf(stderr, "EXCEPTION TABLE:\n"); for (i = 0; i < op_array->last_try_catch; i++) { - fprintf(stderr, "\tL%u", + fprintf(stderr, " L%u", op_array->try_catch_array[i].try_op); if (op_array->try_catch_array[i].catch_op) { fprintf(stderr, ", L%u", -- 2.50.1