void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *ctx) { int T = op_array->T; int offset = op_array->last_var; char *taken_T; /* T index in use */ zend_op **start_of_T; /* opline where T is first used */ char *valid_T; /* Is the map_T valid */ int *map_T; /* Map's the T to its new index */ zend_op *opline, *end; int currT; int i; int max = -1; int var_to_free = -1; void *checkpoint = zend_arena_checkpoint(ctx->arena); taken_T = (char *) zend_arena_alloc(&ctx->arena, T); start_of_T = (zend_op **) zend_arena_alloc(&ctx->arena, T * sizeof(zend_op *)); valid_T = (char *) zend_arena_alloc(&ctx->arena, T); map_T = (int *) zend_arena_alloc(&ctx->arena, T * sizeof(int)); end = op_array->opcodes; opline = &op_array->opcodes[op_array->last - 1]; /* Find T definition points */ while (opline >= end) { if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) { start_of_T[VAR_NUM(ZEND_RESULT(opline).var) - offset] = opline; } /* special puprose variable to keep HashPointer on VM stack */ if (opline->opcode == ZEND_OP_DATA && (opline-1)->opcode == ZEND_FE_FETCH && opline->op1_type == IS_TMP_VAR) { start_of_T[VAR_NUM(ZEND_OP1(opline).var) - offset] = opline; if (sizeof(HashPointer) > sizeof(zval)) { /* Make shure 1 zval is enough for HashPointer (2 must be enough) */ start_of_T[VAR_NUM(ZEND_OP1(opline).var) + 1 - offset] = opline; } } opline--; } memset(valid_T, 0, T); memset(taken_T, 0, T); end = op_array->opcodes; opline = &op_array->opcodes[op_array->last - 1]; while (opline >= end) { if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) { /* special puprose variable to keep HashPointer on VM stack */ if (opline->opcode == ZEND_OP_DATA && (opline-1)->opcode == ZEND_FE_FETCH && opline->op1_type == IS_TMP_VAR) { max++; ZEND_OP1(opline).var = NUM_VAR(max + offset); if (sizeof(HashPointer) > sizeof(zval)) { /* Make shure 1 zval is enough for HashPointer (2 must be enough) */ max++; } } else { currT = VAR_NUM(ZEND_OP1(opline).var) - offset; if (!valid_T[currT]) { GET_AVAILABLE_T(); map_T[currT] = i; valid_T[currT] = 1; } ZEND_OP1(opline).var = NUM_VAR(map_T[currT] + offset); } } /* Skip OP_DATA */ if (opline->opcode == ZEND_OP_DATA && (opline-1)->opcode == ZEND_ASSIGN_DIM) { opline--; continue; } if ((ZEND_OP2_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) { currT = VAR_NUM(ZEND_OP2(opline).var) - offset; if (!valid_T[currT]) { GET_AVAILABLE_T(); map_T[currT] = i; valid_T[currT] = 1; } ZEND_OP2(opline).var = NUM_VAR(map_T[currT] + offset); } if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS || opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) { currT = VAR_NUM(opline->extended_value) - offset; if (!valid_T[currT]) { GET_AVAILABLE_T(); map_T[currT] = i; valid_T[currT] = 1; } opline->extended_value = NUM_VAR(map_T[currT] + offset); } /* Allocate OP_DATA->op2 after "operands", but before "result" */ if (opline->opcode == ZEND_ASSIGN_DIM && (opline + 1)->opcode == ZEND_OP_DATA && ZEND_OP2_TYPE(opline + 1) & (IS_VAR | IS_TMP_VAR)) { currT = VAR_NUM(ZEND_OP2(opline + 1).var) - offset; GET_AVAILABLE_T(); map_T[currT] = i; valid_T[currT] = 1; taken_T[i] = 0; ZEND_OP2(opline + 1).var = NUM_VAR(i + offset); var_to_free = i; } if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) { currT = VAR_NUM(ZEND_RESULT(opline).var) - offset; if (valid_T[currT]) { if (start_of_T[currT] == opline) { taken_T[map_T[currT]] = 0; } ZEND_RESULT(opline).var = NUM_VAR(map_T[currT] + offset); } else { /* Au still needs to be assigned a T which is a bit dumb. Should consider changing Zend */ GET_AVAILABLE_T(); if (RESULT_UNUSED(opline)) { taken_T[i] = 0; } else { /* Code which gets here is using a wrongly built opcode such as RECV() */ map_T[currT] = i; valid_T[currT] = 1; } ZEND_RESULT(opline).var = NUM_VAR(i + offset); } } if (var_to_free >= 0) { taken_T[var_to_free] = 0; var_to_free = -1; } opline--; } zend_arena_release(&ctx->arena, checkpoint); op_array->T = max + 1; }
int vld_dump_zval (zval val) { #if PHP_VERSION_ID >= 70000 switch (val.u1.v.type) { #else switch (val.type) { #endif case IS_NULL: return vld_dump_zval_null (val.value); case IS_LONG: return vld_dump_zval_long (val.value); case IS_DOUBLE: return vld_dump_zval_double (val.value); case IS_STRING: return vld_dump_zval_string (val.value); case IS_ARRAY: return vld_dump_zval_array (val.value); case IS_OBJECT: return vld_dump_zval_object (val.value); case IS_RESOURCE: return vld_dump_zval_resource (val.value); case IS_CONSTANT: return vld_dump_zval_constant (val.value); #if PHP_VERSION_ID >= 50600 case IS_CONSTANT_AST: return vld_dump_zval_constant_ast (val.value); #else case IS_CONSTANT_ARRAY: return vld_dump_zval_constant_array (val.value); #endif #if PHP_VERSION_ID >= 70000 case IS_UNDEF: return vld_dump_zval_undef (val.value); case IS_FALSE: return vld_dump_zval_false (val.value); case IS_TRUE: return vld_dump_zval_true (val.value); case IS_REFERENCE: return vld_dump_zval_reference (val.value); case IS_CALLABLE: return vld_dump_zval_callable (val.value); case IS_INDIRECT: return vld_dump_zval_indirect (val.value); case IS_PTR: return vld_dump_zval_ptr (val.value); #else case IS_BOOL: return vld_dump_zval_bool (val.value); #endif } return vld_printf(stderr, "<unknown>"); } int vld_dump_znode (int *print_sep, unsigned int node_type, VLD_ZNODE node, unsigned int base_address, zend_op_array *op_array, int opline TSRMLS_DC) { int len = 0; if (node_type != IS_UNUSED && print_sep) { if (*print_sep) { len += vld_printf (stderr, ", "); } *print_sep = 1; } switch (node_type) { case IS_UNUSED: VLD_PRINT(3, " IS_UNUSED "); break; case IS_CONST: /* 1 */ #if PHP_VERSION_ID >= 70000 VLD_PRINT1(3, " IS_CONST (%d) ", VLD_ZNODE_ELEM(node, var) / sizeof(zval)); #else VLD_PRINT1(3, " IS_CONST (%d) ", VLD_ZNODE_ELEM(node, var) / sizeof(temp_variable)); #endif #if PHP_VERSION_ID >= 70000 vld_dump_zval(*RT_CONSTANT_EX(op_array->literals, node)); #else # if PHP_VERSION_ID >= 50399 vld_dump_zval(*node.zv); # else vld_dump_zval(node.u.constant); # endif #endif break; #if defined(ZEND_ENGINE_2) || defined(ZEND_ENGINE_3) case IS_TMP_VAR: /* 2 */ VLD_PRINT(3, " IS_TMP_VAR "); len += vld_printf (stderr, "~%d", VAR_NUM(VLD_ZNODE_ELEM(node, var))); break; case IS_VAR: /* 4 */ VLD_PRINT(3, " IS_VAR "); len += vld_printf (stderr, "$%d", VAR_NUM(VLD_ZNODE_ELEM(node, var))); break; #if (PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1) case IS_CV: /* 16 */ VLD_PRINT(3, " IS_CV "); #if PHP_VERSION_ID >= 70000 len += vld_printf (stderr, "!%d", (VLD_ZNODE_ELEM(node, var)-sizeof(zend_execute_data)) / sizeof(zval)); #else len += vld_printf (stderr, "!%d", VLD_ZNODE_ELEM(node, var)); #endif break; #endif case VLD_IS_OPNUM: #if PHP_VERSION_ID >= 70000 len += vld_printf (stderr, "->%d", VLD_ZNODE_JMP_LINE(node, opline, base_address)); #else len += vld_printf (stderr, "->%d", VLD_ZNODE_ELEM(node, opline_num)); #endif break; case VLD_IS_OPLINE: #if PHP_VERSION_ID >= 70000 len += vld_printf (stderr, "->%d", VLD_ZNODE_JMP_LINE(node, opline, base_address)); #else len += vld_printf (stderr, "->%d", (VLD_ZNODE_ELEM(node, opline_num) - base_address) / sizeof(zend_op)); #endif break; case VLD_IS_CLASS: len += vld_printf (stderr, ":%d", VAR_NUM(VLD_ZNODE_ELEM(node, var))); break; #else /* ZEND_ENGINE_1 */ case IS_TMP_VAR: /* 2 */ len += vld_printf (stderr, "~%d", node.u.var); break; case IS_VAR: /* 4 */ len += vld_printf (stderr, "$%d", node.u.var); break; case VLD_IS_OPNUM: case VLD_IS_OPLINE: len += vld_printf (stderr, "->%d", node.u.opline_num); break; case VLD_IS_CLASS: len += vld_printf (stderr, ":%d", node.u.var); break; #endif default: return 0; } return len; }
void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *ctx) { int T = op_array->T; int offset = op_array->last_var; char *taken_T; /* T index in use */ zend_op **start_of_T; /* opline where T is first used */ char *valid_T; /* Is the map_T valid */ int *map_T; /* Map's the T to its new index */ zend_op *opline, *end; int currT; int i; int max = -1; int var_to_free = -1; void *checkpoint = zend_arena_checkpoint(ctx->arena); taken_T = (char *) zend_arena_alloc(&ctx->arena, T); start_of_T = (zend_op **) zend_arena_alloc(&ctx->arena, T * sizeof(zend_op *)); valid_T = (char *) zend_arena_alloc(&ctx->arena, T); map_T = (int *) zend_arena_alloc(&ctx->arena, T * sizeof(int)); end = op_array->opcodes; opline = &op_array->opcodes[op_array->last - 1]; /* Find T definition points */ while (opline >= end) { if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) { start_of_T[VAR_NUM(ZEND_RESULT(opline).var) - offset] = opline; } opline--; } memset(valid_T, 0, T); memset(taken_T, 0, T); end = op_array->opcodes; opline = &op_array->opcodes[op_array->last - 1]; while (opline >= end) { if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) { currT = VAR_NUM(ZEND_OP1(opline).var) - offset; if (opline->opcode == ZEND_ROPE_END) { int num = (((opline->extended_value + 1) * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval); int var; var = max; while (var >= 0 && !taken_T[var]) { var--; } max = MAX(max, var + num); var = var + 1; map_T[currT] = var; valid_T[currT] = 1; taken_T[var] = 1; ZEND_OP1(opline).var = NUM_VAR(var + offset); while (num > 1) { num--; taken_T[var + num] = 1; } } else { if (!valid_T[currT]) { GET_AVAILABLE_T(); map_T[currT] = i; valid_T[currT] = 1; } ZEND_OP1(opline).var = NUM_VAR(map_T[currT] + offset); } } /* Skip OP_DATA */ if (opline->opcode == ZEND_OP_DATA && (opline-1)->opcode == ZEND_ASSIGN_DIM) { opline--; continue; } if ((ZEND_OP2_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) { currT = VAR_NUM(ZEND_OP2(opline).var) - offset; if (!valid_T[currT]) { GET_AVAILABLE_T(); map_T[currT] = i; valid_T[currT] = 1; } ZEND_OP2(opline).var = NUM_VAR(map_T[currT] + offset); } if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS || opline->opcode == ZEND_DECLARE_ANON_INHERITED_CLASS || opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) { currT = VAR_NUM(opline->extended_value) - offset; if (!valid_T[currT]) { GET_AVAILABLE_T(); map_T[currT] = i; valid_T[currT] = 1; } opline->extended_value = NUM_VAR(map_T[currT] + offset); } /* Allocate OP_DATA->op2 after "operands", but before "result" */ if (opline->opcode == ZEND_ASSIGN_DIM && (opline + 1)->opcode == ZEND_OP_DATA && ZEND_OP2_TYPE(opline + 1) & (IS_VAR | IS_TMP_VAR)) { currT = VAR_NUM(ZEND_OP2(opline + 1).var) - offset; GET_AVAILABLE_T(); map_T[currT] = i; valid_T[currT] = 1; taken_T[i] = 0; ZEND_OP2(opline + 1).var = NUM_VAR(i + offset); var_to_free = i; } if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) { currT = VAR_NUM(ZEND_RESULT(opline).var) - offset; if (valid_T[currT]) { if (start_of_T[currT] == opline) { taken_T[map_T[currT]] = 0; } ZEND_RESULT(opline).var = NUM_VAR(map_T[currT] + offset); if (opline->opcode == ZEND_ROPE_INIT) { if (start_of_T[currT] == opline) { uint32_t num = ((opline->extended_value * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval); while (num > 1) { num--; taken_T[map_T[currT]+num] = 0; } } } } else { /* Au still needs to be assigned a T which is a bit dumb. Should consider changing Zend */ GET_AVAILABLE_T(); if (RESULT_UNUSED(opline)) { taken_T[i] = 0; } else { /* Code which gets here is using a wrongly built opcode such as RECV() */ map_T[currT] = i; valid_T[currT] = 1; } ZEND_RESULT(opline).var = NUM_VAR(i + offset); } } if (var_to_free >= 0) { taken_T[var_to_free] = 0; var_to_free = -1; } opline--; } zend_arena_release(&ctx->arena, checkpoint); op_array->T = max + 1; }
void zend_optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *ctx) { int T = op_array->T; int offset = op_array->last_var; uint32_t bitset_len; zend_bitset taken_T; /* T index in use */ zend_op **start_of_T; /* opline where T is first used */ zend_bitset valid_T; /* Is the map_T valid */ int *map_T; /* Map's the T to its new index */ zend_op *opline, *end; int currT; int i; int max = -1; int var_to_free = -1; void *checkpoint = zend_arena_checkpoint(ctx->arena); bitset_len = zend_bitset_len(T); taken_T = (zend_bitset) zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE); start_of_T = (zend_op **) zend_arena_alloc(&ctx->arena, T * sizeof(zend_op *)); valid_T = (zend_bitset) zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE); map_T = (int *) zend_arena_alloc(&ctx->arena, T * sizeof(int)); end = op_array->opcodes; opline = &op_array->opcodes[op_array->last - 1]; /* Find T definition points */ while (opline >= end) { if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) { start_of_T[VAR_NUM(ZEND_RESULT(opline).var) - offset] = opline; } opline--; } zend_bitset_clear(valid_T, bitset_len); zend_bitset_clear(taken_T, bitset_len); end = op_array->opcodes; opline = &op_array->opcodes[op_array->last - 1]; while (opline >= end) { if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) { currT = VAR_NUM(ZEND_OP1(opline).var) - offset; if (opline->opcode == ZEND_ROPE_END) { int num = (((opline->extended_value + 1) * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval); int var; var = max; while (var >= 0 && !zend_bitset_in(taken_T, var)) { var--; } max = MAX(max, var + num); var = var + 1; map_T[currT] = var; zend_bitset_incl(valid_T, currT); zend_bitset_incl(taken_T, var); ZEND_OP1(opline).var = NUM_VAR(var + offset); while (num > 1) { num--; zend_bitset_incl(taken_T, var + num); } } else { if (!zend_bitset_in(valid_T, currT)) { int use_new_var = 0; /* Code in "finally" blocks may modify temorary variables. * We allocate new temporaries for values that need to * relive FAST_CALLs. */ if ((op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) && (opline->opcode == ZEND_RETURN || opline->opcode == ZEND_GENERATOR_RETURN || opline->opcode == ZEND_RETURN_BY_REF || opline->opcode == ZEND_FREE || opline->opcode == ZEND_FE_FREE)) { zend_op *curr = opline; while (--curr >= end) { if (curr->opcode == ZEND_FAST_CALL) { use_new_var = 1; break; } else if (curr->opcode != ZEND_FREE && curr->opcode != ZEND_FE_FREE && curr->opcode != ZEND_VERIFY_RETURN_TYPE && curr->opcode != ZEND_DISCARD_EXCEPTION) { break; } } } if (use_new_var) { i = ++max; zend_bitset_incl(taken_T, i); } else { GET_AVAILABLE_T(); } map_T[currT] = i; zend_bitset_incl(valid_T, currT); } ZEND_OP1(opline).var = NUM_VAR(map_T[currT] + offset); } } if ((ZEND_OP2_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) { currT = VAR_NUM(ZEND_OP2(opline).var) - offset; if (!zend_bitset_in(valid_T, currT)) { GET_AVAILABLE_T(); map_T[currT] = i; zend_bitset_incl(valid_T, currT); } ZEND_OP2(opline).var = NUM_VAR(map_T[currT] + offset); } if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) { currT = VAR_NUM(ZEND_RESULT(opline).var) - offset; if (zend_bitset_in(valid_T, currT)) { if (start_of_T[currT] == opline) { /* ZEND_FAST_CALL can not share temporary var with others * since the fast_var could also be set by ZEND_HANDLE_EXCEPTION * which could be ahead of it */ if (opline->opcode != ZEND_FAST_CALL) { zend_bitset_excl(taken_T, map_T[currT]); } } ZEND_RESULT(opline).var = NUM_VAR(map_T[currT] + offset); if (opline->opcode == ZEND_ROPE_INIT) { if (start_of_T[currT] == opline) { uint32_t num = ((opline->extended_value * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval); while (num > 1) { num--; zend_bitset_excl(taken_T, map_T[currT]+num); } } } } else { /* Code which gets here is using a wrongly built opcode such as RECV() */ GET_AVAILABLE_T(); map_T[currT] = i; zend_bitset_incl(valid_T, currT); ZEND_RESULT(opline).var = NUM_VAR(i + offset); } } if (var_to_free >= 0) { zend_bitset_excl(taken_T, var_to_free); var_to_free = -1; } opline--; } if (op_array->live_range) { for (i = 0; i < op_array->last_live_range; i++) { op_array->live_range[i].var = NUM_VAR(map_T[VAR_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK) - offset] + offset) | (op_array->live_range[i].var & ZEND_LIVE_MASK); } } zend_arena_release(&ctx->arena, checkpoint); op_array->T = max + 1; }
/* This pass removes all CVs and temporaries that are completely unused. It does *not* merge any CVs or TMPs. * This pass does not operate on SSA form anymore. */ void zend_optimizer_compact_vars(zend_op_array *op_array) { int i; ALLOCA_FLAG(use_heap1); ALLOCA_FLAG(use_heap2); uint32_t used_vars_len = zend_bitset_len(op_array->last_var + op_array->T); zend_bitset used_vars = ZEND_BITSET_ALLOCA(used_vars_len, use_heap1); uint32_t *vars_map = do_alloca((op_array->last_var + op_array->T) * sizeof(uint32_t), use_heap2); uint32_t num_cvs, num_tmps; /* Determine which CVs are used */ zend_bitset_clear(used_vars, used_vars_len); for (i = 0; i < op_array->last; i++) { zend_op *opline = &op_array->opcodes[i]; if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { zend_bitset_incl(used_vars, VAR_NUM(opline->op1.var)); } if (opline->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { zend_bitset_incl(used_vars, VAR_NUM(opline->op2.var)); } if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { zend_bitset_incl(used_vars, VAR_NUM(opline->result.var)); if (opline->opcode == ZEND_ROPE_INIT) { uint32_t num = ((opline->extended_value * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval); while (num > 1) { num--; zend_bitset_incl(used_vars, VAR_NUM(opline->result.var) + num); } } } } num_cvs = 0; for (i = 0; i < op_array->last_var; i++) { if (zend_bitset_in(used_vars, i)) { vars_map[i] = num_cvs++; } else { vars_map[i] = (uint32_t) -1; } } num_tmps = 0; for (i = op_array->last_var; i < op_array->last_var + op_array->T; i++) { if (zend_bitset_in(used_vars, i)) { vars_map[i] = num_cvs + num_tmps++; } else { vars_map[i] = (uint32_t) -1; } } free_alloca(used_vars, use_heap1); if (num_cvs == op_array->last_var && num_tmps == op_array->T) { free_alloca(vars_map, use_heap2); return; } ZEND_ASSERT(num_cvs <= op_array->last_var); ZEND_ASSERT(num_tmps <= op_array->T); /* Update CV and TMP references in opcodes */ for (i = 0; i < op_array->last; i++) { zend_op *opline = &op_array->opcodes[i]; if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { opline->op1.var = NUM_VAR(vars_map[VAR_NUM(opline->op1.var)]); } if (opline->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { opline->op2.var = NUM_VAR(vars_map[VAR_NUM(opline->op2.var)]); } if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { opline->result.var = NUM_VAR(vars_map[VAR_NUM(opline->result.var)]); } } /* Update TMP references in live ranges */ if (op_array->live_range) { for (i = 0; i < op_array->last_live_range; i++) { op_array->live_range[i].var = (op_array->live_range[i].var & ZEND_LIVE_MASK) | NUM_VAR(vars_map[VAR_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK)]); } } /* Update CV name table */ if (num_cvs != op_array->last_var) { zend_string **names = safe_emalloc(sizeof(zend_string *), num_cvs, 0); for (i = 0; i < op_array->last_var; i++) { if (vars_map[i] != (uint32_t) -1) { names[vars_map[i]] = op_array->vars[i]; } else { zend_string_release(op_array->vars[i]); } } efree(op_array->vars); op_array->vars = names; } op_array->last_var = num_cvs; op_array->T = num_tmps; free_alloca(vars_map, use_heap2); }
int vld_dump_znode (int *print_sep, unsigned int node_type, VLD_ZNODE node, zend_uint base_address TSRMLS_DC) { int len = 0; if (node_type != IS_UNUSED && print_sep) { if (*print_sep) { len += vld_printf (stderr, ", "); } *print_sep = 1; } switch (node_type) { case IS_UNUSED: VLD_PRINT(3, " IS_UNUSED "); break; case IS_CONST: /* 1 */ VLD_PRINT1(3, " IS_CONST (%d) ", VLD_ZNODE_ELEM(node, var) / sizeof(temp_variable)); #if PHP_VERSION_ID >= 50399 vld_dump_zval(*node.zv); #else vld_dump_zval(node.u.constant); #endif break; #ifdef ZEND_ENGINE_2 case IS_TMP_VAR: /* 2 */ VLD_PRINT(3, " IS_TMP_VAR "); len += vld_printf (stderr, "~%d", VAR_NUM(VLD_ZNODE_ELEM(node, var))); break; case IS_VAR: /* 4 */ VLD_PRINT(3, " IS_VAR "); len += vld_printf (stderr, "$%d", VAR_NUM(VLD_ZNODE_ELEM(node, var))); break; #if (PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1) case IS_CV: /* 16 */ VLD_PRINT(3, " IS_CV "); len += vld_printf (stderr, "!%d", VLD_ZNODE_ELEM(node, var)); break; #endif case VLD_IS_OPNUM: len += vld_printf (stderr, "->%d", VLD_ZNODE_ELEM(node, opline_num)); break; case VLD_IS_OPLINE: len += vld_printf (stderr, "->%d", (VLD_ZNODE_ELEM(node, opline_num) - base_address) / sizeof(zend_op)); break; case VLD_IS_CLASS: len += vld_printf (stderr, ":%d", VAR_NUM(VLD_ZNODE_ELEM(node, var))); break; #else case IS_TMP_VAR: /* 2 */ len += vld_printf (stderr, "~%d", node.u.var); break; case IS_VAR: /* 4 */ len += vld_printf (stderr, "$%d", node.u.var); break; case VLD_IS_OPNUM: case VLD_IS_OPLINE: len += vld_printf (stderr, "->%d", node.u.opline_num); break; case VLD_IS_CLASS: len += vld_printf (stderr, ":%d", node.u.var); break; #endif default: return 0; } return len; }