@@ -56,6 +56,59 @@ static int __attribute__((fastcall)) ZEND_ASSIGN_SPEC_CV_CONST_HANDLER(zend_exe
5656 return 0; 
5757} 
5858``` 
59- 从这个例子可以很清楚的看到,执行完以后会将execute_data->opline加1,也就是指向下一条opcode,然后返回0给execute_ex(),接着执行器在下一次循环时执行下一条opcode,依次类推,直至所有的opcode执行完成。
59+ 从这个例子可以很清楚的看到,执行完以后会将execute_data->opline加1,也就是指向下一条opcode,然后返回0给execute_ex(),接着执行器在下一次循环时执行下一条opcode,依次类推,直至所有的opcode执行完成。这个处理过程比较简单,并没有不好理解的地方,而且整个过程看起来也都那么顺理成章。PHP7针对execute_data、opline两个变量的存储位置进行了优化,那就是使用全局寄存器保存这两个变量的地址,以实现更高效率的读取。这种方式下execute_data、opline直接从寄存器读取地址,在性能上大概有5%的提升(官方说法)。在分析PHP7的优化之前,我们先简单介绍下什么是寄存器变量。
60+ 
61+ 寄存器变量存放在CPU的寄存器中,使用时,不需要访问内存直接从寄存器中读写,与存储在内存中的变量相比,寄存器变量具有更快的访问速度,在计算机的存储层次中,寄存器的速度最快,其>次是内存,最慢的是内存。C语言中使用关键字register来声明局部变量为寄存器变量,需要注意的是,只有局部自动变量和形式参数才能够被定义为寄存器变量,全局变量和局部静态变量都不能被定义为寄存器变量。而且,一个计算机中寄存器数量是有限的,一般为2到3个,因此寄存器变量的数量不能太多。对于在一个函数中说明的多于2到3个的寄存器变量,C编译程序会自动地将寄存器变量变为自动变量。 受硬件寄存器长度的限制,寄存器变量只能是char、int或指针型,而不能使其他复杂数据类型。由于register变量使用的是硬件CPU中的寄存器,寄存器变量无地址,所以不能使用取地址运算符"&"求寄存器变量的地址。
62+ 
63+ GCC从4.8.0版本开始支持了另外一项特性:全局寄存器变量,也就是可以把全局变量定义为寄存器变量,从而可以实现函数间共享数据。可以通过下面的语法告诉编译器使用寄存器来保存数据:
64+ ``` c 
65+ register  int  *foo asm  ("r12"); //r12、%r12
66+ ``` 
67+ 或者: 
68+ ```c 
69+ register int *foo __asm__ ("r12"); //r12、%r12 
70+ ``` 
71+ 这里r12就是指定使用的寄存器,它必须是运行平台上有效的寄存器,这样就可以像使用普通的变量一样使用foo,但是foo同样没有地址,也就是无法通过&获取它的地址,在gdb调试时也无法使用foo符号,只能使用对应的寄存器获取数据。举个例子来看:
72+ ``` c 
73+ // main.c
74+ #include  < stdlib.h> 
75+ 
76+ typedef  struct  _execute_data {
77+  int ip; 
78+ }zend_execute_data;
79+ 
80+ 
81+ register  zend_execute_data* execute_data __asm__  ("%r14");
82+ 
83+ int main(void)
84+ {
85+  execute_data = (zend_execute_data * )malloc(sizeof(zend_execute_data));
86+  execute_data->ip = 9999;
87+ 
88+  return 0; 
89+ }
90+ ``` 
91+ 编译:`$ gcc -o main -g main.c`,然后通过gdb看下: 
92+ ```sh 
93+ $ gdb main 
94+ (gdb) break main 
95+ (gdb) r 
96+ Starting program: /home/qinpeng/c/php/main  
97+ 
98+ Breakpoint 1, main () at main.c:12 
99+ 12 execute_data = (zend_execute_data *)malloc(sizeof(zend_execute_data)); 
100+ (gdb) n 
101+ 13 execute_data->ip = 9999; 
102+ (gdb) n 
103+ 15 return 0; 
104+ ``` 
105+ 这时我们就无法再像普通变量那样直接使用execute_data访问数据,只能通过r14寄存器读取:
106+ ``` sh 
107+ (gdb) p execute_data
108+ Missing ELF symbol " execute_data" 
109+ (gdb) info register r14
110+ r14 0x601010 6295568
111+ (gdb) p (( zend_execute_data * )$r14 )-> ip
112+ $3  =  9999 
113+ ``` 
60114
61- 全局寄存器变量(Global Register Variables)是数据保存在寄存器中的一种变量,与存储在内存中的变量相比,寄存器变量具有更快的访问速度,在计算机的存储层次中,寄存器的速度最快,其次是内存,最慢的是内存。寄存器变量
0 commit comments