Maison > Article > développement back-end > Analyse du code source du noyau sous-jacent PHP8 - tableau (4)
Cet article vous présente "Analyse du code source du noyau sous-jacent PHP8 - tableau (4)". Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il sera utile à tout le monde.
Articles connexes recommandés : "Analyse du code source du noyau sous-jacent PHP8 - tableau (1) " "Analyse du code source du noyau sous-jacent PHP8 - tableau (2) " " Analyse du code source du noyau sous-jacent PHP8 - tableau (3) 》
Dans le processus d'exécution, nous savons déjà que le code doit passer par une analyse lexicale, une analyse syntaxique, une compilation et une exécution de quatre étapes majeures
PHP 8 créera une constante de tableau lors de la compilation phase (lorsque l'arbre de syntaxe abstraite AST est compilé en opcode). Cette constante de tableau, comme les constantes numériques et les constantes de chaîne, est déterminée et allouée en mémoire lors de la phase de compilation. L'initialisation du tableau se produit donc lors de la phase de compilation.
La partie code d'initialisation du tableau de PHP est la suivante
//如果开启zend_debug #if !ZEND_DEBUG && defined(HAVE_BUILTIN_CONSTANT_P) # define zend_new_array(size) \ (__builtin_constant_p(size) ? \ ((((uint32_t)(size)) <= HT_MIN_SIZE) ? \ _zend_new_array_0() \ //走 _zend_new_array_0 : \ _zend_new_array((size)) \ ) \ : \ _zend_new_array((size)) \ ) #else //没有开启 也就是一般模式 走 _zend_new_array # define zend_new_array(size) \ _zend_new_array(size) #endif ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent) { _zend_hash_init_int(ht, nSize, pDestructor, persistent); } ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void) { //分配内存空间 HashTable *ht = emalloc(sizeof(HashTable)); //初始化 _zend_hash_init_int(ht, HT_MIN_SIZE, ZVAL_PTR_DTOR, 0); return ht; } //初始化方法 static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent) { GC_SET_REFCOUNT(ht, 1); GC_TYPE_INFO(ht) = GC_ARRAY | (persistent ? ((GC_PERSISTENT|GC_NOT_COLLECTABLE) << GC_FLAGS_SHIFT) : 0); HT_FLAGS(ht) = HASH_FLAG_UNINITIALIZED; ht->nTableMask = HT_MIN_MASK; HT_SET_DATA_ADDR(ht, &uninitialized_bucket); ht->nNumUsed = 0; ht->nNumOfElements = 0; ht->nInternalPointer = 0; ht->nNextFreeElement = ZEND_LONG_MIN; ht->pDestructor = pDestructor; ht->nTableSize = zend_hash_check_size(nSize); } //初始化 bucket 也就是 ardata ZEND_API void ZEND_FASTCALL zend_hash_real_init(HashTable *ht, zend_bool packed) { IS_CONSISTENT(ht); HT_ASSERT_RC1(ht); //调用 zend_hash_real_init_ex方法 zend_hash_real_init_ex(ht, packed); } //zend_hash_real_init_ex方法 static zend_always_inline void zend_hash_real_init_ex(HashTable *ht, bool packed) { HT_ASSERT_RC1(ht); ZEND_ASSERT(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED); if (packed) { //如果是packed_array zend_hash_real_init_packed_ex(ht); } else { //如果是 hash_array zend_hash_real_init_mixed_ex(ht); } } //paced_array 初始化bucket 的代码 static zend_always_inline void zend_hash_real_init_packed_ex(HashTable *ht) { void *data; if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) { data = pemalloc(HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), 1); } else if (EXPECTED(ht->nTableSize == HT_MIN_SIZE)) { data = emalloc(HT_SIZE_EX(HT_MIN_SIZE, HT_MIN_MASK)); } else { data = emalloc(HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK)); } HT_SET_DATA_ADDR(ht, data); /* Don't overwrite iterator count. */ ht->u.v.flags = HASH_FLAG_PACKED | HASH_FLAG_STATIC_KEYS; HT_HASH_RESET_PACKED(ht); } //hash_array 初始化bucket的代码 static zend_always_inline void zend_hash_real_init_mixed_ex(HashTable *ht) { void *data; uint32_t nSize = ht->nTableSize; if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) { data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), 1); } else if (EXPECTED(nSize == HT_MIN_SIZE)) { data = emalloc(HT_SIZE_EX(HT_MIN_SIZE, HT_SIZE_TO_MASK(HT_MIN_SIZE))); ht->nTableMask = HT_SIZE_TO_MASK(HT_MIN_SIZE); HT_SET_DATA_ADDR(ht, data); /* Don't overwrite iterator count. */ ht->u.v.flags = HASH_FLAG_STATIC_KEYS; #ifdef __SSE2__ do { __m128i xmm0 = _mm_setzero_si128(); xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); _mm_storeu_si128((__m128i*)&HT_HASH_EX(data, 0), xmm0); _mm_storeu_si128((__m128i*)&HT_HASH_EX(data, 4), xmm0); _mm_storeu_si128((__m128i*)&HT_HASH_EX(data, 8), xmm0); _mm_storeu_si128((__m128i*)&HT_HASH_EX(data, 12), xmm0); } while (0); #elif defined(__aarch64__) do { int32x4_t t = vdupq_n_s32(-1); vst1q_s32((int32_t*)&HT_HASH_EX(data, 0), t); vst1q_s32((int32_t*)&HT_HASH_EX(data, 4), t); vst1q_s32((int32_t*)&HT_HASH_EX(data, 8), t); vst1q_s32((int32_t*)&HT_HASH_EX(data, 12), t); } while (0); #else HT_HASH_EX(data, 0) = -1; HT_HASH_EX(data, 1) = -1; HT_HASH_EX(data, 2) = -1; HT_HASH_EX(data, 3) = -1; HT_HASH_EX(data, 4) = -1; HT_HASH_EX(data, 5) = -1; HT_HASH_EX(data, 6) = -1; HT_HASH_EX(data, 7) = -1; HT_HASH_EX(data, 8) = -1; HT_HASH_EX(data, 9) = -1; HT_HASH_EX(data, 10) = -1; HT_HASH_EX(data, 11) = -1; HT_HASH_EX(data, 12) = -1; HT_HASH_EX(data, 13) = -1; HT_HASH_EX(data, 14) = -1; HT_HASH_EX(data, 15) = -1; #endif return; } else { data = emalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize))); } ht->nTableMask = HT_SIZE_TO_MASK(nSize); HT_SET_DATA_ADDR(ht, data); HT_FLAGS(ht) = HASH_FLAG_STATIC_KEYS; HT_HASH_RESET(ht); } //数组赋值和更新值 static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag) { uint32_t nIndex; uint32_t idx; Bucket *p; IS_CONSISTENT(ht); HT_ASSERT_RC1(ht); if ((flag & HASH_ADD_NEXT) && h == ZEND_LONG_MIN) { h = 0; } if (HT_FLAGS(ht) & HASH_FLAG_PACKED) { if (h < ht->nNumUsed) { p = ht->arData + h; if (Z_TYPE(p->val) != IS_UNDEF) { replace: if (flag & HASH_ADD) { return NULL; } if (ht->pDestructor) { ht->pDestructor(&p->val); } ZVAL_COPY_VALUE(&p->val, pData); return &p->val; } else { /* we have to keep the order :( */ goto convert_to_hash; } } else if (EXPECTED(h < ht->nTableSize)) { add_to_packed: p = ht->arData + h; /* incremental initialization of empty Buckets */ if ((flag & (HASH_ADD_NEW|HASH_ADD_NEXT)) != (HASH_ADD_NEW|HASH_ADD_NEXT)) { if (h > ht->nNumUsed) { Bucket *q = ht->arData + ht->nNumUsed; while (q != p) { ZVAL_UNDEF(&q->val); q++; } } } ht->nNextFreeElement = ht->nNumUsed = h + 1; goto add; } else if ((h >> 1) < ht->nTableSize && (ht->nTableSize >> 1) < ht->nNumOfElements) { zend_hash_packed_grow(ht); goto add_to_packed; } else { if (ht->nNumUsed >= ht->nTableSize) { ht->nTableSize += ht->nTableSize; } convert_to_hash: zend_hash_packed_to_hash(ht); } } else if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) { if (h < ht->nTableSize) { zend_hash_real_init_packed_ex(ht); goto add_to_packed; } zend_hash_real_init_mixed(ht); } else { if ((flag & HASH_ADD_NEW) == 0 || ZEND_DEBUG) { p = zend_hash_index_find_bucket(ht, h); if (p) { ZEND_ASSERT((flag & HASH_ADD_NEW) == 0); goto replace; } } ZEND_HASH_IF_FULL_DO_RESIZE(ht);/* If the Hash table is full, resize it */ } idx = ht->nNumUsed++; nIndex = h | ht->nTableMask; p = ht->arData + idx; Z_NEXT(p->val) = HT_HASH(ht, nIndex); HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx); if ((zend_long)h >= ht->nNextFreeElement) { ht->nNextFreeElement = (zend_long)h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX; } add: ht->nNumOfElements++; p->h = h; p->key = NULL; ZVAL_COPY_VALUE(&p->val, pData); return &p->val; }
_zend_hash_init_int L'organigramme est la suivante
En PHP 8, l'initialisation des tableaux est en fait divisée en deux étapes.
Étape 1 : allouer la mémoire de la structure HashTable
Étape 2 : initialiser chaque champ de la structure HashTable
Étape 3 : allouer la mémoire du tableau de compartiments et modifier certaines valeurs de champ.
Pour l'étape 3, cela ne se fait pas à chaque fois. Par exemple, comme "$a = array()", puisque le tableau est vide, PHP ne demandera pas de mémoire supplémentaire pour le tableau de compartiments. Pour la méthode d'écriture "$a = array(1, 2, 3)", puisque le tableau n'est pas vide, PHP doit effectuer l'étape 3 pour allouer la mémoire du tableau de compartiment et modifier certaines valeurs de champ.
▏Cet article a été publié sur le site Web PHP chinois avec le consentement de l'auteur original PHP Cui Xuefeng L'adresse originale : https://zhuanlan.zhihu.com/p/361006441
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!