root/ext/opcache/Optimizer/optimize_temp_vars_5.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. optimize_temporary_variables

#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO

/* ops that use CLs:
op1:
ZEND_FETCH_CONSTANT:
ZEND_INIT_CTOR_CALL:
ZEND_INIT_STATIC_METHOD_CALL:
ZEND_INIT_METHOD_CALL:
ZEND_IMPORT_CLASS:
ZEND_IMPORT_FUNCTION:
ZEND_IMPORT_CONST:
ZEND_ADD_INTERFACE:
ZEND_VERIFY_ABSTRACT_CLASS:
ZEND_NEW:
ZEND_CATCH:
ZEND_INIT_FCALL_BY_NAME:

op2:
ZEND_UNSET_VAR:
ZEND_ISSET_ISEMPTY_VAR:
ZEND_FETCH_UNSET:
ZEND_FETCH_IS:
ZEND_FETCH_R:
ZEND_FETCH_W:
ZEND_FETCH_RW:
ZEND_FETCH_FUNC_ARG:
ZEND_ADD_INTERFACE:
ZEND_INSTANCEOF:

extended_value:
ZEND_DECLARE_INHERITED_CLASS:

ignore result
INIT_METHOD_CALL:
*/

#define OP1_CONST_IS_CLASS 1
#define OP2_CONST_IS_CLASS 2
#define EXT_CONST_IS_CLASS 4
#define RESULT_IS_UNUSED   8

static const char op_const_means_class[256]  = {
        /* 0 */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 32 */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
        /* 64 */
        0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2,
        /* 96 */
        0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 9, 1, 2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 128 */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 160 */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 192 */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 224 */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
#endif

#define GET_AVAILABLE_T()               \
        for (i = 0; i < T; i++) {       \
                if (!taken_T[i]) {              \
                        break;                          \
                }                                               \
        }                                                       \
        taken_T[i] = 1;                         \
        if (i > max) {                          \
                max = i;                                \
        }

static void optimize_temporary_variables(zend_op_array *op_array)
{
        int T = op_array->T;
        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;

        taken_T = (char *) emalloc(T);
        start_of_T = (zend_op **) emalloc(T * sizeof(zend_op *));
        valid_T = (char *) emalloc(T);
        map_T = (int *) emalloc(T * sizeof(int));

    end = op_array->opcodes;
    opline = &op_array->opcodes[op_array->last - 1];

    /* Find T definition points */
    while (opline >= end) {
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
        if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR | IS_CONST)) {
                        if (!(op_const_means_class[opline->opcode] & RESULT_IS_UNUSED)) {
                                start_of_T[VAR_NUM(ZEND_RESULT(opline).var)] = opline;
                        }
                }
#else
        if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
                        start_of_T[VAR_NUM(ZEND_RESULT(opline).var)] = opline;
                }
#endif
                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))
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
                        || ((op_const_means_class[opline->opcode] & OP1_CONST_IS_CLASS) && ZEND_OP1_TYPE(opline) == IS_CONST)
#endif
                        ) {
                        currT = VAR_NUM(ZEND_OP1(opline).var);
                        if (!valid_T[currT]) {
                                GET_AVAILABLE_T();
                                map_T[currT] = i;
                                valid_T[currT] = 1;
                        }
                        ZEND_OP1(opline).var = NUM_VAR(map_T[currT]);
                }

                /* 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))
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
                        || ((op_const_means_class[opline->opcode] & OP2_CONST_IS_CLASS) && ZEND_OP2_TYPE(opline) == IS_CONST)
#endif
                   ) {
                        currT = VAR_NUM(ZEND_OP2(opline).var);
                        if (!valid_T[currT]) {
                                GET_AVAILABLE_T();
                                map_T[currT] = i;
                                valid_T[currT] = 1;
                        }
                        ZEND_OP2(opline).var = NUM_VAR(map_T[currT]);
                }

#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
                if ((op_const_means_class[opline->opcode] & EXT_CONST_IS_CLASS)) {
#else
                if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS ||
            opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) {
#endif
                        currT = VAR_NUM(opline->extended_value);
                        if (!valid_T[currT]) {
                                GET_AVAILABLE_T();
                                map_T[currT] = i;
                                valid_T[currT] = 1;
                        }
                        opline->extended_value = NUM_VAR(map_T[currT]);
                }

                /* 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);
                        GET_AVAILABLE_T();
                        map_T[currT] = i;
                        valid_T[currT] = 1;
                        taken_T[i] = 0;
                        ZEND_OP2(opline + 1).var = NUM_VAR(i);
                        var_to_free = i;
                }

#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
                if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR | IS_CONST)) {
                        if (!(op_const_means_class[opline->opcode] & RESULT_IS_UNUSED)) {
#else
                if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
#endif
                                currT = VAR_NUM(ZEND_RESULT(opline).var);
                                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]);
                                } 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);
                                }
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
                        }
#endif
                }

                if (var_to_free >= 0) {
                        taken_T[var_to_free] = 0;
                        var_to_free = -1;
                }

                opline--;
        }

        efree(taken_T);
        efree(start_of_T);
        efree(valid_T);
        efree(map_T);
        op_array->T = max + 1;
}

/* [<][>][^][v][top][bottom][index][help] */