xref: /PHP-7.2/ext/opcache/Optimizer/zend_dump.c (revision 7a7ec01a)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine, Bytecode Visualisation                                  |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2018 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Dmitry Stogov <dmitry@zend.com>                             |
16    +----------------------------------------------------------------------+
17 */
18 
19 #include "php.h"
20 #include "zend_compile.h"
21 #include "zend_cfg.h"
22 #include "zend_ssa.h"
23 #include "zend_inference.h"
24 #include "zend_func_info.h"
25 #include "zend_call_graph.h"
26 #include "zend_dump.h"
27 
zend_dump_const(const zval * zv)28 static void zend_dump_const(const zval *zv)
29 {
30 	switch (Z_TYPE_P(zv)) {
31 		case IS_NULL:
32 			fprintf(stderr, " null");
33 			break;
34 		case IS_FALSE:
35 			fprintf(stderr, " bool(false)");
36 			break;
37 		case IS_TRUE:
38 			fprintf(stderr, " bool(true)");
39 			break;
40 		case IS_LONG:
41 			fprintf(stderr, " int(" ZEND_LONG_FMT ")", Z_LVAL_P(zv));
42 			break;
43 		case IS_DOUBLE:
44 			fprintf(stderr, " float(%g)", Z_DVAL_P(zv));
45 			break;
46 		case IS_STRING:
47 			fprintf(stderr, " string(\"%s\")", Z_STRVAL_P(zv));
48 			break;
49 		case IS_ARRAY:
50 			fprintf(stderr, " array(...)");
51 			break;
52 		default:
53 			fprintf(stderr, " zval(type=%d)", Z_TYPE_P(zv));
54 			break;
55 	}
56 }
57 
zend_dump_class_fetch_type(uint32_t fetch_type)58 static void zend_dump_class_fetch_type(uint32_t fetch_type)
59 {
60 	switch (fetch_type & ZEND_FETCH_CLASS_MASK) {
61 		case ZEND_FETCH_CLASS_SELF:
62 			fprintf(stderr, " (self)");
63 			break;
64 		case ZEND_FETCH_CLASS_PARENT:
65 			fprintf(stderr, " (parent)");
66 			break;
67 		case ZEND_FETCH_CLASS_STATIC:
68 			fprintf(stderr, " (static)");
69 			break;
70 		case ZEND_FETCH_CLASS_AUTO:
71 			fprintf(stderr, " (auto)");
72 			break;
73 		case ZEND_FETCH_CLASS_INTERFACE:
74 			fprintf(stderr, " (interface)");
75 			break;
76 		case ZEND_FETCH_CLASS_TRAIT:
77 			fprintf(stderr, " (trait)");
78 			break;
79 	}
80 	if (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) {
81 			fprintf(stderr, " (no-autolod)");
82 	}
83 	if (fetch_type & ZEND_FETCH_CLASS_SILENT) {
84 			fprintf(stderr, " (silent)");
85 	}
86 	if (fetch_type & ZEND_FETCH_CLASS_EXCEPTION) {
87 			fprintf(stderr, " (exception)");
88 	}
89 }
90 
zend_dump_unused_op(const zend_op * opline,znode_op op,uint32_t flags)91 static void zend_dump_unused_op(const zend_op *opline, znode_op op, uint32_t flags) {
92 	if (ZEND_VM_OP_NUM == (flags & ZEND_VM_OP_MASK)) {
93 		fprintf(stderr, " %u", op.num);
94 	} else if (ZEND_VM_OP_TRY_CATCH == (flags & ZEND_VM_OP_MASK)) {
95 		if (op.num != (uint32_t)-1) {
96 			fprintf(stderr, " try-catch(%u)", op.num);
97 		}
98 	} else if (ZEND_VM_OP_LIVE_RANGE == (flags & ZEND_VM_OP_MASK)) {
99 		if (opline->extended_value & ZEND_FREE_ON_RETURN) {
100 			fprintf(stderr, " live-range(%u)", op.num);
101 		}
102 	} else if (ZEND_VM_OP_THIS == (flags & ZEND_VM_OP_MASK)) {
103 		fprintf(stderr, " THIS");
104 	} else if (ZEND_VM_OP_NEXT == (flags & ZEND_VM_OP_MASK)) {
105 		fprintf(stderr, " NEXT");
106 	} else if (ZEND_VM_OP_CLASS_FETCH == (flags & ZEND_VM_OP_MASK)) {
107 		zend_dump_class_fetch_type(op.num);
108 	} else if (ZEND_VM_OP_CONSTRUCTOR == (flags & ZEND_VM_OP_MASK)) {
109 		fprintf(stderr, " CONSTRUCTOR");
110 	}
111 }
112 
zend_dump_var(const zend_op_array * op_array,zend_uchar var_type,int var_num)113 void zend_dump_var(const zend_op_array *op_array, zend_uchar var_type, int var_num)
114 {
115 	if (var_type == IS_CV && var_num < op_array->last_var) {
116 		fprintf(stderr, "CV%d($%s)", var_num, op_array->vars[var_num]->val);
117 	} else if (var_type == IS_VAR) {
118 		fprintf(stderr, "V%d", var_num);
119 	} else if (var_type == IS_TMP_VAR) {
120 		fprintf(stderr, "T%d", var_num);
121 	} else {
122 		fprintf(stderr, "X%d", var_num);
123 	}
124 }
125 
zend_dump_range(const zend_ssa_range * r)126 static void zend_dump_range(const zend_ssa_range *r)
127 {
128 	if (r->underflow && r->overflow) {
129 		return;
130 	}
131 	fprintf(stderr, " RANGE[");
132 	if (r->underflow) {
133 		fprintf(stderr, "--..");
134 	} else {
135 		fprintf(stderr, ZEND_LONG_FMT "..", r->min);
136 	}
137 	if (r->overflow) {
138 		fprintf(stderr, "++]");
139 	} else {
140 		fprintf(stderr, ZEND_LONG_FMT "]", r->max);
141 	}
142 }
143 
zend_dump_type_info(uint32_t info,zend_class_entry * ce,int is_instanceof,uint32_t dump_flags)144 static void zend_dump_type_info(uint32_t info, zend_class_entry *ce, int is_instanceof, uint32_t dump_flags)
145 {
146 	int first = 1;
147 
148 	fprintf(stderr, " [");
149 	if (info & MAY_BE_UNDEF) {
150 		if (first) first = 0; else fprintf(stderr, ", ");
151 		fprintf(stderr, "undef");
152 	}
153 	if (info & MAY_BE_REF) {
154 		if (first) first = 0; else fprintf(stderr, ", ");
155 		fprintf(stderr, "ref");
156 	}
157 	if (dump_flags & ZEND_DUMP_RC_INFERENCE) {
158 		if (info & MAY_BE_RC1) {
159 			if (first) first = 0; else fprintf(stderr, ", ");
160 			fprintf(stderr, "rc1");
161 		}
162 		if (info & MAY_BE_RCN) {
163 			if (first) first = 0; else fprintf(stderr, ", ");
164 			fprintf(stderr, "rcn");
165 		}
166 	}
167 	if (info & MAY_BE_CLASS) {
168 		if (first) first = 0; else fprintf(stderr, ", ");
169 		fprintf(stderr, "class");
170 		if (ce) {
171 			if (is_instanceof) {
172 				fprintf(stderr, " (instanceof %s)", ce->name->val);
173 			} else {
174 				fprintf(stderr, " (%s)", ce->name->val);
175 			}
176 		}
177 	} else if ((info & MAY_BE_ANY) == MAY_BE_ANY) {
178 		if (first) first = 0; else fprintf(stderr, ", ");
179 		fprintf(stderr, "any");
180 	} else {
181 		if (info & MAY_BE_NULL) {
182 			if (first) first = 0; else fprintf(stderr, ", ");
183 			fprintf(stderr, "null");
184 		}
185 		if ((info & MAY_BE_FALSE) && (info & MAY_BE_TRUE)) {
186 			if (first) first = 0; else fprintf(stderr, ", ");
187 			fprintf(stderr, "bool");
188 		} else if (info & MAY_BE_FALSE) {
189 			if (first) first = 0; else fprintf(stderr, ", ");
190 			fprintf(stderr, "false");
191 		} else if (info & MAY_BE_TRUE) {
192 			if (first) first = 0; else fprintf(stderr, ", ");
193 			fprintf(stderr, "true");
194 		}
195 		if (info & MAY_BE_LONG) {
196 			if (first) first = 0; else fprintf(stderr, ", ");
197 			fprintf(stderr, "long");
198 		}
199 		if (info & MAY_BE_DOUBLE) {
200 			if (first) first = 0; else fprintf(stderr, ", ");
201 			fprintf(stderr, "double");
202 		}
203 		if (info & MAY_BE_STRING) {
204 			if (first) first = 0; else fprintf(stderr, ", ");
205 			fprintf(stderr, "string");
206 		}
207 		if (info & MAY_BE_ARRAY) {
208 			if (first) first = 0; else fprintf(stderr, ", ");
209 			fprintf(stderr, "array");
210 			if ((info & MAY_BE_ARRAY_KEY_ANY) != 0 &&
211 			    (info & MAY_BE_ARRAY_KEY_ANY) != MAY_BE_ARRAY_KEY_ANY) {
212 				int afirst = 1;
213 				fprintf(stderr, " [");
214 				if (info & MAY_BE_ARRAY_KEY_LONG) {
215 					if (afirst) afirst = 0; else fprintf(stderr, ", ");
216 					fprintf(stderr, "long");
217 				}
218 				if (info & MAY_BE_ARRAY_KEY_STRING) {
219 					if (afirst) afirst = 0; else fprintf(stderr, ", ");
220 						fprintf(stderr, "string");
221 					}
222 				fprintf(stderr, "]");
223 			}
224 			if (info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF)) {
225 				int afirst = 1;
226 				fprintf(stderr, " of [");
227 				if ((info & MAY_BE_ARRAY_OF_ANY) == MAY_BE_ARRAY_OF_ANY) {
228 					if (afirst) afirst = 0; else fprintf(stderr, ", ");
229 					fprintf(stderr, "any");
230 				} else {
231 					if (info & MAY_BE_ARRAY_OF_NULL) {
232 						if (afirst) afirst = 0; else fprintf(stderr, ", ");
233 						fprintf(stderr, "null");
234 					}
235 					if (info & MAY_BE_ARRAY_OF_FALSE) {
236 						if (afirst) afirst = 0; else fprintf(stderr, ", ");
237 						fprintf(stderr, "false");
238 					}
239 					if (info & MAY_BE_ARRAY_OF_TRUE) {
240 						if (afirst) afirst = 0; else fprintf(stderr, ", ");
241 						fprintf(stderr, "true");
242 					}
243 					if (info & MAY_BE_ARRAY_OF_LONG) {
244 						if (afirst) afirst = 0; else fprintf(stderr, ", ");
245 						fprintf(stderr, "long");
246 					}
247 					if (info & MAY_BE_ARRAY_OF_DOUBLE) {
248 						if (afirst) afirst = 0; else fprintf(stderr, ", ");
249 						fprintf(stderr, "double");
250 					}
251 					if (info & MAY_BE_ARRAY_OF_STRING) {
252 						if (afirst) afirst = 0; else fprintf(stderr, ", ");
253 						fprintf(stderr, "string");
254 					}
255 					if (info & MAY_BE_ARRAY_OF_ARRAY) {
256 						if (afirst) afirst = 0; else fprintf(stderr, ", ");
257 						fprintf(stderr, "array");
258 					}
259 					if (info & MAY_BE_ARRAY_OF_OBJECT) {
260 						if (afirst) afirst = 0; else fprintf(stderr, ", ");
261 						fprintf(stderr, "object");
262 					}
263 					if (info & MAY_BE_ARRAY_OF_RESOURCE) {
264 						if (afirst) afirst = 0; else fprintf(stderr, ", ");
265 						fprintf(stderr, "resource");
266 					}
267 				}
268 				if (info & MAY_BE_ARRAY_OF_REF) {
269 					if (afirst) afirst = 0; else fprintf(stderr, ", ");
270 					fprintf(stderr, "ref");
271 				}
272 				fprintf(stderr, "]");
273 			}
274 		}
275 		if (info & MAY_BE_OBJECT) {
276 			if (first) first = 0; else fprintf(stderr, ", ");
277 			fprintf(stderr, "object");
278 			if (ce) {
279 				if (is_instanceof) {
280 					fprintf(stderr, " (instanceof %s)", ce->name->val);
281 				} else {
282 					fprintf(stderr, " (%s)", ce->name->val);
283 				}
284 			}
285 		}
286 		if (info & MAY_BE_RESOURCE) {
287 			if (first) first = 0; else fprintf(stderr, ", ");
288 			fprintf(stderr, "resource");
289 		}
290 	}
291 	if (info & MAY_BE_ERROR) {
292 		if (first) first = 0; else fprintf(stderr, ", ");
293 		fprintf(stderr, "error");
294 	}
295 //TODO: this is useful only for JIT???
296 	if (info & MAY_BE_IN_REG) {
297 		if (first) first = 0; else fprintf(stderr, ", ");
298 		fprintf(stderr, "reg");
299 	}
300 	fprintf(stderr, "]");
301 }
302 
zend_dump_ssa_var_info(const zend_ssa * ssa,int ssa_var_num,uint32_t dump_flags)303 static void zend_dump_ssa_var_info(const zend_ssa *ssa, int ssa_var_num, uint32_t dump_flags)
304 {
305 	zend_dump_type_info(
306 		ssa->var_info[ssa_var_num].type,
307 		ssa->var_info[ssa_var_num].ce,
308 		ssa->var_info[ssa_var_num].ce ?
309 			ssa->var_info[ssa_var_num].is_instanceof : 0,
310 		dump_flags);
311 }
312 
zend_dump_ssa_var(const zend_op_array * op_array,const zend_ssa * ssa,int ssa_var_num,zend_uchar var_type,int var_num,uint32_t dump_flags)313 static void zend_dump_ssa_var(const zend_op_array *op_array, const zend_ssa *ssa, int ssa_var_num, zend_uchar var_type, int var_num, uint32_t dump_flags)
314 {
315 	if (ssa_var_num >= 0) {
316 		fprintf(stderr, "#%d.", ssa_var_num);
317 	} else {
318 		fprintf(stderr, "#?.");
319 	}
320 	zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : var_type), var_num);
321 
322 	if (ssa_var_num >= 0 && ssa->vars) {
323 		if (ssa_var_num >= 0 && ssa->vars[ssa_var_num].no_val) {
324 			fprintf(stderr, " NOVAL");
325 		}
326 		if (ssa->var_info) {
327 			zend_dump_ssa_var_info(ssa, ssa_var_num, dump_flags);
328 			if (ssa->var_info[ssa_var_num].has_range) {
329 				zend_dump_range(&ssa->var_info[ssa_var_num].range);
330 			}
331 		}
332 	}
333 }
334 
zend_dump_type_constraint(const zend_op_array * op_array,const zend_ssa * ssa,const zend_ssa_type_constraint * constraint,uint32_t dump_flags)335 static void zend_dump_type_constraint(const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_type_constraint *constraint, uint32_t dump_flags)
336 {
337 	fprintf(stderr, " TYPE");
338 	zend_dump_type_info(constraint->type_mask, constraint->ce, 1, dump_flags);
339 }
340 
zend_dump_range_constraint(const zend_op_array * op_array,const zend_ssa * ssa,const zend_ssa_range_constraint * r,uint32_t dump_flags)341 static void zend_dump_range_constraint(const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_range_constraint *r, uint32_t dump_flags)
342 {
343 	if (r->range.underflow && r->range.overflow) {
344 		return;
345 	}
346 	fprintf(stderr, " RANGE");
347 	if (r->negative) {
348 		fprintf(stderr, "~");
349 	}
350 	fprintf(stderr, "[");
351 	if (r->range.underflow) {
352 		fprintf(stderr, "-- .. ");
353 	} else {
354 		if (r->min_ssa_var >= 0) {
355 			zend_dump_ssa_var(op_array, ssa, r->min_ssa_var, (r->min_var < op_array->last_var ? IS_CV : 0), r->min_var, dump_flags);
356 			if (r->range.min > 0) {
357 				fprintf(stderr, " + " ZEND_LONG_FMT, r->range.min);
358 			} else if (r->range.min < 0) {
359 				fprintf(stderr, " - " ZEND_LONG_FMT, -r->range.min);
360 			}
361 			fprintf(stderr, " .. ");
362 		} else {
363 			fprintf(stderr, ZEND_LONG_FMT " .. ", r->range.min);
364 		}
365 	}
366 	if (r->range.overflow) {
367 		fprintf(stderr, "++]");
368 	} else {
369 		if (r->max_ssa_var >= 0) {
370 			zend_dump_ssa_var(op_array, ssa, r->max_ssa_var, (r->max_var < op_array->last_var ? IS_CV : 0), r->max_var, dump_flags);
371 			if (r->range.max > 0) {
372 				fprintf(stderr, " + " ZEND_LONG_FMT, r->range.max);
373 			} else if (r->range.max < 0) {
374 				fprintf(stderr, " - " ZEND_LONG_FMT, -r->range.max);
375 			}
376 			fprintf(stderr, "]");
377 		} else {
378 			fprintf(stderr, ZEND_LONG_FMT "]", r->range.max);
379 		}
380 	}
381 }
382 
zend_dump_op(const zend_op_array * op_array,const zend_basic_block * b,const zend_op * opline,uint32_t dump_flags,const void * data)383 static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const void *data)
384 {
385 	const char *name = zend_get_opcode_name(opline->opcode);
386 	uint32_t flags = zend_get_opcode_flags(opline->opcode);
387 	uint32_t n = 0;
388 	int len = 0;
389 	const zend_ssa *ssa = NULL;
390 
391 	if (dump_flags & ZEND_DUMP_SSA) {
392 		ssa = (const zend_ssa*)data;
393 	}
394 
395 	if (!b) {
396 		len = fprintf(stderr, "L%u (%u):", (uint32_t)(opline - op_array->opcodes), opline->lineno);
397 	}
398 	fprintf(stderr, "%*c", 12-len, ' ');
399 
400 	if (!ssa || !ssa->ops || ssa->ops[opline - op_array->opcodes].result_use < 0) {
401 		if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
402 			if (ssa && ssa->ops && ssa->ops[opline - op_array->opcodes].result_def >= 0) {
403 				int ssa_var_num = ssa->ops[opline - op_array->opcodes].result_def;
404 				zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->result_type, EX_VAR_TO_NUM(opline->result.var), dump_flags);
405 			} else {
406 				zend_dump_var(op_array, opline->result_type, EX_VAR_TO_NUM(opline->result.var));
407 			}
408 			fprintf(stderr, " = ");
409 		}
410 	}
411 
412 	if (name) {
413 		fprintf(stderr, "%s", (name + 5));
414 	} else {
415 		fprintf(stderr, "OP_%d", (int)opline->opcode);
416 	}
417 
418 	if (ZEND_VM_EXT_NUM == (flags & ZEND_VM_EXT_MASK)) {
419 		fprintf(stderr, " %u", opline->extended_value);
420 	} else if (ZEND_VM_EXT_DIM_OBJ == (flags & ZEND_VM_EXT_MASK)) {
421 		if (opline->extended_value == ZEND_ASSIGN_DIM) {
422 			fprintf(stderr, " (dim)");
423 		} else if (opline->extended_value == ZEND_ASSIGN_OBJ) {
424 			fprintf(stderr, " (obj)");
425 		}
426 	} else if (ZEND_VM_EXT_CLASS_FETCH == (flags & ZEND_VM_EXT_MASK)) {
427 		zend_dump_class_fetch_type(opline->extended_value);
428 	} else if (ZEND_VM_EXT_CONST_FETCH == (flags & ZEND_VM_EXT_MASK)) {
429 		if (opline->extended_value & IS_CONSTANT_UNQUALIFIED) {
430 				fprintf(stderr, " (unqualified)");
431 		}
432 		if (opline->extended_value & IS_CONSTANT_CLASS) {
433 				fprintf(stderr, " (__class__)");
434 		}
435 		if (opline->extended_value & IS_CONSTANT_IN_NAMESPACE) {
436 				fprintf(stderr, " (in-namespace)");
437 		}
438 	} else if (ZEND_VM_EXT_TYPE == (flags & ZEND_VM_EXT_MASK)) {
439 		switch (opline->extended_value) {
440 			case IS_NULL:
441 				fprintf(stderr, " (null)");
442 				break;
443 			case IS_FALSE:
444 				fprintf(stderr, " (false)");
445 				break;
446 			case IS_TRUE:
447 				fprintf(stderr, " (true)");
448 				break;
449 			case IS_LONG:
450 				fprintf(stderr, " (long)");
451 				break;
452 			case IS_DOUBLE:
453 				fprintf(stderr, " (double)");
454 				break;
455 			case IS_STRING:
456 				fprintf(stderr, " (string)");
457 				break;
458 			case IS_ARRAY:
459 				fprintf(stderr, " (array)");
460 				break;
461 			case IS_OBJECT:
462 				fprintf(stderr, " (object)");
463 				break;
464 			case IS_RESOURCE:
465 				fprintf(stderr, " (resource)");
466 				break;
467 			case _IS_BOOL:
468 				fprintf(stderr, " (bool)");
469 				break;
470 			case IS_CALLABLE:
471 				fprintf(stderr, " (callable)");
472 				break;
473 			case IS_VOID:
474 				fprintf(stderr, " (void)");
475 				break;
476 			default:
477 				fprintf(stderr, " (\?\?\?)");
478 				break;
479 		}
480 	} else if (ZEND_VM_EXT_EVAL == (flags & ZEND_VM_EXT_MASK)) {
481 		switch (opline->extended_value) {
482 			case ZEND_EVAL:
483 				fprintf(stderr, " (eval)");
484 				break;
485 			case ZEND_INCLUDE:
486 				fprintf(stderr, " (include)");
487 				break;
488 			case ZEND_INCLUDE_ONCE:
489 				fprintf(stderr, " (include_once)");
490 				break;
491 			case ZEND_REQUIRE:
492 				fprintf(stderr, " (require)");
493 				break;
494 			case ZEND_REQUIRE_ONCE:
495 				fprintf(stderr, " (require_once)");
496 				break;
497 			default:
498 				fprintf(stderr, " (\?\?\?)");
499 				break;
500 		}
501 	} else if (ZEND_VM_EXT_SRC == (flags & ZEND_VM_EXT_MASK)) {
502 		if (opline->extended_value == ZEND_RETURNS_VALUE) {
503 			fprintf(stderr, " (value)");
504 		} else if (opline->extended_value == ZEND_RETURNS_FUNCTION) {
505 			fprintf(stderr, " (function)");
506 		}
507 	} else {
508 		if (ZEND_VM_EXT_VAR_FETCH & flags) {
509 			switch (opline->extended_value & ZEND_FETCH_TYPE_MASK) {
510 				case ZEND_FETCH_GLOBAL:
511 					fprintf(stderr, " (global)");
512 					break;
513 				case ZEND_FETCH_LOCAL:
514 					fprintf(stderr, " (local)");
515 					break;
516 				case ZEND_FETCH_GLOBAL_LOCK:
517 					fprintf(stderr, " (global+lock)");
518 					break;
519 			}
520 		}
521 		if (ZEND_VM_EXT_ISSET & flags) {
522 			if (opline->extended_value & ZEND_ISSET) {
523 				fprintf(stderr, " (isset)");
524 			} else if (opline->extended_value & ZEND_ISEMPTY) {
525 				fprintf(stderr, " (empty)");
526 			}
527 		}
528 		if (ZEND_VM_EXT_ARG_NUM & flags) {
529 			fprintf(stderr, " %u", opline->extended_value & ZEND_FETCH_ARG_MASK);
530 		}
531 		if (ZEND_VM_EXT_ARRAY_INIT & flags) {
532 			fprintf(stderr, " %u", opline->extended_value >> ZEND_ARRAY_SIZE_SHIFT);
533 			if (!(opline->extended_value & ZEND_ARRAY_NOT_PACKED)) {
534 				fprintf(stderr, " (packed)");
535 			}
536 		}
537 		if (ZEND_VM_EXT_REF & flags) {
538 			if (opline->extended_value & ZEND_ARRAY_ELEMENT_REF) {
539 				fprintf(stderr, " (ref)");
540 			}
541 		}
542 	}
543 
544 	if (opline->op1_type == IS_CONST) {
545 		zend_dump_const(CRT_CONSTANT_EX(op_array, opline->op1, (dump_flags & ZEND_DUMP_RT_CONSTANTS)));
546 	} else if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
547 		if (ssa && ssa->ops) {
548 			int ssa_var_num = ssa->ops[opline - op_array->opcodes].op1_use;
549 			if (ssa_var_num >= 0) {
550 				fprintf(stderr, " ");
551 				zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->op1_type, EX_VAR_TO_NUM(opline->op1.var), dump_flags);
552 			} else if (ssa->ops[opline - op_array->opcodes].op1_def < 0) {
553 				fprintf(stderr, " ");
554 				zend_dump_var(op_array, opline->op1_type, EX_VAR_TO_NUM(opline->op1.var));
555 			}
556 		} else {
557 			fprintf(stderr, " ");
558 			zend_dump_var(op_array, opline->op1_type, EX_VAR_TO_NUM(opline->op1.var));
559 		}
560 		if (ssa && ssa->ops) {
561 			int ssa_var_num = ssa->ops[opline - op_array->opcodes].op1_def;
562 			if (ssa_var_num >= 0) {
563 				fprintf(stderr, " -> ");
564 				zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->op1_type, EX_VAR_TO_NUM(opline->op1.var), dump_flags);
565 			}
566 		}
567 	} else {
568 		uint32_t op1_flags = ZEND_VM_OP1_FLAGS(flags);
569 		if (ZEND_VM_OP_JMP_ADDR == (op1_flags & ZEND_VM_OP_MASK)) {
570 			if (b) {
571 				fprintf(stderr, " BB%d", b->successors[n++]);
572 			} else {
573 				fprintf(stderr, " L%u", (uint32_t)(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes));
574 			}
575 		} else {
576 			zend_dump_unused_op(opline, opline->op1, op1_flags);
577 		}
578 	}
579 
580 	if (opline->op2_type == IS_CONST) {
581 		zval *op = CRT_CONSTANT_EX(op_array, opline->op2, (dump_flags & ZEND_DUMP_RT_CONSTANTS));
582 		if (opline->opcode == ZEND_SWITCH_LONG || opline->opcode == ZEND_SWITCH_STRING) {
583 			HashTable *jumptable = Z_ARRVAL_P(op);
584 			zend_string *key;
585 			zend_ulong num_key;
586 			zval *zv;
587 			ZEND_HASH_FOREACH_KEY_VAL(jumptable, num_key, key, zv) {
588 				if (key) {
589 					fprintf(stderr, " \"%s\":", ZSTR_VAL(key));
590 				} else {
591 					fprintf(stderr, " " ZEND_LONG_FMT ":", num_key);
592 				}
593 				if (b) {
594 					fprintf(stderr, " BB%d,", b->successors[n++]);
595 				} else {
596 					fprintf(stderr, " L%u,", (uint32_t)ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv)));
597 				}
598 			} ZEND_HASH_FOREACH_END();
599 			fprintf(stderr, " default:");
600 		} else {
601 			zend_dump_const(op);
602 		}
603 	} else if (opline->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
604 		if (ssa && ssa->ops) {
605 			int ssa_var_num = ssa->ops[opline - op_array->opcodes].op2_use;
606 			if (ssa_var_num >= 0) {
607 				fprintf(stderr, " ");
608 				zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->op2_type, EX_VAR_TO_NUM(opline->op2.var), dump_flags);
609 			} else if (ssa->ops[opline - op_array->opcodes].op2_def < 0) {
610 				fprintf(stderr, " ");
611 				zend_dump_var(op_array, opline->op2_type, EX_VAR_TO_NUM(opline->op2.var));
612 			}
613 		} else {
614 			fprintf(stderr, " ");
615 			zend_dump_var(op_array, opline->op2_type, EX_VAR_TO_NUM(opline->op2.var));
616 		}
617 		if (ssa && ssa->ops) {
618 			int ssa_var_num = ssa->ops[opline - op_array->opcodes].op2_def;
619 			if (ssa_var_num >= 0) {
620 				fprintf(stderr, " -> ");
621 				zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->op2_type, EX_VAR_TO_NUM(opline->op2.var), dump_flags);
622 			}
623 		}
624 	} else {
625 		uint32_t op2_flags = ZEND_VM_OP2_FLAGS(flags);
626 		if (ZEND_VM_OP_JMP_ADDR == (op2_flags & ZEND_VM_OP_MASK)) {
627 			if (b) {
628 				fprintf(stderr, " BB%d", b->successors[n++]);
629 			} else {
630 				fprintf(stderr, " L%u", (uint32_t)(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes));
631 			}
632 		} else {
633 			zend_dump_unused_op(opline, opline->op2, op2_flags);
634 		}
635 	}
636 
637 	if (ZEND_VM_EXT_JMP_ADDR == (flags & ZEND_VM_EXT_MASK)) {
638 		if (opline->opcode != ZEND_CATCH || !opline->result.num) {
639 			if (b) {
640 				fprintf(stderr, " BB%d", b->successors[n++]);
641 			} else {
642 				fprintf(stderr, " L%u", (uint32_t)ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
643 			}
644 		}
645 	}
646 	if (opline->result_type == IS_CONST) {
647 		zend_dump_const(CRT_CONSTANT_EX(op_array, opline->result, (dump_flags & ZEND_DUMP_RT_CONSTANTS)));
648 	} else if (ssa && ssa->ops && ssa->ops[opline - op_array->opcodes].result_use >= 0) {
649 		if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
650 			if (ssa && ssa->ops) {
651 				int ssa_var_num = ssa->ops[opline - op_array->opcodes].result_use;
652 				if (ssa_var_num >= 0) {
653 					fprintf(stderr, " ");
654 					zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->result_type, EX_VAR_TO_NUM(opline->result.var), dump_flags);
655 				}
656 			} else {
657 				fprintf(stderr, " ");
658 				zend_dump_var(op_array, opline->result_type, EX_VAR_TO_NUM(opline->result.var));
659 			}
660 			if (ssa && ssa->ops) {
661 				int ssa_var_num = ssa->ops[opline - op_array->opcodes].result_def;
662 				if (ssa_var_num >= 0) {
663 					fprintf(stderr, " -> ");
664 					zend_dump_ssa_var(op_array, ssa, ssa_var_num, opline->result_type, EX_VAR_TO_NUM(opline->result.var), dump_flags);
665 				}
666 			}
667 		}
668 	}
669 	fprintf(stderr, "\n");
670 }
671 
zend_dump_block_info(const zend_cfg * cfg,int n,uint32_t dump_flags)672 static void zend_dump_block_info(const zend_cfg *cfg, int n, uint32_t dump_flags)
673 {
674 	zend_basic_block *b = cfg->blocks + n;
675 
676 	fprintf(stderr, "BB%d:", n);
677 	if (b->flags & ZEND_BB_START) {
678 		fprintf(stderr, " start");
679 	}
680 	if (b->flags & ZEND_BB_FOLLOW) {
681 		fprintf(stderr, " follow");
682 	}
683 	if (b->flags & ZEND_BB_TARGET) {
684 		fprintf(stderr, " target");
685 	}
686 	if (b->flags & ZEND_BB_EXIT) {
687 		fprintf(stderr, " exit");
688 	}
689 	if (b->flags & (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) {
690 		fprintf(stderr, " entry");
691 	}
692 	if (b->flags & ZEND_BB_TRY) {
693 		fprintf(stderr, " try");
694 	}
695 	if (b->flags & ZEND_BB_CATCH) {
696 		fprintf(stderr, " catch");
697 	}
698 	if (b->flags & ZEND_BB_FINALLY) {
699 		fprintf(stderr, " finally");
700 	}
701 	if (b->flags & ZEND_BB_FINALLY_END) {
702 		fprintf(stderr, " finally_end");
703 	}
704 	if (b->flags & ZEND_BB_GEN_VAR) {
705 		fprintf(stderr, " gen_var");
706 	}
707 	if (b->flags & ZEND_BB_KILL_VAR) {
708 		fprintf(stderr, " kill_var");
709 	}
710 	if (!(dump_flags & ZEND_DUMP_HIDE_UNREACHABLE) && !(b->flags & ZEND_BB_REACHABLE)) {
711 		fprintf(stderr, " unreachable");
712 	}
713 	if (b->flags & ZEND_BB_LOOP_HEADER) {
714 		fprintf(stderr, " loop_header");
715 	}
716 	if (b->flags & ZEND_BB_IRREDUCIBLE_LOOP) {
717 		fprintf(stderr, " irreducible");
718 	}
719 	if (b->len != 0) {
720 		fprintf(stderr, " lines=[%d-%d]", b->start, b->start + b->len - 1);
721 	} else {
722 		fprintf(stderr, " empty");
723 	}
724 	fprintf(stderr, "\n");
725 
726 	if (b->predecessors_count) {
727 		int *p = cfg->predecessors + b->predecessor_offset;
728 		int *end = p + b->predecessors_count;
729 
730 		fprintf(stderr, "    ; from=(BB%d", *p);
731 		for (p++; p < end; p++) {
732 			fprintf(stderr, ", BB%d", *p);
733 		}
734 		fprintf(stderr, ")\n");
735 	}
736 
737 	if (b->successors_count > 0) {
738 		int s;
739 		fprintf(stderr, "    ; to=(BB%d", b->successors[0]);
740 		for (s = 1; s < b->successors_count; s++) {
741 			fprintf(stderr, ", BB%d", b->successors[s]);
742 		}
743 		fprintf(stderr, ")\n");
744 	}
745 
746 	if (b->idom >= 0) {
747 		fprintf(stderr, "    ; idom=BB%d\n", b->idom);
748 	}
749 	if (b->level >= 0) {
750 		fprintf(stderr, "    ; level=%d\n", b->level);
751 	}
752 	if (b->loop_header >= 0) {
753 		fprintf(stderr, "    ; loop_header=%d\n", b->loop_header);
754 	}
755 	if (b->children >= 0) {
756 		int j = b->children;
757 		fprintf(stderr, "    ; children=(BB%d", j);
758 		j = cfg->blocks[j].next_child;
759 		while (j >= 0) {
760 			fprintf(stderr, ", BB%d", j);
761 			j = cfg->blocks[j].next_child;
762 		}
763 		fprintf(stderr, ")\n");
764 	}
765 }
766 
zend_dump_block_header(const zend_cfg * cfg,const zend_op_array * op_array,const zend_ssa * ssa,int n,uint32_t dump_flags)767 static void zend_dump_block_header(const zend_cfg *cfg, const zend_op_array *op_array, const zend_ssa *ssa, int n, uint32_t dump_flags)
768 {
769 	zend_dump_block_info(cfg, n, dump_flags);
770 	if (ssa && ssa->blocks && ssa->blocks[n].phis) {
771 		zend_ssa_phi *p = ssa->blocks[n].phis;
772 
773 		do {
774 			int j;
775 
776 			fprintf(stderr, "        ");
777 			zend_dump_ssa_var(op_array, ssa, p->ssa_var, 0, p->var, dump_flags);
778 			if (p->pi < 0) {
779 				fprintf(stderr, " = Phi(");
780 				for (j = 0; j < cfg->blocks[n].predecessors_count; j++) {
781 					if (j > 0) {
782 						fprintf(stderr, ", ");
783 					}
784 					zend_dump_ssa_var(op_array, ssa, p->sources[j], 0, p->var, dump_flags);
785 				}
786 				fprintf(stderr, ")\n");
787 			} else {
788 				fprintf(stderr, " = Pi<BB%d>(", p->pi);
789 				zend_dump_ssa_var(op_array, ssa, p->sources[0], 0, p->var, dump_flags);
790 				fprintf(stderr, " &");
791 				if (p->has_range_constraint) {
792 					zend_dump_range_constraint(op_array, ssa, &p->constraint.range, dump_flags);
793 				} else {
794 					zend_dump_type_constraint(op_array, ssa, &p->constraint.type, dump_flags);
795 				}
796 				fprintf(stderr, ")\n");
797 			}
798 			p = p->next;
799 		} while (p);
800 	}
801 }
802 
zend_dump_op_array_name(const zend_op_array * op_array)803 static void zend_dump_op_array_name(const zend_op_array *op_array)
804 {
805 	zend_func_info *func_info = NULL;
806 
807 	func_info = ZEND_FUNC_INFO(op_array);
808 	if (op_array->function_name) {
809 		if (op_array->scope && op_array->scope->name) {
810 			fprintf(stderr, "%s::%s", op_array->scope->name->val, op_array->function_name->val);
811 		} else {
812 			fprintf(stderr, "%s", op_array->function_name->val);
813 		}
814 	} else {
815 		fprintf(stderr, "%s", "$_main");
816 	}
817 	if (func_info && func_info->clone_num > 0) {
818 		fprintf(stderr, "_@_clone_%d", func_info->clone_num);
819 	}
820 }
821 
zend_dump_op_array(const zend_op_array * op_array,uint32_t dump_flags,const char * msg,const void * data)822 void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, const char *msg, const void *data)
823 {
824 	int i;
825 	const zend_cfg *cfg = NULL;
826 	const zend_ssa *ssa = NULL;
827 	zend_func_info *func_info = NULL;
828 	uint32_t func_flags = 0;
829 
830 	if (dump_flags & (ZEND_DUMP_CFG|ZEND_DUMP_SSA)) {
831 		cfg = (const zend_cfg*)data;
832 		if (!cfg->blocks) {
833 			cfg = data = NULL;
834 		}
835 	}
836 	if (dump_flags & ZEND_DUMP_SSA) {
837 		ssa = (const zend_ssa*)data;
838 	}
839 
840 	func_info = ZEND_FUNC_INFO(op_array);
841 	if (func_info) {
842 		func_flags = func_info->flags;
843 	}
844 
845 	fprintf(stderr, "\n");
846 	zend_dump_op_array_name(op_array);
847 	fprintf(stderr, ": ; (lines=%d, args=%d",
848 		op_array->last,
849 		op_array->num_args);
850 	if (func_info && func_info->num_args >= 0) {
851 		fprintf(stderr, "/%d", func_info->num_args);
852 	}
853 	fprintf(stderr, ", vars=%d, tmps=%d", op_array->last_var, op_array->T);
854 	if (ssa) {
855 		fprintf(stderr, ", ssa_vars=%d", ssa->vars_count);
856 	}
857 	if (func_flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) {
858 		fprintf(stderr, ", dynamic");
859 	}
860 	if (func_flags & ZEND_FUNC_RECURSIVE) {
861 		fprintf(stderr, ", recursive");
862 		if (func_flags & ZEND_FUNC_RECURSIVE_DIRECTLY) {
863 			fprintf(stderr, " directly");
864 		}
865 		if (func_flags & ZEND_FUNC_RECURSIVE_INDIRECTLY) {
866 			fprintf(stderr, " indirectly");
867 		}
868 	}
869 	if (func_flags & ZEND_FUNC_IRREDUCIBLE) {
870 		fprintf(stderr, ", irreducable");
871 	}
872 	if (func_flags & ZEND_FUNC_NO_LOOPS) {
873 		fprintf(stderr, ", no_loops");
874 	}
875 //TODO: this is useful only for JIT???
876 #if 0
877 	if (info->flags & ZEND_JIT_FUNC_NO_IN_MEM_CVS) {
878 		fprintf(stderr, ", no_in_mem_cvs");
879 	}
880 	if (info->flags & ZEND_JIT_FUNC_NO_USED_ARGS) {
881 		fprintf(stderr, ", no_used_args");
882 	}
883 	if (info->flags & ZEND_JIT_FUNC_NO_SYMTAB) {
884 		fprintf(stderr, ", no_symtab");
885 	}
886 	if (info->flags & ZEND_JIT_FUNC_NO_FRAME) {
887 		fprintf(stderr, ", no_frame");
888 	}
889 	if (info->flags & ZEND_JIT_FUNC_INLINE) {
890 		fprintf(stderr, ", inline");
891 	}
892 #endif
893 	if (func_info && func_info->return_value_used == 0) {
894 		fprintf(stderr, ", no_return_value");
895 	} else if (func_info && func_info->return_value_used == 1) {
896 		fprintf(stderr, ", return_value");
897 	}
898 	fprintf(stderr, ")\n");
899 	if (msg) {
900 		fprintf(stderr, "    ; (%s)\n", msg);
901 	}
902 	fprintf(stderr, "    ; %s:%u-%u\n", op_array->filename->val, op_array->line_start, op_array->line_end);
903 
904 	if (func_info && func_info->num_args > 0) {
905 		uint32_t j;
906 
907 		for (j = 0; j < MIN(op_array->num_args, func_info->num_args ); j++) {
908 			fprintf(stderr, "    ; arg %d ", j);
909 			zend_dump_type_info(func_info->arg_info[j].info.type, func_info->arg_info[j].info.ce, func_info->arg_info[j].info.is_instanceof, dump_flags);
910 			zend_dump_range(&func_info->arg_info[j].info.range);
911 			fprintf(stderr, "\n");
912 		}
913 	}
914 
915 	if (func_info) {
916 		fprintf(stderr, "    ; return ");
917 		zend_dump_type_info(func_info->return_info.type, func_info->return_info.ce, func_info->return_info.is_instanceof, dump_flags);
918 		zend_dump_range(&func_info->return_info.range);
919 		fprintf(stderr, "\n");
920 	}
921 
922 	if (ssa && ssa->var_info) {
923 		for (i = 0; i < op_array->last_var; i++) {
924 			fprintf(stderr, "    ; ");
925 			zend_dump_ssa_var(op_array, ssa, i, IS_CV, i, dump_flags);
926 			fprintf(stderr, "\n");
927 		}
928 	}
929 
930 	if (cfg) {
931 		int n;
932 		zend_basic_block *b;
933 
934 		for (n = 0; n < cfg->blocks_count; n++) {
935 			b = cfg->blocks + n;
936 			if (!(dump_flags & ZEND_DUMP_HIDE_UNREACHABLE) || (b->flags & ZEND_BB_REACHABLE)) {
937 				const zend_op *opline;
938 				const zend_op *end;
939 
940 				zend_dump_block_header(cfg, op_array, ssa, n, dump_flags);
941 				opline = op_array->opcodes + b->start;
942 				end = opline + b->len;
943 				while (opline < end) {
944 					zend_dump_op(op_array, b, opline, dump_flags, data);
945 					opline++;
946 				}
947 			}
948 		}
949 		if (op_array->last_live_range) {
950 			fprintf(stderr, "LIVE RANGES:\n");
951 			for (i = 0; i < op_array->last_live_range; i++) {
952 				if (cfg->split_at_live_ranges) {
953 					fprintf(stderr, "        %u: BB%u - BB%u ",
954 						EX_VAR_TO_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK),
955 						cfg->map[op_array->live_range[i].start],
956 						cfg->map[op_array->live_range[i].end]);
957 				} else {
958 					fprintf(stderr, "        %u: L%u - L%u ",
959 						EX_VAR_TO_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK),
960 						op_array->live_range[i].start,
961 						op_array->live_range[i].end);
962 				}
963 				switch (op_array->live_range[i].var & ZEND_LIVE_MASK) {
964 					case ZEND_LIVE_TMPVAR:
965 						fprintf(stderr, "(tmp/var)\n");
966 						break;
967 					case ZEND_LIVE_LOOP:
968 						fprintf(stderr, "(loop)\n");
969 						break;
970 					case ZEND_LIVE_SILENCE:
971 						fprintf(stderr, "(silence)\n");
972 						break;
973 					case ZEND_LIVE_ROPE:
974 						fprintf(stderr, "(rope)\n");
975 						break;
976 				}
977 			}
978 		}
979 		if (op_array->last_try_catch) {
980 			fprintf(stderr, "EXCEPTION TABLE:\n");
981 			for (i = 0; i < op_array->last_try_catch; i++) {
982 				fprintf(stderr, "        BB%u",
983 					cfg->map[op_array->try_catch_array[i].try_op]);
984 				if (op_array->try_catch_array[i].catch_op) {
985 					fprintf(stderr, ", BB%u",
986 						cfg->map[op_array->try_catch_array[i].catch_op]);
987 				} else {
988 					fprintf(stderr, ", -");
989 				}
990 				if (op_array->try_catch_array[i].finally_op) {
991 					fprintf(stderr, ", BB%u",
992 						cfg->map[op_array->try_catch_array[i].finally_op]);
993 				} else {
994 					fprintf(stderr, ", -");
995 				}
996 				if (op_array->try_catch_array[i].finally_end) {
997 					fprintf(stderr, ", BB%u\n",
998 						cfg->map[op_array->try_catch_array[i].finally_end]);
999 				} else {
1000 					fprintf(stderr, ", -\n");
1001 				}
1002 			}
1003 		}
1004 	} else {
1005 		const zend_op *opline = op_array->opcodes;
1006 		const zend_op *end = opline + op_array->last;
1007 
1008 		while (opline < end) {
1009 			zend_dump_op(op_array, NULL, opline, dump_flags, data);
1010 			opline++;
1011 		}
1012 		if (op_array->last_live_range) {
1013 			fprintf(stderr, "LIVE RANGES:\n");
1014 			for (i = 0; i < op_array->last_live_range; i++) {
1015 				fprintf(stderr, "        %u: L%u - L%u ",
1016 					EX_VAR_TO_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK),
1017 					op_array->live_range[i].start,
1018 					op_array->live_range[i].end);
1019 				switch (op_array->live_range[i].var & ZEND_LIVE_MASK) {
1020 					case ZEND_LIVE_TMPVAR:
1021 						fprintf(stderr, "(tmp/var)\n");
1022 						break;
1023 					case ZEND_LIVE_LOOP:
1024 						fprintf(stderr, "(loop)\n");
1025 						break;
1026 					case ZEND_LIVE_SILENCE:
1027 						fprintf(stderr, "(silence)\n");
1028 						break;
1029 					case ZEND_LIVE_ROPE:
1030 						fprintf(stderr, "(rope)\n");
1031 						break;
1032 				}
1033 			}
1034 		}
1035 		if (op_array->last_try_catch) {
1036 			fprintf(stderr, "EXCEPTION TABLE:\n");
1037 			for (i = 0; i < op_array->last_try_catch; i++) {
1038 				fprintf(stderr, "        L%u",
1039 					op_array->try_catch_array[i].try_op);
1040 				if (op_array->try_catch_array[i].catch_op) {
1041 					fprintf(stderr, ", L%u",
1042 						op_array->try_catch_array[i].catch_op);
1043 				} else {
1044 					fprintf(stderr, ", -");
1045 				}
1046 				if (op_array->try_catch_array[i].finally_op) {
1047 					fprintf(stderr, ", L%u",
1048 						op_array->try_catch_array[i].finally_op);
1049 				} else {
1050 					fprintf(stderr, ", -");
1051 				}
1052 				if (op_array->try_catch_array[i].finally_end) {
1053 					fprintf(stderr, ", L%u\n",
1054 						op_array->try_catch_array[i].finally_end);
1055 				} else {
1056 					fprintf(stderr, ", -\n");
1057 				}
1058 			}
1059 		}
1060 	}
1061 }
1062 
zend_dump_dominators(const zend_op_array * op_array,const zend_cfg * cfg)1063 void zend_dump_dominators(const zend_op_array *op_array, const zend_cfg *cfg)
1064 {
1065 	int j;
1066 
1067 	fprintf(stderr, "\nDOMINATORS-TREE for \"");
1068 	zend_dump_op_array_name(op_array);
1069 	fprintf(stderr, "\"\n");
1070 	for (j = 0; j < cfg->blocks_count; j++) {
1071 		zend_basic_block *b = cfg->blocks + j;
1072 		if (b->flags & ZEND_BB_REACHABLE) {
1073 			zend_dump_block_info(cfg, j, 0);
1074 		}
1075 	}
1076 }
1077 
zend_dump_variables(const zend_op_array * op_array)1078 void zend_dump_variables(const zend_op_array *op_array)
1079 {
1080 	int j;
1081 
1082 	fprintf(stderr, "\nCV Variables for \"");
1083 	zend_dump_op_array_name(op_array);
1084 	fprintf(stderr, "\"\n");
1085 	for (j = 0; j < op_array->last_var; j++) {
1086 		fprintf(stderr, "    ");
1087 		zend_dump_var(op_array, IS_CV, j);
1088 		fprintf(stderr, "\n");
1089 	}
1090 }
1091 
zend_dump_ssa_variables(const zend_op_array * op_array,const zend_ssa * ssa,uint32_t dump_flags)1092 void zend_dump_ssa_variables(const zend_op_array *op_array, const zend_ssa *ssa, uint32_t dump_flags)
1093 {
1094 	int j;
1095 
1096 	if (ssa->vars) {
1097 		fprintf(stderr, "\nSSA Variable for \"");
1098 		zend_dump_op_array_name(op_array);
1099 		fprintf(stderr, "\"\n");
1100 
1101 		for (j = 0; j < ssa->vars_count; j++) {
1102 			fprintf(stderr, "    ");
1103 			zend_dump_ssa_var(op_array, ssa, j, IS_CV, ssa->vars[j].var, dump_flags);
1104 			if (ssa->vars[j].scc >= 0) {
1105 				if (ssa->vars[j].scc_entry) {
1106 					fprintf(stderr, " *");
1107 				}  else {
1108 					fprintf(stderr, "  ");
1109 				}
1110 				fprintf(stderr, "SCC=%d", ssa->vars[j].scc);
1111 			}
1112 			fprintf(stderr, "\n");
1113 		}
1114 	}
1115 }
1116 
zend_dump_var_set(const zend_op_array * op_array,const char * name,zend_bitset set)1117 static void zend_dump_var_set(const zend_op_array *op_array, const char *name, zend_bitset set)
1118 {
1119 	int first = 1;
1120 	uint32_t i;
1121 
1122 	fprintf(stderr, "    ; %s = {", name);
1123 	for (i = 0; i < op_array->last_var + op_array->T; i++) {
1124 		if (zend_bitset_in(set, i)) {
1125 			if (first) {
1126 				first = 0;
1127 			} else {
1128 				fprintf(stderr, ", ");
1129 			}
1130 			zend_dump_var(op_array, IS_CV, i);
1131 		}
1132 	}
1133 	fprintf(stderr, "}\n");
1134 }
1135 
zend_dump_dfg(const zend_op_array * op_array,const zend_cfg * cfg,const zend_dfg * dfg)1136 void zend_dump_dfg(const zend_op_array *op_array, const zend_cfg *cfg, const zend_dfg *dfg)
1137 {
1138 	int j;
1139 	fprintf(stderr, "\nVariable Liveness for \"");
1140 	zend_dump_op_array_name(op_array);
1141 	fprintf(stderr, "\"\n");
1142 
1143 	for (j = 0; j < cfg->blocks_count; j++) {
1144 		fprintf(stderr, "  BB%d:\n", j);
1145 		zend_dump_var_set(op_array, "def", DFG_BITSET(dfg->def, dfg->size, j));
1146 		zend_dump_var_set(op_array, "use", DFG_BITSET(dfg->use, dfg->size, j));
1147 		zend_dump_var_set(op_array, "in ", DFG_BITSET(dfg->in,  dfg->size, j));
1148 		zend_dump_var_set(op_array, "out", DFG_BITSET(dfg->out, dfg->size, j));
1149 	}
1150 }
1151 
zend_dump_phi_placement(const zend_op_array * op_array,const zend_ssa * ssa)1152 void zend_dump_phi_placement(const zend_op_array *op_array, const zend_ssa *ssa)
1153 {
1154 	int j;
1155 	zend_ssa_block *ssa_blocks = ssa->blocks;
1156 	int blocks_count = ssa->cfg.blocks_count;
1157 
1158 	fprintf(stderr, "\nSSA Phi() Placement for \"");
1159 	zend_dump_op_array_name(op_array);
1160 	fprintf(stderr, "\"\n");
1161 	for (j = 0; j < blocks_count; j++) {
1162 		if (ssa_blocks && ssa_blocks[j].phis) {
1163 			zend_ssa_phi *p = ssa_blocks[j].phis;
1164 			int first = 1;
1165 
1166 			fprintf(stderr, "  BB%d:\n", j);
1167 			if (p->pi >= 0) {
1168 				fprintf(stderr, "    ; pi={");
1169 			} else {
1170 				fprintf(stderr, "    ; phi={");
1171 			}
1172 			do {
1173 				if (first) {
1174 					first = 0;
1175 				} else {
1176 					fprintf(stderr, ", ");
1177 				}
1178 				zend_dump_var(op_array, IS_CV, p->var);
1179 				p = p->next;
1180 			} while (p);
1181 			fprintf(stderr, "}\n");
1182 		}
1183 	}
1184 }
1185 
1186 /*
1187  * Local variables:
1188  * tab-width: 4
1189  * c-basic-offset: 4
1190  * indent-tabs-mode: t
1191  * End:
1192  */
1193