Exemplo n.º 1
0
static void zend_mark_reachable(zend_op *opcodes, zend_basic_block *blocks, zend_basic_block *b) /* {{{ */
{
	zend_uchar opcode;
	zend_basic_block *b0;
	int successor_0, successor_1;

	while (1) {
		b->flags |= ZEND_BB_REACHABLE;
		successor_0 = b->successors[0];
		if (successor_0 >= 0) {
			successor_1 = b->successors[1];
			if (successor_1 >= 0) {
				b0 = blocks + successor_0;
				b0->flags |= ZEND_BB_TARGET;
				if (!(b0->flags & ZEND_BB_REACHABLE)) {
					zend_mark_reachable(opcodes, blocks, b0);
				}
				opcode = opcodes[b->end].opcode;
				b = blocks + successor_1;
				if (opcode == ZEND_JMPZNZ) {
					b->flags |= ZEND_BB_TARGET;
				} else {
					b->flags |= ZEND_BB_FOLLOW;
				}
			} else {
				opcode = opcodes[b->end].opcode;
				b = blocks + successor_0;
				if (opcode == ZEND_JMP) {
					b->flags |= ZEND_BB_TARGET;
				} else {
					b->flags |= ZEND_BB_FOLLOW;

					//TODO: support for stackless CFG???
					if (0/*stackless*/) {
						if (opcode == ZEND_INCLUDE_OR_EVAL ||
						    opcode == ZEND_YIELD ||
						    opcode == ZEND_YIELD_FROM ||
						    opcode == ZEND_DO_FCALL ||
						    opcode == ZEND_DO_UCALL ||
						    opcode == ZEND_DO_FCALL_BY_NAME) {
							b->flags |= ZEND_BB_ENTRY;
						}
					}
				}
			}
			if (b->flags & ZEND_BB_REACHABLE) return;
		} else {
			b->flags |= ZEND_BB_EXIT;
			return;
		}
	}
}
Exemplo n.º 2
0
static void zend_mark_reachable_blocks(const zend_op_array *op_array, zend_cfg *cfg, int start) /* {{{ */
{
	zend_basic_block *blocks = cfg->blocks;

	blocks[start].flags = ZEND_BB_START;
	zend_mark_reachable(op_array->opcodes, blocks, blocks + start);

	if (op_array->last_live_range || op_array->last_try_catch) {
		zend_basic_block *b;
		int j, changed;
		uint32_t *block_map = cfg->map;

		do {
			changed = 0;

			/* Add brk/cont paths */
			for (j = 0; j < op_array->last_live_range; j++) {
				if (op_array->live_range[j].var == (uint32_t)-1) {
					/* this live range already removed */
					continue;
				}
				b = blocks + block_map[op_array->live_range[j].start];
				if (b->flags & ZEND_BB_REACHABLE) {
					while (op_array->opcodes[b->start].opcode == ZEND_NOP && b->start != b->end) {
						b->start++;
					}
					if (op_array->opcodes[b->start].opcode == ZEND_NOP &&
					    b->start == b->end &&
					    b->successors[0] == block_map[op_array->live_range[j].end]) {
						/* mark as removed (empty live range) */
						op_array->live_range[j].var = (uint32_t)-1;
						continue;
					}
					b->flags |= ZEND_BB_GEN_VAR;
					b = blocks + block_map[op_array->live_range[j].end];
					b->flags |= ZEND_BB_KILL_VAR;
					if (!(b->flags & ZEND_BB_REACHABLE)) {
						changed = 1;
						zend_mark_reachable(op_array->opcodes, blocks, b);
					}
				} else {
					ZEND_ASSERT(!(blocks[block_map[op_array->live_range[j].end]].flags & ZEND_BB_REACHABLE));
				}
			}

			/* Add exception paths */
			for (j = 0; j < op_array->last_try_catch; j++) {

				/* check for jumps into the middle of try block */
				b = blocks + block_map[op_array->try_catch_array[j].try_op];
				if (!(b->flags & ZEND_BB_REACHABLE)) {
					zend_basic_block *end;

					if (op_array->try_catch_array[j].catch_op) {
						end = blocks + block_map[op_array->try_catch_array[j].catch_op];
						while (b != end) {
							if (b->flags & ZEND_BB_REACHABLE) {
								op_array->try_catch_array[j].try_op = b->start;
								break;
							}
							b++;
						}
					}
					b = blocks + block_map[op_array->try_catch_array[j].try_op];
					if (!(b->flags & ZEND_BB_REACHABLE)) {
						if (op_array->try_catch_array[j].finally_op) {
							end = blocks + block_map[op_array->try_catch_array[j].finally_op];
							while (b != end) {
								if (b->flags & ZEND_BB_REACHABLE) {
									op_array->try_catch_array[j].try_op = op_array->try_catch_array[j].catch_op;
									changed = 1;
									zend_mark_reachable(op_array->opcodes, blocks, blocks + block_map[op_array->try_catch_array[j].try_op]);
									break;
								}
								b++;
							}
						}
					}
				}

				b = blocks + block_map[op_array->try_catch_array[j].try_op];
				if (b->flags & ZEND_BB_REACHABLE) {
					b->flags |= ZEND_BB_TRY;
					if (op_array->try_catch_array[j].catch_op) {
						b = blocks + block_map[op_array->try_catch_array[j].catch_op];
						b->flags |= ZEND_BB_CATCH;
						if (!(b->flags & ZEND_BB_REACHABLE)) {
							changed = 1;
							zend_mark_reachable(op_array->opcodes, blocks, b);
						}
					}
					if (op_array->try_catch_array[j].finally_op) {
						b = blocks + block_map[op_array->try_catch_array[j].finally_op];
						b->flags |= ZEND_BB_FINALLY;
						if (!(b->flags & ZEND_BB_REACHABLE)) {
							changed = 1;
							zend_mark_reachable(op_array->opcodes, blocks, b);
						}
					}
					if (op_array->try_catch_array[j].finally_end) {
						b = blocks + block_map[op_array->try_catch_array[j].finally_end];
						b->flags |= ZEND_BB_FINALLY_END;
						if (!(b->flags & ZEND_BB_REACHABLE)) {
							changed = 1;
							zend_mark_reachable(op_array->opcodes, blocks, b);
						}
					}
				} else {
					if (op_array->try_catch_array[j].catch_op) {
						ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].catch_op]].flags & ZEND_BB_REACHABLE));
					}
					if (op_array->try_catch_array[j].finally_op) {
						ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].finally_op]].flags & ZEND_BB_REACHABLE));
					}
					if (op_array->try_catch_array[j].finally_end) {
						ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].finally_end]].flags & ZEND_BB_REACHABLE));
					}
				}
			}
		} while (changed);
	}
}
Exemplo n.º 3
0
static void zend_mark_reachable_blocks(zend_op_array *op_array, zend_cfg *cfg, int start)
{
	zend_basic_block *blocks = cfg->blocks;

	blocks[start].flags = ZEND_BB_START;
	zend_mark_reachable(op_array->opcodes, blocks, blocks + start);

	if (op_array->last_live_range || op_array->last_try_catch) {
		zend_basic_block *b;
		int j, changed;
		uint32_t *block_map = cfg->map;

		do {
			changed = 0;

			/* Add brk/cont paths */
			for (j = 0; j < op_array->last_live_range; j++) {
				b = blocks + block_map[op_array->live_range[j].start];
				if (b->flags & ZEND_BB_REACHABLE) {
					b->flags |= ZEND_BB_GEN_VAR;
					b = blocks + block_map[op_array->live_range[j].end];
					b->flags |= ZEND_BB_KILL_VAR;
					if (!(b->flags & ZEND_BB_REACHABLE)) {
						changed = 1;
						zend_mark_reachable(op_array->opcodes, blocks, b);
					}
				} else {
					ZEND_ASSERT(!(blocks[block_map[op_array->live_range[j].end]].flags & ZEND_BB_REACHABLE));
				}
			}

			/* Add exception paths */
			for (j = 0; j < op_array->last_try_catch; j++) {

				/* check for jumps into the middle of try block */
				b = blocks + block_map[op_array->try_catch_array[j].try_op];
				if (!(b->flags & ZEND_BB_REACHABLE)) {
					zend_basic_block *end;

					if (op_array->try_catch_array[j].catch_op) {
						end = blocks + block_map[op_array->try_catch_array[j].catch_op];
						while (b != end) {
							if (b->flags & ZEND_BB_REACHABLE) {
								op_array->try_catch_array[j].try_op = b->start;
								break;
							}
							b++;
						}
					}
					b = blocks + block_map[op_array->try_catch_array[j].try_op];
					if (!(b->flags & ZEND_BB_REACHABLE)) {
						if (op_array->try_catch_array[j].finally_op) {
							end = blocks + block_map[op_array->try_catch_array[j].finally_op];
							while (b != end) {
								if (b->flags & ZEND_BB_REACHABLE) {
									op_array->try_catch_array[j].try_op = op_array->try_catch_array[j].catch_op;
									changed = 1;
									zend_mark_reachable(op_array->opcodes, blocks, blocks + block_map[op_array->try_catch_array[j].try_op]);
									break;
								}
								b++;
							}
						}
					}
				}

				b = blocks + block_map[op_array->try_catch_array[j].try_op];
				if (b->flags & ZEND_BB_REACHABLE) {
					b->flags |= ZEND_BB_TRY;
					if (op_array->try_catch_array[j].catch_op) {
						b = blocks + block_map[op_array->try_catch_array[j].catch_op];
						b->flags |= ZEND_BB_CATCH;
						if (!(b->flags & ZEND_BB_REACHABLE)) {
							changed = 1;
							zend_mark_reachable(op_array->opcodes, blocks, b);
						}
					}
					if (op_array->try_catch_array[j].finally_op) {
						b = blocks + block_map[op_array->try_catch_array[j].finally_op];
						b->flags |= ZEND_BB_FINALLY;
						if (!(b->flags & ZEND_BB_REACHABLE)) {
							changed = 1;
							zend_mark_reachable(op_array->opcodes, blocks, b);
						}
					}
					if (op_array->try_catch_array[j].finally_end) {
						b = blocks + block_map[op_array->try_catch_array[j].finally_end];
						b->flags |= ZEND_BB_FINALLY_END;
						if (!(b->flags & ZEND_BB_REACHABLE)) {
							changed = 1;
							zend_mark_reachable(op_array->opcodes, blocks, b);
						}
					}
				} else {
					if (op_array->try_catch_array[j].catch_op) {
						ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].catch_op]].flags & ZEND_BB_REACHABLE));
					}
					if (op_array->try_catch_array[j].finally_op) {
						ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].finally_op]].flags & ZEND_BB_REACHABLE));
					}
					if (op_array->try_catch_array[j].finally_end) {
						ZEND_ASSERT(!(blocks[block_map[op_array->try_catch_array[j].finally_end]].flags & ZEND_BB_REACHABLE));
					}
				}
			}
		} while (changed);
	}
}