search
HomeBackend DevelopmentPHP8Parsing PHP8 underlying kernel source code - array (4)

This article introduces to you "Analysis of PHP8 underlying kernel source code - array (4)". It has certain reference value. Friends in need can refer to it. I hope it will be helpful to everyone.

Recommended related articles: "Analysis of PHP8 underlying kernel source code - array (1) " "Analysis of PHP8 underlying kernel source code - array (2) " " Parsing PHP8 underlying kernel source code - array (3)

In Runningprocess, we already know that the code needs to go through lexical analysis, syntax analysis, compilation and execution of four major steps

PHP 8 will create an array constant during the compilation phase (when the AST abstract syntax tree is compiled into opcode). This array constant, like numeric constants and string constants, is determined and allocated memory during the compilation phase. So the initialization of the array happens during the compilation phase.

PHP’s array initialization code part is as follows

//如果开启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&#39;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&#39;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 The flow chart is as follows

Parsing PHP8 underlying kernel source code - array (4)
_zend_hash_init_int method flow chart ( Initializing hash)
Parsing PHP8 underlying kernel source code - array (4)##zend_hash_real_init_ex method flow chart (initializing bucket)


In PHP 8, the initialization of the array is actually divided into two steps.

Step 1: Allocate HashTable structure memory

Step 2: Initialize each field of the HashTable structure

Step 3: Allocate bucket array memory and modify some field values .

For step 3, it is not done every time. For example, like "$a = array()", since the array is empty, PHP will not apply for additional bucket array memory. For the writing method "$a = array(1, 2, 3)", since the array is not empty, PHP needs to perform step 3 to allocate bucket array memory and modify some field values.

Parsing PHP8 underlying kernel source code - array (4)


#zend_hash_real_init_packed_ex( Bucket initialization flow chart when it is packed_array)Parsing PHP8 underlying kernel source code - array (4)
Parsing PHP8 underlying kernel source code - array (4)
▏This article was published on the PHP Chinese website with the consent of the original author PHP Cui Xuefeng, the original address: https://zhuanlan.zhihu.com/p/361006441

The above is the detailed content of Parsing PHP8 underlying kernel source code - array (4). For more information, please follow other related articles on the PHP Chinese website!

Statement
This article is reproduced at:PHP崔雪峰. If there is any infringement, please contact admin@php.cn delete
php8怎么加mysql扩展php8怎么加mysql扩展Oct 07, 2023 pm 03:31 PM

php8加mysql扩展的步骤是:1、安装MySQL客户端库;2、安装PHP 8的开发工具;3、下载MySQL扩展源代码;4、编译和安装MySQL扩展;5、启用MySQL扩展;6、重启Web服务器即可。

php5和php8有什么区别php5和php8有什么区别Sep 25, 2023 pm 01:34 PM

php5和php8的区别在性能、语言结构、类型系统、错误处理、异步编程、标准库函数和安全性等方面。详细介绍:1、性能提升,PHP8相对于PHP5来说在性能方面有了巨大的提升,PHP8引入了JIT编译器,可以对一些高频执行的代码进行编译和优化,从而提高运行速度;2、语言结构改进,PHP8引入了一些新的语言结构和功能,PHP8支持命名参数,允许开发者通过参数名而不是参数顺序等等。

图文详解apache2.4+php8.0的安装配置方法图文详解apache2.4+php8.0的安装配置方法Dec 06, 2022 pm 04:53 PM

本文给大家介绍如何安装apache2.4,以及如何配置php8.0,文中附有图文详细步骤,下面就带大家一起看看怎么安装配置apache2.4+php8.0吧~

php8怎么连接数据库php8怎么连接数据库Nov 16, 2023 pm 02:41 PM

PHP8可以使用mysqli和PDO来连接数据库。详细介绍:1、使用mysqli连接数据库,通过传入数据库服务器名称、用户名、密码和数据库名称来进行连接。然后,使用`connect_error`属性来检查连接是否成功,如果连接失败,则输出错误信息。最后,通过调用`close()`方法关闭连接;2、使用PDO连接数据库,通过传入数据库服务器名称、密码和数据库名称来进行连接等等。

php8数据类型怎么转换php8数据类型怎么转换Nov 16, 2023 pm 02:51 PM

php8数据类型的方法有字符串转换为整数、整数转换为字符串、字符串转换为浮点数、浮点数转换为字符串、数组转换为字符串、字符串转换为数组、布尔值转换为整数、整数转换为布尔值和变量类型判断和转换。详细介绍:1、字符串转换为整数包括intval()函数和(int)强制类型转换;2、整数转换为字符串包括strval()函数和(string)强制类型转换;3、字符串转换为浮点数等等。

php 怎么求2个数组相同的元素php 怎么求2个数组相同的元素Dec 23, 2022 am 10:04 AM

php求2个数组相同元素的方法:1、创建一个php示例文件;2、定义两个有相同元素的数组;3、使用“array_intersect($array1,$array2)”或“array_intersect_assoc()”方法获取两个数组相同元素即可。

c++数组怎么初始化c++数组怎么初始化Oct 15, 2021 pm 02:09 PM

c++初始化数组的方法:1、先定义数组再给数组赋值,语法“数据类型 数组名[length];数组名[下标]=值;”;2、定义数组时初始化数组,语法“数据类型 数组名[length]=[值列表]”。

一文深入了解 PHP 8 中的 JIT一文深入了解 PHP 8 中的 JITApr 25, 2022 pm 08:46 PM

本篇文章带大家了解一下PHP 8 中的 JIT,并聊聊JIT 是怎么参与解释流程的,希望对大家有所帮助!

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
Repo: How To Revive Teammates
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: How To Get Giant Seeds
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

SublimeText3 Linux new version

SublimeText3 Linux new version

SublimeText3 Linux latest version

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

Atom editor mac version download

Atom editor mac version download

The most popular open source editor

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Powerful PHP integrated development environment