成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術文章
文章詳情頁

聊一聊關于php源碼中refcount的疑問

瀏覽:229日期:2022-06-05 18:54:05

在瀏覽PHP源碼的時候,在眾多的*.stub.php中,發現了這樣的注釋,@refcount 1

通過翻看build/gen_stub.php源碼,發現了在解析*.stub.php文件時,關于返回信息的代碼。

<?php
class ReturnInfo {
    const REFCOUNT_0 = "0";
    const REFCOUNT_1 = "1";
    const REFCOUNT_N = "N";

    const REFCOUNTS = [
self::REFCOUNT_0,
self::REFCOUNT_1,
self::REFCOUNT_N,
    ];

    //...
    
    private function setRefcount(?string $refcount): void
    {
$type = $this->phpDocType ?? $this->type;
$isScalarType = $type !== null && $type->isScalar();

if ($refcount === null) {
    $this->refcount = $isScalarType ? self::REFCOUNT_0 : self::REFCOUNT_N;
    return;
}

if (!in_array($refcount, ReturnInfo::REFCOUNTS, true)) {
    throw new Exception("@refcount must have one of the following values: \"0\", \"1\", \"N\", $refcount given");
}

if ($isScalarType && $refcount !== self::REFCOUNT_0) {
    throw new Exception("A scalar return type of "" . $type->__toString() . "" must have a refcount of "" . self::REFCOUNT_0 . """);
}

if (!$isScalarType && $refcount === self::REFCOUNT_0) {
    throw new Exception("A non-scalar return type of "" . $type->__toString() . "" cannot have a refcount of "" . self::REFCOUNT_0 . """);
}

$this->refcount = $refcount;
    }

明顯,如果返回值類型是scalar,也就是標量(基本數據類型,整型、浮點型、字符串等),那么refcount指定為0,否則為N。如果設置了注釋,那么以注釋為最高優先級。

以函數ob_list_handlers為例:

/**
 * @return array<int, string>
 * @refcount 1
 */
function ob_list_handlers(): array {}

返回值是array,所以默認的refcount應該是N,但由于設置了注釋@refcount 1,所以返回值的引用計數被替換成1。

這些邏輯我能看懂,但設置返回值引用計數的目的是什么?我還是一頭霧水

我接著往下排查,發現通過返回值的引用計數,在生成func_info的時候,會有些不同。如果返回值引用計數為1或N,則會用對應的宏去初始化func_info結構體。如果是0,則不進入初始化列表。

以上的代碼邏輯依然可以在gen_stub.php中找到,1393行,getOptimizerInfo

public function getOptimizerInfo(): ?string {
if ($this->isMethod()) {
    return null;
}

if ($this->alias !== null) {
    return null;
}

if ($this->return->refcount !== ReturnInfo::REFCOUNT_1 && $this->return->phpDocType === null) {
    return null;
}

$type = $this->return->phpDocType ?? $this->return->type;
if ($type === null) {
    return null;
}

return "\tF" . $this->return->refcount . "("" . $this->name->__toString() . "", " . $type->toOptimizerTypeMask() . "),\n";
    }

獲取函數原型的refcount,生成諸如F1()FN()的代碼,生成的頭文件位置在Zend/Optimizer/zend_func_infos.h

static const func_info_t func_infos[] = {
    F1("zend_version", MAY_BE_STRING),
    FN("func_get_args", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_ANY),
    F1("get_class_vars", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF),
    F1("get_class_methods", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING),
    F1("get_included_files", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING),
    FN("set_error_handler", MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_OBJECT|MAY_BE_NULL),
    FN("set_exception_handler", MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_OBJECT|MAY_BE_NULL),
    F1("get_declared_classes", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING),
    F1("get_declared_traits", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING),
    F1("get_declared_interfaces", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING),
    F1("get_defined_functions", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ARRAY),
    F1("get_defined_vars", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF),
    F1("get_resource_type", MAY_BE_STRING),
    F1("get_loaded_extensions", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING),
    F1("get_defined_constants", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY),
    F1("debug_backtrace", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_ARRAY),
    F1("get_extension_funcs", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_FALSE),
    F1("gc_status", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_FALSE|MAY_BE_ARRAY_OF_TRUE),
    F1("bcadd", MAY_BE_STRING),
    F1("bcsub", MAY_BE_STRING),
    F1("bcmul", MAY_BE_STRING),
    F1("bcdiv", MAY_BE_STRING),
    F1("bcmod", MAY_BE_STRING),
    F1("bcpowmod", MAY_BE_STRING),
    F1("bcpow", MAY_BE_STRING),
    F1("bcsqrt", MAY_BE_STRING),
    FN("bzopen", MAY_BE_RESOURCE|MAY_BE_FALSE),
    F1("bzerror", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING),
    F1("cal_from_jd", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_NULL),
    F1("cal_info", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY),
    F1("curl_copy_handle", MAY_BE_OBJECT|MAY_BE_FALSE),
    //...
};

再去看看F1FN的宏定義。

typedef struct _func_info_t {
    const char *name;
    unsigned    name_len;
    uint32_t    info;
    info_func_t info_func;
} func_info_t;

#define F0(name, info) \
    {name, sizeof(name)-1, (info), NULL}
#define F1(name, info) \
    {name, sizeof(name)-1, (MAY_BE_RC1 | (info)), NULL}
#define FN(name, info) \
    {name, sizeof(name)-1, (MAY_BE_RC1 | MAY_BE_RCN | (info)), NULL}
#define FC(name, callback) \
    {name, sizeof(name)-1, 0, callback}

僅僅是設置了不同的type maskF1設置了MAY_BE_RC1FN設置了MAY_BE_RCN | MAY_BE_RC1

依然一頭霧水,但是通過目錄名,我依稀能猜出這跟性能優化有關,跟JIT有關系。我決定繼續追查下去,看看這些初始化后的結構體在哪里使用過。

我們很清楚,設置位信息用|,那判斷有沒有設置肯定用&,全局搜索& MAY_BE_RCN,再看看哪些代碼跟優化有關,定位到了如下代碼,在zend_jit.c的530行:

#ifdef ZEND_JIT_USE_RC_INFERENCE
    /* Refcount may be increased by RETURN opcode */
    if ((info & MAY_BE_RC1) && !(info & MAY_BE_RCN)) {
for (j = 0; j < ssa->cfg.blocks_count; j++) {
    if ((ssa->cfg.blocks[j].flags & ZEND_BB_REACHABLE) &&
ssa->cfg.blocks[j].len > 0) {
const zend_op *opline = op_array->opcodes + ssa->cfg.blocks[j].start + ssa->cfg.blocks[j].len - 1;

if (opline->opcode == ZEND_RETURN) {
    if (opline->op1_type == IS_CV && opline->op1.var == EX_NUM_TO_VAR(var)) {
info |= MAY_BE_RCN;
break;
    }
}
    }
}
    }
#endif

如果返回值的引用計數是1,而不是N的時候,并且開啟了返回值引用計數推導功能,就走這段代碼。這段代碼又涉及到所謂SSA,靜態單賦值的編譯器設計方式。

在編譯器設計中,靜態單一賦值形式(通常縮寫為SSA形式或簡稱SSA)是中間表示(IR)的屬性,它要求每個變量只分配一次,并且每個變量在使用之前定義。原始IR中的現有變量被拆分為版本,在教科書中,新變量通常由原始名稱用下標表示,以便每次定義都有自己的版本。在SSA形式中,use-def鏈是顯式的,每個包含一個元素。

所以上面的代碼就是判斷SSA的cfg(control flow graph控制流圖)的塊是不是可達的,如果可達,執行條件中的代碼。

還是不太通透,雖然能推斷出設置refcount跟優化有關,跟靜態單一賦值有關,但在寫擴展的時候,什么時候該用@refcount 1,還是不太清楚。

 總結

到此這篇關于php源碼中refcount疑問的文章就介紹到這了,更多相關php源碼中refcount內容請搜索以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持!

標簽: PHP
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
99国内精品久久| 激情久久久久久久| 99精品视频中文字幕| 欧美日韩视频在线第一区| 亚洲18影院在线观看| 亚洲精品极品| 中国av一区二区三区| 色综合天天综合色综合av | 日韩欧美高清dvd碟片| 蜜桃在线一区二区三区| 久久一区二区三区四区五区| 亚洲一区精品在线| 中文在线不卡| 一区二区激情视频| 国产日韩欧美亚洲一区| 亚洲欧洲日韩av| 欧美韩国一区| 中文字幕高清一区| 欧美全黄视频| 久久精品一区四区| 99久久伊人网影院| 日韩精品一区二区三区swag| 国产成人免费视频网站| 日韩一级片网站| 丁香婷婷综合激情五月色| 91精品国产综合久久久久久漫画| 国产一区二区三区观看| 欧美区视频在线观看| 久久99久久精品欧美| 欧美中文字幕一二三区视频| 蜜桃av一区二区| 欧美精品乱码久久久久久按摩| 国内外成人在线视频| 91精品蜜臀在线一区尤物| 成人午夜视频在线| 久久噜噜亚洲综合| 欧美在线首页| 中文字幕乱码一区二区免费| 欧美午夜精品久久久久免费视| 亚洲欧洲日本在线| 国产三区精品| 午夜精品久久久久久久久久久| 葵司免费一区二区三区四区五区| 图片区小说区国产精品视频| 色88888久久久久久影院野外| 麻豆精品视频在线| 欧美一区日本一区韩国一区| 97久久精品人人澡人人爽| 日本一区二区久久| 亚洲人人精品| 日韩精品久久理论片| 在线观看亚洲一区| 国内精品免费**视频| 精品理论电影在线| 欧美激情视频一区二区三区免费| 亚洲私人黄色宅男| 久久国产日韩欧美| 精品一区二区三区香蕉蜜桃| 欧美一区二区性放荡片| 99久久精品国产一区二区三区| 国产精品理论片| 午夜影院日韩| 久草中文综合在线| 久久久影视传媒| 国产日韩在线一区二区三区| 日韩av一级电影| 欧美肥妇bbw| 91丨九色丨蝌蚪丨老版| 亚洲欧洲国产日韩| 色综合久久88色综合天天免费| 国产一区二区不卡| 国产精品久久久久7777按摩| 亚洲欧美卡通另类91av| 精品一区二区综合| 久久综合狠狠综合| 一区二区三区|亚洲午夜| 日本中文一区二区三区| 日韩精品中文字幕在线不卡尤物 | 国产婷婷色一区二区三区四区| 国产精品日韩欧美一区| 捆绑紧缚一区二区三区视频| 久久毛片高清国产| 欧美亚洲视频| 国产高清在线精品| 亚洲三级电影网站| 在线电影一区二区三区| 欧美日韩免费高清| 男男gaygay亚洲| 久久久青草青青国产亚洲免观| 国产日韩一区欧美| 国产成人免费在线视频| 中文字幕欧美一区| 欧美羞羞免费网站| 91麻豆成人久久精品二区三区| 亚洲一区二区视频| 欧美电影免费提供在线观看| 国产日韩1区 | 亚洲高清在线精品| 精品第一国产综合精品aⅴ| 一本久道综合久久精品| 国产精品一二三区在线| 亚洲另类在线视频| 777午夜精品免费视频| 在线播放一区| 久久电影网电视剧免费观看| 日本一区二区三区久久久久久久久不| 麻豆久久婷婷| 欧美在线网站| 国模少妇一区二区三区| 一区二区成人在线观看| 日韩欧美亚洲另类制服综合在线| 国产欧美日韩在线播放| 成人教育av在线| 偷拍与自拍一区| 国产精品入口麻豆九色| 欧美群妇大交群中文字幕| 国产日韩一区二区三区| 色综合久久综合网97色综合| 蓝色福利精品导航| 亚洲天堂2014| 2019国产精品| 欧美亚洲另类激情小说| 一区二区三区成人精品| 99久久精品久久久久久清纯| 久久精品国产精品青草| 亚洲欧美国产77777| 欧美mv日韩mv国产网站app| 久久亚洲精选| 伊人精品视频| 99久久精品国产一区| 麻豆国产精品一区二区三区| 一区二区三区四区av| 久久久不卡网国产精品一区| 在线观看精品一区| 亚洲精品视频啊美女在线直播| av激情亚洲男人天堂| 国产综合一区二区| 亚欧色一区w666天堂| 亚洲视频资源在线| 久久久噜噜噜久久中文字幕色伊伊| 欧美熟乱第一页| 一区二区久久| 国产精品国产亚洲精品看不卡15 | 激情五月婷婷综合| 亚洲不卡一区二区三区| 亚洲免费观看视频| 中文字幕高清一区| 精品国产免费久久| 欧美精选一区二区| 欧美性一二三区| 老鸭窝毛片一区二区三区| 99riav1国产精品视频| 欧美日韩一视频区二区| av一区二区三区| 丰满白嫩尤物一区二区| 国产真实乱偷精品视频免| 日本成人在线电影网| 亚洲一区在线观看免费观看电影高清| 国产情人综合久久777777| 欧美成人女星排名| 日韩一区二区在线观看视频| 欧美在线视频你懂得| 亚洲一区在线直播| 亚洲黄色影院| 伊人久久亚洲影院| 亚洲视频精品| 欧美午夜精品理论片a级大开眼界| 成人爱爱电影网址| 成熟亚洲日本毛茸茸凸凹| 国产伦精品一区二区三区免费迷 | 国内一区二区三区| 欧美freesex交免费视频| 91麻豆国产在线观看| 99久久免费国产| 91亚洲永久精品| 波多野结衣精品在线| 成人性视频网站| 国产精品亚洲午夜一区二区三区| 极品美女销魂一区二区三区| 极品少妇一区二区| 国产一区二区三区在线观看精品| 精品一区二区免费看| 精品亚洲免费视频| 久久99国产精品成人| 国内精品嫩模私拍在线| 国产一区二区三区精品视频| 国产麻豆精品一区二区| 国产精品888| 成人免费看视频| 97久久超碰国产精品| 色综合欧美在线| 91视频在线观看免费| 午夜精品网站| 激情久久五月| 一区二区毛片| 午夜一区二区三区不卡视频| 久久久久欧美精品| 91福利小视频| 欧美精品v国产精品v日韩精品| 69久久99精品久久久久婷婷 |