Example #1
0
int zend_optimizer_replace_by_const(zend_op_array *op_array,
                                    zend_op       *opline,
                                    zend_uchar     type,
                                    uint32_t       var,
                                    zval          *val)
{
	zend_op *end = op_array->opcodes + op_array->last;

	while (opline < end) {
		if (ZEND_OP1_TYPE(opline) == type &&
			ZEND_OP1(opline).var == var) {
			switch (opline->opcode) {
				case ZEND_FETCH_DIM_W:
				case ZEND_FETCH_DIM_RW:
				case ZEND_FETCH_DIM_FUNC_ARG:
				case ZEND_FETCH_DIM_UNSET:
				case ZEND_ASSIGN_DIM:
				case ZEND_SEPARATE:
					return 0;
				case ZEND_SEND_VAR:
					opline->extended_value = 0;
					opline->opcode = ZEND_SEND_VAL;
					break;
				case ZEND_SEND_VAR_EX:
					opline->extended_value = 0;
					opline->opcode = ZEND_SEND_VAL_EX;
					break;
				case ZEND_SEND_VAR_NO_REF:
					if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) {
						if (opline->extended_value & ZEND_ARG_SEND_BY_REF) {
							zval_dtor(val);
							return 0;
						}
						opline->extended_value = 0;
						opline->opcode = ZEND_SEND_VAL_EX;
					} else {
						opline->extended_value = 0;
						opline->opcode = ZEND_SEND_VAL;
					}
					break;
				/* In most cases IS_TMP_VAR operand may be used only once.
				 * The operands are usually destroyed by the opcode handler.
				 * ZEND_CASE is an exception, that keeps operand unchanged,
				 * and allows its reuse. The number of ZEND_CASE instructions
				 * usually terminated by ZEND_FREE that finally kills the value.
				 */
				case ZEND_FREE:
				case ZEND_CASE: {
					zend_op *m, *n;
					int brk = op_array->last_brk_cont;
					zend_bool in_switch = 0;
					while (brk--) {
						if (op_array->brk_cont_array[brk].start <= (opline - op_array->opcodes) &&
								op_array->brk_cont_array[brk].brk > (opline - op_array->opcodes)) {
							in_switch = 1;
							break;
						}
					}

					if (!in_switch) {
						ZEND_ASSERT(opline->opcode == ZEND_FREE);
						MAKE_NOP(opline);
						zval_dtor(val);
						return 1;
					}

					m = opline;
					n = op_array->opcodes + op_array->brk_cont_array[brk].brk + 1;
					while (m < n) {
						if (ZEND_OP1_TYPE(m) == type &&
								ZEND_OP1(m).var == var) {
							if (m->opcode == ZEND_CASE) {
								zval old_val;
								ZVAL_COPY_VALUE(&old_val, val);
								zval_copy_ctor(val);
								zend_optimizer_update_op1_const(op_array, m, val);
								ZVAL_COPY_VALUE(val, &old_val);
							} else if (m->opcode == ZEND_FREE) {
								MAKE_NOP(m);
							} else {
								ZEND_ASSERT(0);
							}
						}
						m++;
					}
					zval_dtor(val);
					return 1;
				}
				case ZEND_VERIFY_RETURN_TYPE: {
					zend_arg_info *ret_info = op_array->arg_info - 1;
					ZEND_ASSERT((opline + 1)->opcode == ZEND_RETURN || (opline + 1)->opcode == ZEND_RETURN_BY_REF);
					if (ret_info->class_name
						|| ret_info->type_hint == IS_CALLABLE
						|| !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(val))
						|| (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
						zval_dtor(val);
						return 0;
					}
					MAKE_NOP(opline);
					zend_optimizer_update_op1_const(op_array, opline + 1, val);
					return 1;
				  }
				default:
					break;
			}
			zend_optimizer_update_op1_const(op_array, opline, val);
			break;
		}

		if (ZEND_OP2_TYPE(opline) == type &&
			ZEND_OP2(opline).var == var) {
			switch (opline->opcode) {
				case ZEND_ASSIGN_REF:
					zval_dtor(val);
					return 0;
				default:
					break;
			}
			zend_optimizer_update_op2_const(op_array, opline, val);
			break;
		}
		opline++;
	}

	return 1;
}
Example #2
0
int zend_optimizer_replace_by_const(zend_op_array *op_array,
                                    zend_op       *opline,
                                    zend_uchar     type,
                                    uint32_t       var,
                                    zval          *val)
{
	zend_op *end = op_array->opcodes + op_array->last;

	while (opline < end) {
		if (ZEND_OP1_TYPE(opline) == type &&
			ZEND_OP1(opline).var == var) {
			switch (opline->opcode) {
				case ZEND_FETCH_DIM_W:
				case ZEND_FETCH_DIM_RW:
				case ZEND_FETCH_DIM_FUNC_ARG:
				case ZEND_FETCH_DIM_UNSET:
				case ZEND_ASSIGN_DIM:
				case ZEND_SEPARATE:
					return 0;
				case ZEND_SEND_VAR:
					opline->extended_value = 0;
					opline->opcode = ZEND_SEND_VAL;
					break;
				case ZEND_SEND_VAR_EX:
					opline->extended_value = 0;
					opline->opcode = ZEND_SEND_VAL_EX;
					break;
				case ZEND_SEND_VAR_NO_REF:
					if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) {
						if (opline->extended_value & ZEND_ARG_SEND_BY_REF) {
							return 0;
						}
						opline->extended_value = 0;
						opline->opcode = ZEND_SEND_VAL_EX;
					} else {
						opline->extended_value = 0;
						opline->opcode = ZEND_SEND_VAL;
					}
					break;
				/* In most cases IS_TMP_VAR operand may be used only once.
				 * The operands are usually destroyed by the opcode handler.
				 * ZEND_CASE is an exception, that keeps operand unchanged,
				 * and allows its reuse. The number of ZEND_CASE instructions
				 * usually terminated by ZEND_FREE that finally kills the value.
				 */
				case ZEND_CASE: {
					zval old_val;
					ZVAL_COPY_VALUE(&old_val, val);
					zval_copy_ctor(val);
					zend_optimizer_update_op1_const(op_array, opline, val);
					ZVAL_COPY_VALUE(val, &old_val);
					opline++;
					continue;
				}
				case ZEND_FREE:
					MAKE_NOP(opline);
					zval_dtor(val);
					return 1;
				default:
					break;
			}
			zend_optimizer_update_op1_const(op_array, opline, val);
			break;
		}

		if (ZEND_OP2_TYPE(opline) == type &&
			ZEND_OP2(opline).var == var) {
			switch (opline->opcode) {
				case ZEND_ASSIGN_REF:
					return 0;
				default:
					break;
			}
			zend_optimizer_update_op2_const(op_array, opline, val);
			break;
		}
		opline++;
	}

	return 1;
}