zend_vm_stack_push_call_frame

coder_study發表於2019-11-05

本文支援建立最簡單的物件

static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(uint32_t call_info, zend_function *func, uint32_t num_args, zend_class_entry *called_scope, zend_object *object)
{
    //根據引數和方法,計算使用的堆疊
    uint32_t used_stack = zend_vm_calc_used_stack(num_args, func);

    return zend_vm_stack_push_call_frame_ex(used_stack, call_info,
        func, num_args, called_scope, object);
}

1.zend_vm_calc_used_stack

static zend_always_inline uint32_t zend_vm_calc_used_stack(uint32_t num_args, zend_function *func)
{
    //槽,加上引數數量個數
    uint32_t used_stack = ZEND_CALL_FRAME_SLOT + num_args;
    //ZEND_USER_CODE(type) ((type & 1) == 0)
    if (EXPECTED(ZEND_USER_CODE(func->type))) {
        //加上op_array最後一個定義的變數,加上臨時變數和返回值的大小,減去一個重複的變數個數
        used_stack += func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args);
    }
    return used_stack * sizeof(zval);
}
 //兩個結構體的長度除以一個zval的長度,得出佔用幾個zval的個數,aligned 對其方式
#define ZEND_CALL_FRAME_SLOT \
    ((int)((ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval)) - 1) / ZEND_MM_ALIGNED_SIZE(sizeof(zval))))

2.zend_vm_stack_push_call_frame_ex

static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame_ex(uint32_t used_stack, uint32_t call_info, zend_function *func, uint32_t num_args, zend_class_entry *called_scope, zend_object *object)
{
    zend_execute_data *call = (zend_execute_data*)EG(vm_stack_top);

    ZEND_ASSERT_VM_STACK_GLOBAL;

    //需要的堆疊空間大於剩餘可用的,則擴容
    if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
        call = (zend_execute_data*)zend_vm_stack_extend(used_stack);
        ZEND_ASSERT_VM_STACK_GLOBAL;

        //call_info  ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR
        // func  constructor
        zend_vm_init_call_frame(call, call_info | ZEND_CALL_ALLOCATED, func, num_args, called_scope, object);
        return call;
    } else {
        EG(vm_stack_top) = (zval*)((char*)call + used_stack);
        zend_vm_init_call_frame(call, call_info, func, num_args, called_scope, object);
        return call;
    }
}
ZEND_API void* zend_vm_stack_extend(size_t size)
{
    zend_vm_stack stack;
    void *ptr;

    stack = EG(vm_stack);
    stack->top = EG(vm_stack_top);
    EG(vm_stack) = stack = zend_vm_stack_new_page(
        EXPECTED(size < ZEND_VM_STACK_FREE_PAGE_SIZE(0)) ?
            ZEND_VM_STACK_PAGE_SIZE(0) : ZEND_VM_STACK_PAGE_ALIGNED_SIZE(0, size),
        stack);
    ptr = stack->top;
    EG(vm_stack_top) = (void*)(((char*)ptr) + size);
    EG(vm_stack_end) = stack->end;
    return ptr;
}
static zend_always_inline void zend_vm_init_call_frame(zend_execute_data *call, uint32_t call_info, zend_function *func, uint32_t num_args, zend_class_entry *called_scope, zend_object *object)
{
    call->func = func;
    if (object) {
        //#define Z_OBJ(zval) (zval).value.obj,this值
        Z_OBJ(call->This) = object;
        ZEND_SET_CALL_INFO(call, 1, call_info);
    } else {
        Z_CE(call->This) = called_scope;
        //#define ZEND_SET_CALL_INFO(call, object, info) do { \
        //Z_TYPE_INFO((call)->This) = ((object) ? IS_OBJECT_EX : IS_UNDEF) | ((info) <<       //ZEND_CALL_INFO_SHIFT); \
    //} while (0)
        ZEND_SET_CALL_INFO(call, 0, call_info);
    }

    //#define ZEND_CALL_NUM_ARGS(call) \
    //    (call)->This.u2.num_args
    ZEND_CALL_NUM_ARGS(call) = num_args;
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結