php-5.6.26源代码 - opcode处理器,“函数调用opcode”处理器,如何调用扩展模块的函数

 

// opcode处理器 --- ZEND_DO_FCALL_SPEC_CONST_HANDLER实现在 php-5.6.26\Zend\zend_vm_execute.h
static int ZEND_FASTCALL  ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    USE_OPLINE

    zval *fname = opline->op1.zv;
    call_slot *call = EX(call_slots) + opline->op2.num;

    if (CACHED_PTR(opline->op1.literal->cache_slot)) {
        EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot);
    } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(fname), Z_STRLEN_P(fname)+1, Z_HASH_P(fname), (void **) &EX(function_state).function)==FAILURE)) { // 查找函数,把函数指针放入 EX(function_state).function
        SAVE_OPLINE();
        zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val);
    } else {
        CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function);
    }

    call->fbc = EX(function_state).function; // 函数信息指针
    call->object = NULL;
    call->called_scope = NULL;
    call->num_additional_args = 0;
    call->is_ctor_call = 0;
    EX(call) = call;

    // ZEND_OPCODE_HANDLER_ARGS_PASSTHRU ---> execute_data TSRMLS_CC

    return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); // zend_do_fcall_common_helper_SPEC(execute_data)
    {
        ...
        
        if (fbc->type == ZEND_INTERNAL_FUNCTION) { // 内建函数 --- 执行的是函数指针(扩展中定义的函数)
            if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
                zend_uint i;
                void **p = EX(function_state).arguments - num_args;
    
                for (i = 0; i < num_args; ++i, ++p) {
                    zend_verify_arg_type(fbc, i + 1, (zval *) *p, 0, NULL TSRMLS_CC);
                }
            }
    
            if (EXPECTED(EG(exception) == NULL)) {
                temp_variable *ret = &EX_T(opline->result.var);
    
                MAKE_STD_ZVAL(ret->var.ptr);
                ZVAL_NULL(ret->var.ptr);
                ret->var.ptr_ptr = &ret->var.ptr;
                ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
    
                if (!zend_execute_internal) { // !!! 执行函数
                    /* saves one function call if zend_execute_internal is not used */
                    fbc->internal_function.handler(num_args, ret->var.ptr, &ret->var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);  // 调用扩展模块的函数
                } else {
                    zend_execute_internal(execute_data, NULL, RETURN_VALUE_USED(opline) TSRMLS_CC);
                }
    
                if (!RETURN_VALUE_USED(opline)) {
                    zval_ptr_dtor(&ret->var.ptr);
                }
            } else if (RETURN_VALUE_USED(opline)) {
                EX_T(opline->result.var).var.ptr = NULL;
            }
        } else if (fbc->type == ZEND_USER_FUNCTION) { // 用户定义的函数  --- 执行的opcode
            temp_variable *ret = &EX_T(opline->result.var);
            EX(original_return_value) = EG(return_value_ptr_ptr);
            EG(active_symbol_table) = NULL;
            EG(active_op_array) = &fbc->op_array; // !!! 用户函数编译出来的操作码
            EG(return_value_ptr_ptr) = NULL;
            if (RETURN_VALUE_USED(opline)) {
                ret->var.ptr = NULL;
                EG(return_value_ptr_ptr) = &ret->var.ptr;
                ret->var.ptr_ptr = &ret->var.ptr;
                ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
            }
    
            if (UNEXPECTED((EG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) {
                if (RETURN_VALUE_USED(opline)) {
                    ret->var.ptr = zend_generator_create_zval(EG(active_op_array) TSRMLS_CC);
                    ret->var.fcall_returned_reference = 0;
                }
            } else if (EXPECTED(zend_execute_ex == execute_ex)) {
                if (EXPECTED(EG(exception) == NULL)) {
                    ZEND_VM_ENTER();
                }
            } else {
                zend_execute(EG(active_op_array) TSRMLS_CC); // 执行操作码
            }
    
            EG(opline_ptr) = &EX(opline);
            EG(active_op_array) = EX(op_array);
            EG(return_value_ptr_ptr) = EX(original_return_value);
            if (EG(active_symbol_table)) {
                zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC);
            }
            EG(active_symbol_table) = EX(symbol_table);
        } else { /* ZEND_OVERLOADED_FUNCTION */
            MAKE_STD_ZVAL(EX_T(opline->result.var).var.ptr);
            ZVAL_NULL(EX_T(opline->result.var).var.ptr);
    
            /* Not sure what should be done here if it's a static method */
            if (EXPECTED(EX(object) != NULL)) {
                // 调用对象方法
                Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, num_args, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);
            } else {
                zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object");
            }
    
            if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
                efree((char*)fbc->common.function_name);
            }
            efree(fbc);
    
            if (!RETURN_VALUE_USED(opline)) {
                zval_ptr_dtor(&EX_T(opline->result.var).var.ptr);
            } else {
                Z_UNSET_ISREF_P(EX_T(opline->result.var).var.ptr);
                Z_SET_REFCOUNT_P(EX_T(opline->result.var).var.ptr, 1);
                EX_T(opline->result.var).var.fcall_returned_reference = 0;
                EX_T(opline->result.var).var.ptr_ptr = &EX_T(opline->result.var).var.ptr;
            }
        }
        
        ...
        
        EX(call)--;
    
        zend_vm_stack_clear_multiple(0 TSRMLS_CC);
    
        if (UNEXPECTED(EG(exception) != NULL)) {
            zend_throw_exception_internal(NULL TSRMLS_CC); // 抛异常
            if (RETURN_VALUE_USED(opline) && EX_T(opline->result.var).var.ptr) {
                zval_ptr_dtor(&EX_T(opline->result.var).var.ptr);
            }
            HANDLE_EXCEPTION(); 
        }
    
        ZEND_VM_NEXT_OPCODE();
        
        ...
    }
}

 

posted on 2018-03-23 10:56  周~~  阅读(164)  评论(0编辑  收藏  举报

导航