i_init_func_execute_data

coder_study發表於2019-11-05

本文支援建立最簡單的物件
熟悉一下execute_data的結構

struct _zend_execute_data {
    //執行的opline
    const zend_op       *opline;           /* executed opline                */
    zend_execute_data   *call;             /* current call                   */
    zval                *return_value;
    zend_function       *func;             /* executed function              */
    zval                 This;             /* this + call_info + num_args    */
    zend_execute_data   *prev_execute_data;
    zend_array          *symbol_table;
#if ZEND_EX_USE_RUN_TIME_CACHE
    void               **run_time_cache;   /* cache op_array->run_time_cache */
#endif
#if ZEND_EX_USE_LITERALS
    zval                *literals;         /* cache op_array->literals       */
#endif
};

/*

  • Stack Frame Layout (the whole stack frame is allocated at once)
  • ==================
  • +========================================+
  • EG(current_execute_data) -> | zend_execute_data |
  • +---------------------------------------- +
  • EX_CV_NUM(0) --------->
  • VAR[0] = ARG[1]
  • ...
  • VAR[op_array->num_args-1] = ARG[N]
  • ...
  • VAR[op_array->last_var-1]
  • VAR[op_array->last_var] = TMP[0]
  • ...
  • VAR[op_array->last_var+op_array->T-1]
  • ARG[N+1] (extra_args)
  • ...
  • */

 //堆疊幀佈局(一次分配整個堆疊幀)
static zend_always_inline void i_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
{
    uint32_t first_extra_arg, num_args;
    ZEND_ASSERT(EX(func) == (zend_function*)op_array);

    EX(opline) = op_array->opcodes;
    EX(call) = NULL;
    EX(return_value) = return_value;

    /* Handle arguments */
    first_extra_arg = op_array->num_args;
    num_args = EX_NUM_ARGS();
    if (UNEXPECTED(num_args > first_extra_arg)) {
        if (EXPECTED(!(op_array->fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))) {
            zval *end, *src, *dst;
            uint32_t type_flags = 0;

            if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
                /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
                EX(opline) += first_extra_arg;
            }

            /* move extra args into separate array after all CV and TMP vars */
            end = EX_VAR_NUM(first_extra_arg - 1);
            src = end + (num_args - first_extra_arg);
            dst = src + (op_array->last_var + op_array->T - first_extra_arg);
            if (EXPECTED(src != dst)) {
                do {
                    type_flags |= Z_TYPE_INFO_P(src);
                    ZVAL_COPY_VALUE(dst, src);
                    ZVAL_UNDEF(src);
                    src--;
                    dst--;
                } while (src != end);
            } else {
                do {
                    type_flags |= Z_TYPE_INFO_P(src);
                    src--;
                } while (src != end);
            }
            ZEND_ADD_CALL_FLAG(execute_data, ((type_flags >> Z_TYPE_FLAGS_SHIFT) & IS_TYPE_REFCOUNTED));
        }
    } else if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
        /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
        EX(opline) += num_args;
    }

    /* Initialize CV variables (skip arguments) */
    if (EXPECTED((int)num_args < op_array->last_var)) {
        zval *var = EX_VAR_NUM(num_args);
        zval *end = EX_VAR_NUM(op_array->last_var);

        do {
            ZVAL_UNDEF(var);
            var++;
        } while (var != end);
    }

    EX_LOAD_RUN_TIME_CACHE(op_array);
    EX_LOAD_LITERALS(op_array);

    EG(current_execute_data) = execute_data;
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結