ããã·ã¥ããŒãã«ã¯ãããããæ·±å»ãªCããã°ã©ã ã§ãããããå Žæã§äœ¿çšãããŸãã åºæ¬çã«ãããã°ã©ãã¯æååã§ã€ã³ããã¯ã¹ãäœæããŠå€ããé
åãã«æ ŒçŽã§ããŸãããCã§ã¯æŽæ°é
åããŒã®ã¿ãèš±å¯ãããŸãã ããã·ã¥ããŒãã«ã§ã¯ãå°æåã®ããŒãæåã«ããã·ã¥ããã次ã«ããŒãã«ã®ãµã€ãºã«çž®å°ãããŸãã ããã§ã¯è¡çªãçºçããå¯èœæ§ããããããè¡çªã解決ããã¢ã«ãŽãªãºã ãå¿
èŠã§ãã åæ§ã®ã¢ã«ãŽãªãºã ãããã€ããããPHPã¯ãªã³ã¯ãªã¹ãæŠç¥ã䜿çšããŸãã
Webäžã«ã¯ãããã·ã¥ããŒãã«ã®æ§é ãšãã®å®è£
ã«ã€ããŠè©³ãã説æããŠããçŽ æŽãããèšäºããããããããŸãã
http://preshing.com/ããå§ããããšãã§ããŸãã ãã ããç¡æ°ã®ããã·ã¥ããŒãã«æ§é ã®ãªãã·ã§ã³ãããããããã®ããããå®å
šã§ã¯ãªããããã»ããµãµã€ã¯ã«ãã¡ã¢ãªäœ¿çšéããŸãã¯ã¹ã¬ããç°å¢ã®é©åãªã¹ã±ãŒãªã³ã°ã®æé©åã«ãããããããããããã«ãã¬ãŒããªãããããŸãã ããŒã¿ãè¿œå ããå Žåã¯ããè¯ããªãã·ã§ã³ãæ€çŽ¢ããå Žåã¯ä»ã®ãªãã·ã§ã³ãªã©ããããŸããããéèŠãªãã®ã«å¿ããŠå®è£
ãéžæããŸãã
PHP 5ã®ããã·ã¥ããŒãã«ã«ã€ããŠã¯
ãPHP 7ã®ããã·ã¥ããŒãã«ã«é¢ããåªããèšäºã®èè
ã§ãã
Nikicãš
äžç·ã«æžãã
phpinternalsbookã§è©³ãã説æãããŠããŸãã ããããããªãããããé¢çœããšæãã§ãããã 確ãã«ãããã¯ãªãªãŒã¹ã®åã«æžãããã®ã§ããã®äžã®ããã€ãã®ãã®ã¯ãããã«ç°ãªããŸãã
ããã§ã¯ãPHP 7ã§ããã·ã¥ããŒãã«ãã©ã®ããã«é
眮ãããããCèšèªã®èŠ³ç¹ããããã·ã¥ããŒãã«ãæäœããæ¹æ³ãããã³PHPããŒã«ã䜿çšããŠïŒé
åãšåŒã°ããæ§é ã䜿çšããŠïŒããã·ã¥ããŒãã«ã管çããæ¹æ³ã詳ããèŠãŠãããŸãã ãœãŒã¹ã³ãŒãã®ã»ãšãã©ã¯
zend_hash.cã§å
¥æã§ããŸãã ããã·ã¥ããŒãã«ã¯ã©ãã§ãïŒéåžžã¯èŸæžãšããŠïŒäœ¿çšããããšãå¿ããªãã§ãã ããããããã£ãŠãããã»ããµã§ãã°ããåŠçãããã¡ã¢ãªãã»ãšãã©æ¶è²»ããªãããã«èšèšããå¿
èŠããããŸãã ããã·ã¥ããŒãã«ã䜿çšãããå Žæã¯ããŒã«ã«é
åã ãã§ã¯ãªãããããããã®æ§é ã¯PHPã®å
šäœçãªããã©ãŒãã³ã¹ã«æ±ºå®çãªåœ±é¿ãåãŒããŸãã
ããã·ã¥ããŒãã«ã®èšèš
以äžã§è©³çŽ°ã«æ€èšããå€ãã®èŠå®ããããŸãã
- ããŒã¯æååãŸãã¯æŽæ°ã§ãã
zend_string
å Žåã¯zend_string
æ§é ãzend_string
ã zend_string
å Žåã¯zend_string
ãzend_string
ãŸãã - ããã·ã¥ããŒãã«ã¯ãèŠçŽ ãè¿œå ãããé åºãåžžã«èšæ¶ããŠããå¿
èŠããããŸãã
- ããã·ã¥ããŒãã«ã®ãµã€ãºã¯èªåçã«å€æŽãããŸãã ç¶æ³ã«å¿ããŠãç¬ç«ããŠæžå°ãŸãã¯å¢å ããŸãã
- å
éšå®è£
ã®èŠ³ç¹ããèŠããšãããŒãã«ã®ãµã€ãºã¯åžžã«2床ã«çãããªããŸãã ããã¯ãããã©ãŒãã³ã¹ãæ¹åããã¡ã¢ãªå
ã®ããŒã¿é
眮ã調æŽããããã«è¡ãããŸãã
- ããã·ã¥ããŒãã«å
ã®ãã¹ãŠã®å€ã¯ãä»ã®å Žæã§ã¯ãªãã
zval
æ§é ã«æ ŒçŽãããŸãã Zval
ã¯ãä»»æã®ã¿ã€ãã®ããŒã¿ãå«ããããšãã§ããŸãã
HashTable
æ§é ã«ã€ããŠèããŠã¿ãŸãããã
struct _zend_array { zend_refcounted_h gc; union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar flags, zend_uchar nApplyCount, zend_uchar nIteratorsCount, zend_uchar reserve) } v; uint32_t flags; } u; uint32_t nTableMask; Bucket *arData; uint32_t nNumUsed; uint32_t nNumOfElements; uint32_t nTableSize; uint32_t nInternalPointer; zend_long nNextFreeElement; dtor_func_t pDestructor; };
äžéšã®ãã£ãŒã«ãã¯ãã£ãã«äœ¿çšãããªãããããããã«ã€ããŠã¯èª¬æããŸããã
ãã®æ§é ã®ãµã€ãºã¯
56ãã€ãã§ã ïŒLP64ã¢ãã«ã«ããïŒã
æãèå³æ·±ãããŒã¿ãã£ãŒã«ãã¯ã
Bucket
ãã§ãŒã³ã®ã¡ã¢ãªé åãžã®ãã€ã³ã¿ã®äžçš®ã§ãã
arData
ã§ãã
Bucket
èªäœã¯é
åå
ã®åäžã®ã»ã«ã§ãã
typedef struct _Bucket { zval val; zend_ulong h; zend_string *key; } Bucket;
ãæ°ã¥ããããããŸãããã
zval
ã¯
Bucket
æ§é ã«ä¿åãããŸãã ããã¯
zval
ãžã®ãã€ã³ã¿ã§ã¯ãªããæ§é èªäœã§ããããšã«æ³šæããŠãã ããã ããã¯ãPHP 7ã§ã¯
zval
ãããŒãã«é
眮ãããªããªã£ãããã§ãïŒPHP 5ãšã¯ç°ãªããŸãïŒããPHP 7ã§ã¯ã
zval
ãã€ã³ã¿ãŒãšããŠä¿åãããã¿ãŒã²ããå€ïŒPHPæååãªã©ïŒãé
眮ã§ããŸãã
ã¡ã¢ãªå
ã®é
眮ãã©ã®ããã«çºçããããèŠãŠã¿ãŸãããã
ã芧ã®ãšãããããã·ã¥ããŒãã«ã«é
眮ãããããŒã¿ã¯ãé£æ¥ããã¡ã¢ãªã»ã¯ã·ã§ã³
arData
ä¿åãããŸãã
é åºãç¶æããªããã¢ã€ãã ãè¿œå ãã
PHPã¯ãèŠçŽ ãé
åã«è¿œå ããããšãã«èŠçŽ ã®é åºãç¶æããå¿
èŠããããŸãã
foreach
ãé
åã«é©çšãããšãããŒã«é¢ä¿ãªããé
åã«é
眮ãããæ£ç¢ºãªé åºã§ããŒã¿ãåãåããŸãã
$a = [9=>"foo", 2 => 42, []]; var_dump($a); array(3) { [9]=> string(3) "foo" [2]=> int(42) [10]=> array(0) { } }
ããã¯ãããã·ã¥ããŒãã«ã®å®è£
ã«å€ãã®å¶éã課ããéèŠãªãã€ã³ãã§ãã ãã¹ãŠã®ããŒã¿ã¯ãäºãã«é£ãåãã¡ã¢ãªã«é
眮ãããŸãã
zval
ã§ã¯ã
arData
C-arrayã®ãã£ãŒã«ãã«ãã
Bucket
ããã¯ãããŠæ ŒçŽãããŸãã ãã®ãããªãã®ïŒ
$a = [3=> 'foo', 8 => 'bar', 'baz' => []];
ãã®ã¢ãããŒãã®ãããã§ãããã·ã¥ããŒãã«ãç°¡åã«å埩ã§ããŸã
arData
é
åã
arData
ã ãã§ãã æ¬è³ªçã«ãããã¯ã¡ã¢ãªã®è¿
éãªé 次ã¹ãã£ã³ã§ãããããã»ããµãã£ãã·ã¥ãªãœãŒã¹ãã»ãšãã©æ¶è²»ããŸããã
arData
ããã®ãã¹ãŠã®ããŒã¿ã¯1è¡ã«é
眮ã§ããåã»ã«ãžã®ã¢ã¯ã»ã¹ã«ã¯çŽ1ããç§ããããŸãã 泚ïŒããã»ããµãã£ãã·ã¥ã®äœ¿çšå¹çãé«ããããã«ã
arData
64ãããã¢ãã«ã«åŸã£ãŠã¢ã©ã€ã¡ã³ããããŸãïŒ64ããããã«åœä»€ã®ã¢ã©ã€ã¡ã³ãã®æé©åã䜿çšãããŸãïŒã ããã·ã¥ããŒãã«ã®å埩ã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
size_t i; Bucket p; zval val; for (i=0; i < ht->nTableSize; i++) { p = ht->arData[i]; val = p.val; }
ããŒã¿ã¯ãœãŒãããã次ã®
arData
ã»ã«ã«æž¡ãããŸãã ãã®æé ãå®äºããã«ã¯ã
nNumUsed
ãã£ãŒã«ãã«æ ŒçŽãããŠããããã®é
åã§æ¬¡ã«äœ¿çšå¯èœãªã»ã«ãèŠããŠãããŠ
nNumUsed
ã æ°ããå€ãè¿œå ããããã³ã«ã
ht->nNumUsed++
ãè¿œå ã
ht->nNumUsed++
ã
nNumUsed
ã®èŠçŽ æ°ãããã·ã¥ããŒãã«ã®èŠçŽ æ°ïŒ
nNumOfElements
ïŒã«éãããšãã³ã³ãã¯ãã¢ã«ãŽãªãºã ãŸãã¯ãµã€ãºå€æŽã¢ã«ãŽãªãºã ãå®è¡ããŸããããã«ã€ããŠã¯ä»¥äžã§èª¬æããŸãã
æååããŒã䜿çšããŠããã·ã¥ããŒãã«ã«ã¢ã€ãã ãè¿œå ããç°¡ç¥åããããã¥ãŒïŒ
idx = ht->nNumUsed++; ht->nNumOfElements++; p = ht->arData + idx; p->key = key; p->h = h = ZSTR_H(key); ZVAL_COPY_VALUE(&p->val, pData);
å€ãæ¶å»
å€ãåé€ããŠãã
arData
é
å
arData
æžå°ãããåé
å
arData
ãã
arData
ãã ããããªããšãã¡ã¢ãªå
ã®ããŒã¿ã移åããå¿
èŠããããããããã©ãŒãã³ã¹ãåçã«äœäžããŸãã ãã®ãããããã·ã¥ããŒãã«ããããŒã¿ãåé€ããå Žåã
arData
ã®å¯Ÿå¿ããã»ã«ã¯ã
zval
UNDEFãšããç¹å¥ãªæ¹æ³ã§åçŽã«ããŒã¯ãããŸãã
ãããã£ãŠããã®ãããªã空ã®ãã»ã«ãåŠçã§ããããã«ãå埩ã³ãŒããå°ãåæ§ç¯ããå¿
èŠããããŸãã
size_t i; Bucket p; zval val; for (i=0; i < ht->nTableSize; i++) { p = ht->arData[i]; val = p.val; if (Z_TYPE(val) == IS_UNDEF) { continue; } }
以äžã§ã¯ãããã·ã¥ããŒãã«ã®ãµã€ãºãå€æŽããããšãã«äœãèµ·ããããããã³ã空ã®ãã»ã«ãæ¶ããããã«
arData
é
åãåç·šæããå¿
èŠããããŸãïŒå§çž®ïŒã
ããŒããã·ã¥
ããŒã¯ããã·ã¥ããã³å§çž®ãããå§çž®ãããããã·ã¥å€ããå€æãããŠ
arData
ã€ã³ããã¯ã¹ä»ãããã
arData
ãŸãã ããŒã¯æŽæ°ã§ãã£ãŠãå§çž®ãããŸãã ããã¯ãé
åã®å¢çã«åãŸãããã«ããããã«å¿
èŠã§ãã
arData
çŽæ¥ããããã«ãå§çž®ãããå€ã«ã€ã³ããã¯ã¹ã
arData
ããšã¯ã§ããªãããšã«
arData
ããŠ
arData
ã çµå±ãããã¯é
åã®ã€ã³ããã¯ã¹ã«äœ¿çšãããããŒãããã·ã¥ããååŸããããŒã«çŽæ¥å¯Ÿå¿ããããšãæå³ããŸããããã¯ãPHPã®ããã·ã¥ããŒãã«ã®ããããã£ã®1ã€ãèŠçŽ ã®é åºã®ä¿æã«éåããŸãã
ããšãã°ãæåã«fooããŒãè¿œå ãã次ã«barããŒãè¿œå ãããšãæåã®ããŒã¯ããã·ã¥ãããŠããŒ5ã«å§çž®ããã2çªç®ã®ããŒã¯ããŒ3ã«å§çž®ãããŸã
arData[5]
ããŒã¿ã
arData[5]
arData[3]
ãããŒã¿ããŒãããŒã¿fooã«
移åããããšãããããŸãã ãŸãã
arData
å埩åŠçããå Žå
arData
èŠçŽ ã¯è¿œå ãããé åºã§ã¯ãªã転éãããŸãã
ãããã£ãŠãå²ãåœãŠããã
arData
å¢çã«åãŸãããã«ãããŒãããã·ã¥ããŠããå§çž®ããŸãã ãã ããPHP 5ãšã¯ç°ãªãããã®ãŸãŸäœ¿çšããŸãããæåã«å€æããŒãã«ã䜿çšããŠããŒãå€æããå¿
èŠããããŸãã ããã·ã¥/å§çž®ã«ãã£ãŠååŸããã1ã€ã®æŽæ°å€ãšã
arData
é
åå
ã®ã¢ãã¬ã¹æå®ã«äœ¿çšãããå¥ã®æŽæ°å€ãåçŽã«æ¯èŒããŸãã
泚æç¹ã1ã€ãããŸããå€æããŒãã«ã®ã¡ã¢ãªã¯
ã arData
ãã¯ãã«ã®
èåŸã«æ
éã«é
眮ã
ããŸãã ãã
arData
ããŒãã«ã¯ãã§ã«
arData
é£ã«
arData
ããŠãããåãã¢ãã¬ã¹ç©ºéã«æ®ã£ãŠãããããããŒãã«ãå¥ã®ã¡ã¢ãªé åã䜿çšãã
arData
ãŸãã ããã«ãããããŒã¿ã®å±ææ§ãåäžããŸãã ããã¯ã8èŠçŽ ã®ããã·ã¥ããŒãã«ïŒå¯èœãªæå°ãµã€ãºïŒã®å Žåã«èª¬æãããã¹ããŒã ãã©ã®ããã«èŠãããã§ãïŒ
ããã§ãfooããŒã¯DJB33Xã§ããã·ã¥ãããå¿
èŠãªãµã€ãºïŒ
nTableMask
ïŒã«ã¢ãžã¥ãå§çž®ãããŸãã çµæã®å€ã¯ãïŒçŽæ¥ã»ã«ã§ã¯ãªãïŒ
arData
å€æ arData
ã«ã¢ã¯ã»ã¹ããããã«äœ¿çšã§ããã€ã³ããã¯ã¹ã§ãã
ãããã®ã»ã«ã¯ã
arData
éå§äœçœ®ããã®è² ã®ã·ããã«ãã£ãŠã¢ã¯ã»ã¹ãããŸãã 2ã€ã®ã¡ã¢ãªé åãçµåããããããã¡ã¢ãªã«ããŒã¿ãé çªã«ä¿åã§ããŸãã
nTableMask
ã¯ããŒãã«ã®ãµã€ãºã®è² ã®å€ã«å¯Ÿå¿ãããããã¢ãžã¥ãŒã«ãšããŠååŸãããš0ãâ7ã®å€ãååŸããŸãã ããã§ã¡ã¢ãªã«ã¢ã¯ã»ã¹ã§ããŸãã
arData
ãããã¡ãŒå
šäœãé
眮ããå Žåã次ã®åŒã䜿çšããŠãµã€ãºãèšç®ããŸãã
* bucket' + * (uint32) .
以äžã«ããããã¡ã2ã€ã®éšåã«ã©ã®ããã«åå²ãããŠããããæ確ã«ç€ºããŸãã
#define HT_HASH_SIZE(nTableMask) (((size_t)(uint32_t)-(int32_t)(nTableMask)) * sizeof(uint32_t)) #define HT_DATA_SIZE(nTableSize) ((size_t)(nTableSize) * sizeof(Bucket)) #define HT_SIZE_EX(nTableSize, nTableMask) (HT_DATA_SIZE((nTableSize)) + HT_HASH_SIZE((nTableMask))) #define HT_SIZE(ht) HT_SIZE_EX((ht)->nTableSize, (ht)->nTableMask) Bucket *arData; arData = emalloc(HT_SIZE(ht));
ãã¯ããå®è¡ããããšã次ã®çµæãåŸãããŸãã
(((size_t)(((ht)->nTableSize)) * sizeof(Bucket)) + (((size_t)(uint32_t)-(int32_t)(((ht)->nTableMask))) * sizeof(uint32_t)))
ããã
è¡çªè§£æ±º
ããã§ã¯ãè¡çªãã©ã®ããã«è§£æ±ºãããããèŠãŠã¿ãŸãããã èŠããŠããããã«ãããã·ã¥ããŒãã«ã§ã¯ãããã·ã¥ããã³å§çž®ããããšãã®ããã€ãã®ããŒãåãå€æã€ã³ããã¯ã¹ã«å¯Ÿå¿ããããšããããŸãã ãã®ãããå€æã€ã³ããã¯ã¹ãåãåã£ãããããã䜿çšããŠ
arData
ããããŒã¿ãæœåºããããã·ã¥ãšããŒãæ¯èŒããŠããããå¿
èŠãã©ããã確èªããŸãã ããŒã¿ãæ£ãããªãå Žåã
zval.u2.next
ãã£ãŒã«ãã䜿çšããŠãªã³ã¯ãªã¹ãã
zval.u2.next
ãŸãããã®ãã£ãŒã«ãã«ã¯ãããŒã¿ãå
¥åããããã®æ¬¡ã®ã»ã«ãåæ ãããŸãã
ãªã³ã¯ãªã¹ãã¯ãåŸæ¥ã®ãªã³ã¯ãªã¹ãã®ããã«ã¡ã¢ãªã¹ãã£ãã¿ãªã³ã°ãããªãããšã«æ³šæããŠãã ããã ããŒãããåãåã£ãããã€ãã®ã¡ã¢ãªã«é
眮ããããã€ã³ã¿ã
arData
ã§ã¯
arData
ããããã¢ãã¬ã¹ç©ºéã«æ£ãã°ã£ãŠããïŒãã¡ã¢ãªããå®å
šãªãã¯ãã«
arData
ãèªã¿åããŸãã
ãããŠãããã¯ãPHP 7ããã³èšèªå
šäœã®ããã·ã¥ããŒãã«ã®ããã©ãŒãã³ã¹ãåäžãããäž»ãªçç±ã®1ã€ã§ããPHP 7ã§ã¯ãããã·ã¥ããŒãã«ã®ããŒã¿ã®å±ææ§ã¯éåžžã«é«ããªã£ãŠããŸãã ããŒã¿ã¯éåžžã第1ã¬ãã«ã®ããã»ããµãã£ãã·ã¥ã«ãããããã»ãšãã©ã®å Žåãã¢ã¯ã»ã¹ã¯1ããç§ã§è¡ãããŸãã
ããã·ã¥ã«èŠçŽ ãè¿œå ããè¡çªã解決ããæ¹æ³ãèŠãŠã¿ãŸãããã
idx = ht->nNumUsed++; ht->nNumOfElements++; p = ht->arData + idx; p->key = key; p->h = h = ZSTR_H(key); ZVAL_COPY_VALUE(&p->val, pData); nIndex = h | ht->nTableMask; Z_NEXT(p->val) = HT_HASH(ht, nIndex); HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
åé€ãšåãããšïŒ
h = zend_string_hash_val(key); nIndex = h | ht->nTableMask; idx = HT_HASH(ht, nIndex); while (idx != HT_INVALID_IDX) { p = HT_HASH_TO_BUCKET(ht, idx); if ((p->key == key) || (p->h == h && p->key && ZSTR_LEN(p->key) == ZSTR_LEN(key) && memcmp(ZSTR_VAL(p->key), ZSTR_VAL(key), ZSTR_LEN(key)) == 0)) { _zend_hash_del_el_ex(ht, idx, p, prev); return SUCCESS; } prev = p; idx = Z_NEXT(p->val); } return FAILURE;
å€æã»ã«ãšããã·ã¥ã®åæå
HT_INVALID_IDX
ã¯ãå€æããŒãã«ã«å
¥ããç¹å¥ãªãã©ã°ã§ãã ããã¯ãããã®å€æã¯ã©ãã«ãéããªããããç¶è¡ããå¿
èŠããªããããšãæå³ããŸãã
2段éã®åæåã«ã¯ç¹å®ã®å©ç¹ããããäœæãããã°ããã®ç©ºã®ããã·ã¥ããŒãã«ïŒPHPã®äžè¬çãªã±ãŒã¹ïŒã®åœ±é¿ãæå°éã«æããããšãã§ããŸãã ããŒãã«ãäœæãããšãã«ã
arData
ãã±ããã»ã«ãšã
HT_INVALID_IDX
ãã©ã°ãé
眮ãã2ã€ã®å€æã»ã«ãåæã«äœæããŸãã 次ã«ãæåã®å€æã»ã«ïŒ
HT_INVALID_IDX
ãããã«ã¯ããŒã¿ã¯ãããŸããïŒãæããã¹ã¯ãé©çšããŸãã
#define HT_MIN_MASK ((uint32_t) -2) #define HT_HASH_SIZE(nTableMask) (((size_t)(uint32_t)-(int32_t)(nTableMask)) * sizeof(uint32_t)) #define HT_SET_DATA_ADDR(ht, ptr) do { (ht)->arData = (Bucket*)(((char*)(ptr)) + HT_HASH_SIZE((ht)->nTableMask)); } while (0) static const uint32_t uninitialized_bucket[-HT_MIN_MASK] = {HT_INVALID_IDX, HT_INVALID_IDX}; ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC) { ht->nTableSize = zend_hash_check_size(nSize); ht->nTableMask = HT_MIN_MASK; HT_SET_DATA_ADDR(ht, &uninitialized_bucket); ht->nNumUsed = 0; ht->nNumOfElements = 0; }
ããã§ã¯ãæã䜿çšã§ããªãããšã«æ³šæããŠãã ããã éçconstã¡ã¢ãªãŸãŒã³ã§ååã§ãããã¯ããã«ç°¡åã§ãïŒ
uninitialized_bucket
ïŒã
æåã®èŠçŽ ãè¿œå ããåŸãããã·ã¥ããŒãã«ãå®å
šã«åæåããŸãã ã€ãŸããèŠæ±ããããµã€ãºã«å¿ããŠãæåŸã«å¿
èŠãªå€æã»ã«ãäœæããŸãïŒããã©ã«ãã§ã¯8ã»ã«ããå§ãŸããŸãïŒã ã¡ã¢ãªå
ã®é
眮ã¯ããŒãããæ¥ãŸãã
(ht)->nTableMask = -(ht)->nTableSize; HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), (ht)->u.flags & HASH_FLAG_PERSISTENT)); memset(&HT_HASH(ht, (ht)->nTableMask), HT_INVALID_IDX, HT_HASH_SIZE((ht)->nTableMask))
HT_HASH
ãã¯ãã䜿çš
HT_HASH
ãšãè² ã®ãªãã»ããã䜿çšãããã¡ã¢ãªå
ã«ãããããã¡ãŒã®ãã®éšåã®å€æã»ã«ã«ã¢ã¯ã»ã¹ã§ã
HT_HASH
ã å€æããŒãã«ã®ã»ã«ã«ã¯
arData
ãããã¡ãŒã®å
é ãããã€ãã¹ã®ã€ã³ããã¯ã¹ãä»ãããããããããŒãã«ãã¹ã¯ã¯åžžã«è² ã«ãªããŸãã ããã§ã¯ãCã§ã®ããã°ã©ãã³ã°ããã¹ãŠã®æ å
ã§æããã«ãªããŸãããæ°åååã®ã»ã«ãå©çšå¯èœã§ãç¡éã«æ³³ããjustããªãã§ãã ããã
ã¬ã€ãžãŒåæåïŒã¬ã€ãžãŒåæåïŒããã·ã¥ããŒãã«ã®äŸïŒäœæãããŸãããããããŸã§ããã·ã¥ã¯é
眮ãããŠããŸããã
ããã·ã¥ã®æçåãæ¡å€§ãããã³å§çž®
ããã·ã¥ããŒãã«ããã£ã±ãã§ãæ°ããèŠçŽ ãè¿œå ããå¿
èŠãããå Žåã¯ããµã€ãºã倧ããããå¿
èŠããããŸãã ããã¯ãCã®åŸæ¥ã®ããŒãå¶éé
åãšæ¯èŒããããã·ã¥ããŒãã«ã®å€§ããªå©ç¹ã§ããå¢å ãããã³ã«ãããã·ã¥ããŒãã«ã®ãµã€ãºã¯2åã«ãªããŸãã ããŒãã«ã®ãµã€ãºã倧ãããªããšãã¡ã¢ãªã«Cé
å
arBucket
ãäºåã«å²ãåœãŠã空ã®ã»ã«ã«ç¹å¥ãªUNDEFå€ãé
眮ããããšãæãåºããŠãã ããã ãã®çµæãç§ãã¡ã¯æ¿ããèšæ¶ã倱ããŸãã æ倱ã¯ââ次ã®åŒã§èšç®ãããŸãã
( â ) * Bucket
ãã®ã¡ã¢ãªã¯ãã¹ãŠUNDEFã»ã«ã§æ§æãããããã«ããŒã¿ãé
眮ãããã®ãåŸ
ã¡ãŸãã
ããšãã°ãããã·ã¥ããŒãã«ã«1024åã®ã»ã«ããããæ°ããèŠçŽ ãè¿œå ããŸãã ããŒãã«ã¯2048åã®ã»ã«ã«æ¡å€§ãããã®ãã¡ã®1023åã¯ç©ºã§ãã 1023 * 32ãã€ã=çŽ32 Kbã ããã¯ãPHPã§ããã·ã¥ããŒãã«ãå®è£
ããããšã®æ¬ ç¹ã®1ã€ã§ãã
ããã·ã¥ããŒãã«ãå®å
šã«1ã€ã®UNDEFã»ã«ã§æ§æãããŠããå¯èœæ§ãããããšãèŠããŠããå¿
èŠããããŸãã å€ãã®èŠçŽ ãè¿œå ããã³åé€ãããšãããŒãã«ãæçåãããŸãã ãã ããèŠçŽ ã®é åºãä¿æããããã«ã
arData
ã®æåŸã«ã®ã¿æ°ãããã®ããã¹ãŠè¿œå ããçµæã®ã¹ããŒã¹ã«ã¯æ¿å
¥ããŸããã ãã®ããã
arData
ã®æåŸã«
arData
ãããšç¶æ³ãçºçããå¯èœæ§ããã
arData
ãUNDEFã»ã«ã¯ãŸã ååšããŠããŸãã
éåžžã«æçåããã8ã»ã«ããã·ã¥ããŒãã«ã®äŸïŒ
èŠããŠããããã«ãæ°ããå€ã¯UNDEFã»ã«ã«ä¿åã§ããŸããã äžèšã®ã¹ããŒã ã§ã¯ãããã·ã¥ããŒãã«ãå埩ãããšãã«ã
arData[0]
ãã
arData[7]
ãŸãã
ãµã€ãºã倧ãããããšã
arData
ãã¯ãã«ãæžãããããŒã¿ãåé
åžããã ãã§æçµçã«ç©ºã®ã»ã«ãåããããšãã§ããŸãã ããŒãã«ã«ãµã€ãºå€æŽã®ã³ãã³ããäžãããããšãæåã«ããŒãã«èªäœãå§çž®ããããšããŸãã 次ã«ãå§çž®åŸã«å床å¢å ããå¿
èŠããããã©ãããèšç®ããŸãã ãããŠãã€ãšã¹ãšå€æããå ŽåãããŒãã«ã¯2åã«ãªããŸãã ãã®åŸã
arData
ãã¯ãã«ã¯2åã®ã¡ã¢ãª
(realloc())
arData
å§ããŸãã å¢ããå¿
èŠããªãå ŽåãããŒã¿ã¯æ¢ã«ã¡ã¢ãªã«ããã»ã«ã«åé
åžãããŸãã ããã§ã¯ãèŠçŽ ãåé€ãããã³ã«äœ¿çšã§ããªãã¢ã«ãŽãªãºã ã䜿çšããŸããããã¯ãããŸãã«ãé »ç¹ã«ããã»ããµãªãœãŒã¹ãæ¶è²»ããææ°éãããã»ã©å€§ãããªãããã§ãã æåãªããã°ã©ããŒãããã»ããµãŒãšã¡ã¢ãªãŒã®éã§åŠ¥åããããšãèŠããŠããŸããïŒ
ãã®å³ã¯ãå§çž®åŸã®ä»¥åã®æçåãããããã·ã¥ããŒãã«ã瀺ããŠããŸãã
ã¢ã«ãŽãªãºã ã¯
arData
ã
arData
ãåUNDEFã»ã«ã«æ¬¡ã®éUNDEFã»ã«ããã®ããŒã¿ãåã蟌ã¿ãŸãã ç°¡ç¥åãããšã次ã®ããã«ãªããŸãã
Bucket *p; uint32_t nIndex, i; HT_HASH_RESET(ht); i = 0; p = ht->arData; do { if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) { uint32_t j = i; Bucket *q = p; while (++i < ht->nNumUsed) { p++; if (EXPECTED(Z_TYPE_INFO(p->val) != IS_UNDEF)) { ZVAL_COPY_VALUE(&q->val, &p->val); q->h = p->h; nIndex = q->h | ht->nTableMask; q->key = p->key; Z_NEXT(q->val) = HT_HASH(ht, nIndex); HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(j); if (UNEXPECTED(ht->nInternalPointer == i)) { ht->nInternalPointer = j; } q++; j++; } } ht->nNumUsed = j; break; } nIndex = p->h | ht->nTableMask; Z_NEXT(p->val) = HT_HASH(ht, nIndex); HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(i); p++; } while (++i < ht->nNumUsed);
ããã·ã¥ããŒãã«API
ããŠãããã§PHP 7ã§ããã·ã¥ããŒãã«ãå®è£
ããäž»ãªãã€ã³ããããããŸããã次ã«ããããªãã¯APIãèŠãŠã¿ãŸãããã
ç¹å¥ãªããšã¯äœããããŸããïŒPHP 5ã§ã¯ãAPIã®æ¹ãã¯ããã«åªããŠããŸãïŒã APIé¢æ°ã䜿çšãããšãã¯ã次ã®3ã€ã®ããšãå¿ããªãã§ãã ããã
- æäœã«ã€ããŠïŒè¿œå ãåé€ãã¯ãªãŒãã³ã°ãç Žæ£ãªã©ïŒã
- ããŒã®ã¿ã€ãã«ã€ããŠïŒæŽæ°ãŸãã¯å°æåïŒã
- ä¿åããããŒã¿ã®çš®é¡ã«ã€ããŠã
ããŒãå°æåãæŽæ°ã«ããããããäž»ãªããšïŒå°æåã®ããŒã«ã¯
zend_string
ããã®ããã·ã¥ã
zend_string
ãæŽæ°ã¯ããã«ããã·ã¥ãšããŠäœ¿çšãããããšãAPIãèªèããå¿
èŠããããŸãã ãããã£ãŠã
zend_hash_add(ht, zend_string, data)
ãŸãã¯
zend_hash_index_add(ht, long, data)
ãæºããããšãã§ããŸãã
ããŒã¯åçŽãªãã¢ïŒchar * / intïŒã«ãªãå ŽåããããŸãã ãã®å Žåã
zend_hash_str_add(ht, char *, int, data)
ãªã©ã®å¥ã®APIã䜿çšããå¿
èŠããããŸãã ããã·ã¥ããŒãã«ã¯
zend_string
ã«ã¢ã¯ã»ã¹ããæååããŒã«å€æããŠããã·ã¥ãèšç®ããããçšåºŠã®ããã»ããµãªãœãŒã¹ãæ¶è²»ããããšã«
zend_string
ããŠãã ããã
zend_string
ã䜿çšã§ããå Žåã¯ã䜿çšããŸãã ããã·ã¥ã¯ãã§ã«èšç®ãããŠããã®ã§ãAPIã¯ããããååŸããŸãã ããšãã°ãPHPã³ã³ãã€ã©ã¯ã
zend_string
ããã«ã䜿çšãããæååã®åéšåã®ããã·ã¥ãèšç®ããŸãã OPCacheã¯åæ§ã®ããã·ã¥ãå
±æã¡ã¢ãªã«ä¿åããŸãã æ¡åŒµæ©èœã®äœæè
ãšããŠããã¹ãŠã®
zend_string
ãªãã©ã«ã
zend_string
åæåããããšããå§ãããŸãã
次ã«ãããã·ã¥ããŒãã«ã«ä¿åããããŒã¿ã«ã€ããŠèª¬æããŸãã ç¹°ãè¿ãã«ãªããŸãããããã·ã¥ããŒãã«ã¯å
Bucket
zval
ã«ããŒã¿ãé
眮ããŸãã PHP 7ã§ã¯ãzvalã¯ããããçš®é¡ã®ããŒã¿ãä¿åã§ããŸãã äžè¬ã«ãããã·ã¥ããŒãã«APIã¯ãããŒã¿ã
zval
ã«ããã¯ããããšãæåŸ
ããŠããŸã
zval
ã¯ãAPIãå€ãšããŠèªèããŸãã
ã¹ãã¬ãŒãžãŸãã¯ã¡ã¢ãªé åãžã®ãã€ã³ã¿ãŒïŒãã€ã³ã¿ãŒã«ãã£ãŠåç
§ãããããŒã¿ïŒãããå Žåãç¶æ³ã¯å€å°åçŽåã§ããŸãã 次ã«ãAPIã¯ãã®ãã€ã³ã¿ãŒãŸãã¯ã¡ã¢ãªé åãzvalã«é
眮ããzvalèªäœããã€ã³ã¿ãŒãããŒã¿ãšããŠäœ¿çšããŸãã
äŸã¯ãã¢ã€ãã¢ãç解ããã®ã«åœ¹ç«ã¡ãŸãã
zend_hash_str_add_mem(hashtable *, char *, size_t, void *) zend_hash_index_del(hashtable *, zend_ulong) zend_hash_update_ptr(hashtable *, zend_string *, void *) zend_hash_index_add_empty_element(hashtable *, zend_ulong)
ããŒã¿ãååŸãããšãzval *ãŸãã¯NULLãååŸãããŸãã ãã€ã³ã¿ãŒãå€ãšããŠäœ¿çšãããå ŽåãAPIã¯ãã®ãŸãŸè¿ãããŸãã
zend_hash_index_find(hashtable *, zend_string *) : zval * zend_hash_find_ptr(hashtable *, zend_string *) : void * zend_hash_index_find(hashtable *, zend_ulong) : zval *
zend_hash_add_new()
ãããª_new APIã«ã€ããŠã¯ã䜿çšããªãæ¹ãè¯ãã§ãããã å
éšã®ããŒãºã«ãšã³ãžã³ã䜿çšããŸãã ãã®APIã¯ãããã·ã¥ïŒåãããŒïŒã§æ¢ã«äœ¿çšå¯èœãªå Žåã§ããããã·ã¥ããŒãã«ã«ããŒã¿ãä¿åãããŸãã ãã®çµæãéè€ãçããäœæ¥ã«æé©ãªå¹æãåŸãããªãå ŽåããããŸãã ãããã£ãŠãè¿œå ããããšããŠããããã·ã¥ã«ããŒã¿ããªãããšãå®å
šã«ç¢ºä¿¡ããŠããå Žåã«ã®ã¿ããã®APIã䜿çšã§ããŸãã ãããã£ãŠãããããæ¢ãå¿
èŠã¯ãããŸããã
: 5, API
zend_symtable_api()
:
static zend_always_inline zval *zend_symtable_update(HashTable *ht, zend_string *key, zval *pData) { zend_ulong idx; if (ZEND_HANDLE_NUMERIC(key, idx)) { return zend_hash_index_update(ht, idx, pData); } else { return zend_hash_update(ht, key, pData); } }
, : , zvalâŠ
ZEND_HASH_FOREACH
:
#define ZEND_HASH_FOREACH(_ht, indirect) do { \ Bucket *_p = (_ht)->arData; \ Bucket *_end = _p + (_ht)->nNumUsed; \ for (; _p != _end; _p++) { \ zval *_z = &_p->val; \ if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \ _z = Z_INDIRECT_P(_z); \ } \ if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue; #define ZEND_HASH_FOREACH_END() \ } \ } while (0)
« -»
, :
arData
, ,
arData
. -: -
arData
. - , .
: .
arData
, . , .
« -» (packed hashtable):
, .
arData[0]
. , 2 * uint32 = 8 . . , , .
: , , ( /), - . bucket'.
ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht) { void *new_data, *old_data = HT_GET_DATA_ADDR(ht); Bucket *old_buckets = ht->arData; ht->u.flags &= ~HASH_FLAG_PACKED; new_data = pemalloc(HT_SIZE_EX(ht->nTableSize, -ht->nTableSize), (ht)->u.flags & HASH_FLAG_PERSISTENT); ht->nTableMask = -ht->nTableSize; HT_SET_DATA_ADDR(ht, new_data); memcpy(ht->arData, old_buckets, sizeof(Bucket) * ht->nNumUsed); pefree(old_data, (ht)->u.flags & HASH_FLAG_PERSISTENT); zend_hash_rehash(ht); }
-
u.flags
, , -. , -, . , . äŸïŒ
static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag ZEND_FILE_LINE_DC) { uint32_t nIndex; uint32_t idx; Bucket *p; if (UNEXPECTED(!(ht->u.flags & HASH_FLAG_INITIALIZED))) { CHECK_INIT(ht, h < ht->nTableSize); if (h < ht->nTableSize) { p = ht->arData + h; goto add_to_packed; } goto add_to_hash; } else if (ht->u.flags & HASH_FLAG_PACKED) { } else if (EXPECTED(h < ht->nTableSize)) { p = ht->arData + h; } else if ((h >> 1) < ht->nTableSize && (ht->nTableSize >> 1) < ht->nNumOfElements) { zend_hash_packed_grow(ht); p = ht->arData + h; } else { goto convert_to_hash; }
: - , .
- : :
(_ - 2) * (uint32)
. , . - : . , .
(, 42 60), - «». ( â ) . - API:
void ZEND_FASTCALL zend_hash_real_init(HashTable *ht, zend_bool packed)
,
zend_hash_real_init()
â , «» (
zend_hash_init()
). , «», - . , .
, - .
-
(packed array):
function m() { printf("%d\n", memory_get_usage()); } $a = range(1,20000); m(); for($i=0; $i<5000; $i++) { $a[] = $i; } m(); $a['foo'] = 'bar'; m();
, :
1406744 1406776 1533752
130 ( 25 000 ).
:
function m() { printf("%d\n", memory_get_usage()); } for ($i=0; $i<32768; $i++) { $a[$i] = $i; } m(); for ($i=0; $i<32768; $i++) { unset($a[$i]); } m(); $a[] = 42; m();
çµæïŒ
1406864 1406896 1533872
, ( , modulo noise).
unset()
arData
32 768 , UNDEF-zval'.
-
.
nNumUsed
,
arData
? , , .
?
â , UNDEF-. : ,
, , . , , , .
$a[3] = 42; m();
:
1406864 1406896 1406896
? 32 768 65 538 , . 32 767 .
Bucket
,
zval
,
long
( 42), . zval long. :) ,
32 768 , , , . , , . ., , UNDEF-zval' «» .
-, . , , , . «» , (
idx 0
), â UNDEF-zval.
function m() { printf("%d\n", memory_get_usage()); } for ($i=0; $i<32768; $i++) { $a[' ' . $i] = $i; } m(); for ($i=0; $i<32768; $i++) { unset($a[' ' . $i]); } m(); $a[] = 42; m();
:
2582480 1533936 1533936
. 2,5 .
unset()
, . 32 768
zend_string
, 1,5 .
, , . , , . 42 idx 0, . ç©èªã®çµããã
, - , . ? , (, ?) / , . . , . «» 20 32 , .
(Immutable arrays)
â OPCache. OPCache, , . . . OPCache , . , AST-. , â AST-. äŸïŒ
$a = ['foo', 1, 'bar'];
$a
â AST-. , , . OPCache AST-, ( ) , . OPCache
.
, OPCache ,
IS_ARRAY_IMMUTABLE IS_TYPE_IMMUTABLE .
IS_IMMUTABLE , . , . .
:
$ar = []; for ($i = 0; $i < 1000000; ++$i) { $ar[] = [1, 2, 3, 4, 5, 6, 7, 8]; }
400 OPCache, â 35 . OPCache , 8-
$ar
. 8- . OPCache, 8-
IS_IMMUTABLE $ar
, .
, , ,
$ar[42][3] = 'foo';
, 8-
$ar[42]
.
- , . , PHP- â - Zend. PHP, . - . , / . -. OPArray ( ) ( ). PHP , OPArray: . OPCache
IMMUTABLE , . , .
OPCache , . , ( , ). , - OPCache , PHP- . PHP.
. , :
$a = [1]; $b = [1];
. , (
interned strings ), , . â , ( , , ), runtime' PHP. ( ). , OPCache.