Transcript
Page 1: Zend Engine  изнутри

Zend Engine изнутри

Дмитрий Стогов

Page 2: Zend Engine  изнутри

Немного истории

• Zend Engine была разработана в качестве ядра для PHP 4 Andi Gutmans и Zeev Suraski в 1999

• PHP 5.0 основан на Zend Engine 2 с новой объектной моделью

• PHP 5.1 основан на Zend Engine 2.1 со специализированной VM

• PHP 5.2 основан на Zend Engine 2.2 с новым менеджером памяти

• PHP 5.3 основан на Zend Engine 2.3 которая включает большинство улучшений и нововведений из PHP6, за исключением Unicode, (namespace-ы, сборщик мусора, LSB, оператор goto, ленивая инициализация таблиц символов, новый сканнер основанный на re2c)

• PHP 6 основан на Zend Engine 3 с поддержкой Unicode

Page 3: Zend Engine  изнутри

Подсистемы ZE

• Менеджер памяти • API для доступа к внутренним структурам данных• Компилятор PHP• Виртуальная машина PHP• API для ресурсов (файлы, DB коннекшены)• API для внешних расширений PHP• Набор внутренних функций• Сборщик мусора (5.3)

Page 4: Zend Engine  изнутри

Стадии работы PHP

Page 5: Zend Engine  изнутри

Thread Safe Resource Manager

• non-ZTS-build (single-thread)• ZTS-build (thread-safe)

• Каждый thread работает со своими глобальными данными

• ZE использует compiler_globals (CG) и executor_globals (EG)

• Любое расширение PHP может определить свои глобальные данные, которые должны быть уникальными для разных thread-ов

Page 6: Zend Engine  изнутри

TSRM макросы

• void some_function(void) {process(EG(symbol_table)); // compilation error

}

Page 7: Zend Engine  изнутри

TSRM макросы

• void some_function(void) {int some_local_variable;TSRMLS_FETCH();

process(EG(symbol_table));}

• void some_function(TSRMLS_D) {process(EG(symbol_table));

}some_function(TSRMLS_C);

• void some_function(int some_paremeter TSRMLS_DC) {process(EG(symbol_table));

}some_function(0 TSRMLS_CC);

Page 8: Zend Engine  изнутри

Менеджер памяти

emalloc()efree()erealloc()estrdup()estrndup()ecalloc()

$ USE_ZEND_ALLOC=0 valgrind php test.php

Page 9: Zend Engine  изнутри

Значения (zval-коетейнер)

typedef struct _zval_struct {zend_uchar type;zvalue_value value;zend_uchar is_ref;zebd_uint refcount;

} zval;

Page 10: Zend Engine  изнутри

Значения (zval-коетейнер)

typedef struct _zval_struct {zend_uchar type;zvalue_value value;zend_uchar is_ref;zebd_uint refcount;

} zval;

IS_NULLIS_LONGIS_DOUBLEIS_BOOLIS_ARRAYIS_OBJECTIS_STRINGIS_RESOURCEIS_CONSTANTIS_CONSTANT_ARRAY

Page 11: Zend Engine  изнутри

Значения (zval-коетейнер)

typedef struct _zval_struct {zend_uchar type;zvalue_value value;zend_uchar is_ref;zebd_uint refcount;

} zval;

typedef union _zvalue_value {long lval;double dval;struct {

char *val;int len;

} str;HashTable *ht;zend_object_value obj;

} zvalue_value;

Page 12: Zend Engine  изнутри

Ссылки

<?php

$a = 10;

$b =& $b;$a

$b

EG(symbol_table)

type

value

is_ref

refcount

IS_LONG

10

1

2

zval

HashTable

Page 13: Zend Engine  изнутри

Присваивание и копирование при записи

<?php$a = 1;$b = $a;

$b = 2;

$b =& $a;

$b = 3;

$b =& $c;

// $a = {1, refcount=1, is_ref=0}// $a = {1, refcount=2, is_ref=0}// $b = {1, refcount=2, is_ref=0}// $a = {1, refcount=1, is_ref=0}// $b = {2, refcount=1, is_ref=0}// $a = {1, refcount=2, is_ref=1}// $b = {1, refcount=2, is_ref=1}// $a = {3, refcount=2, is_ref=1}// $b = {3, refcount=2, is_ref=1}// $a = {3, refcount=1, is_ref=0}// $b = {?, refcount=?, is_ref=1}

Page 14: Zend Engine  изнутри

Компилятор

• Основан на flex/bison based (основан на re2c/bison начиная с 5.3)

• Однопроходная компиляция (на самом деле два прохода)– AST не создается– Прямая компиляция в байт-кодVM– Быстрая компиляция– Оптимизация практически не выполняется

Page 15: Zend Engine  изнутри

Глобальные данные компилятора (CG)

• struct _zend_compiler_globals {…HashTable *function_table;HashTable *class_table;zend_class_entry *active_class_entry;zend_op_array *active_op_array;…

};

• CG(function_table)

Page 16: Zend Engine  изнутри

Функции PHP (op_array)

typedef struct _zend_op_array {zend_uchar type;char *function_name;zend_class_entry *scope;zend_uint fn_flags;zend_op *opcodes;zend_compiled_variables *vars;zend_uint last, lat_var, T;HashTable *static_variables;…

} zend_op_array;

Page 17: Zend Engine  изнутри

Инструкции VM (zend_op)

typedef struct _zend_op {zend_uchar opcode;ulong extended_value;znode op1;znode op2;znode result;uint lineno;opcode_handler_t handler;

} zend_op;

Page 18: Zend Engine  изнутри

Инструкции VM (zend_op)

typedef struct _zend_op {zend_uchar opcode;ulong extended_value;znode op1;znode op2;znode result;uint lineno;opcode_handler_t handler;

} zend_op;

ZEND_NOPZEND_ADDZEND_SUBZEND_IS_EQUALZEND_JMPZEND_JMPZZEND_ASSIGNZEND_DO_FCALLZEND_RETURN

~150 opcodes in zend_vm_opcodes.h

Page 19: Zend Engine  изнутри

Инструкции VM (zend_op)

typedef struct _zend_op {zend_uchar opcode;ulong extended_value;znode op1;znode op2;znode result;uint lineno;opcode_handler_t handler;

} zend_op;

typedef struct _znode {int op_type;union {

zval constant;zend_uint var;zend_uint opline_num;zend_op *jmp_addr;struct {

zend_uint var;zend_uint type;

} EA;} u;

} znode;

Page 20: Zend Engine  изнутри

Операнды (znode)

typedef struct _znode {int op_type;union {

zval constant;zend_uint var;zend_uint opline_num;zend_op *jmp_addr;struct {

zend_uint var;zend_uint type;

} EA;} u;

} znode;

IS_CONSTIS_CVIS_TMP_VARIS_VARIS_UNUSED

Page 21: Zend Engine  изнутри

Пример компиляции (5.0)

<?php$a = “Hello”;

$b = “World”;

echo $a .” “. $b;

?>

// FETCH_W C(“a”) -> V(0)// ASSIGN V(0), C(“Hello”)// FETCH_W C(“b”) -> V(1)// ASSIGN V(1), C(“World”)// FETCH_R C(“a”) -> V(2)// CONCAT V(2), C(“ “) -> T(3)// FETCH_R C(“b”) -> V(4)// CONCAT T(3), V(4) -> T(5)// ECHO T(5)// RETURN C(NULL)

Page 22: Zend Engine  изнутри

Пример компиляции (5.1)

<?php

$a = “Hello”;

$b = “World”;

echo $a .” “. $b;

?>

// // ASSIGN CV(0)[“a”], C(“Hello”)// // ASSIGN CV(1)[“b”], C(“World”)// // CONCAT CV(0)[“a”], C(“ “) -> T(0)// CONCAT T(0), CV(1)[“b”] -> T(1)// ECHO T(1)////// RETURN C(NULL)

Page 23: Zend Engine  изнутри

Глобальные данные VM (EG)

• struct _zend_executor_globals {…HashTable *active_symbol_table;HashTable symbol_table; // $GLOBALS[]HashTable *function_table;HashTable *class_table;HashTable *zend_constants;zval *This;zend_class_entry *scope;zend_op_array *active_op_array;zend_op **opline_ptr;struct _zend_execute_data *current_execute_data;…

};

• EG(symbol_table)

Page 24: Zend Engine  изнутри

Switch-threaded Executor (4.*)

void execute(zend_op_array *op_array TSRMLS_DC) {zend_execute_data execute_data;

// initializationEX(opline) = op_array->opcodes;while (1) {

switch (EX(opline)->opcode) {…case ZEND_RETURN;

…return;

}}

}

Page 25: Zend Engine  изнутри

Call-threaded Executor (5.*)

void execute(zend_op_array *op_array TSRMLS_DC) {zend_execute_data execute_data;

// initializationEX(opline) = op_array->opcodes;while (1) {

if (EX(opline)->handler(&execute_data TSRMLS_CC)) {return;

}}

}

Page 26: Zend Engine  изнутри

Call-threaded Executor (5.0)

int zend_concat_handler(ZEND_OPCODE_HANDLER_ARGS) {

zend_op *opline = EX(opline);

concat_function(&EX_T(opline->result.u.var).tmp_var,get_zval_ptr(&opline->op1, EX(Ts),

&EG(free_op1), BP_VAR_R),get_zval_ptr(&opline->op2, EX(Ts),

&EG(free_op2), BP_VAR_R));FREE_OP1(EX(Ts), &opline->op1, EG(free_op1));FREE_OP2(EX(Ts), &opline->op2, EG(free_op2));EX(opline)++;return 0;

}

Page 27: Zend Engine  изнутри

Специализация в VM (5.1)

ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV)

{zend_op *opline = EX(opline);zend_free_op free_op1, free_op2;

concat_function(&EX_T(opline->result.u.var).tmp_var,GET_OP1_ZVAL_PTR(BP_VAR_R),GET_OP2_ZVAL_PTR(BP_VAR_R));

FREE_OP1();FREE_OP2();EX(opline)++;return 0;

}

Page 28: Zend Engine  изнутри

Специализация в VM (5.1)

int ZEND_CONCAT_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)

{zend_op *opline = EX(opline);

concat_function(&EX_T(opline->result.u.var).tmp_var,_get_zval_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R),&opline->op2.u.constant);

EX(opline)++;return 0;

}

Page 29: Zend Engine  изнутри

Классы

typrdef struct _zend_class_entry {char type;char *name;zend_class_entry *parent;zend_uint ce_flags;HashTable function_table;HashTable default_properties;HashTable properties_info;HashTable *static_members;HashTable constants_table;zend_class_entry **interfaces;…

} zend_class_entry;

Page 30: Zend Engine  изнутри

Объекты

typedef struct _zend_object_value {zend_uint handle; // Z_OBJ_HANDLE(zval)zend_object_handlers *handlers; // Z_OBJ_HT(zval)

} zend_object_value;

typedef struct _zend_object {zend_class_entry *ce; // Z_OBJCE(zval)HashTable *properties; // Z_OBJPROP(zval)

} zend_object;

Page 31: Zend Engine  изнутри

Вопросы?


Recommended